@probelabs/visor 0.1.177-ee → 0.1.178
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/defaults/code-talk.yaml +10 -5
- package/dist/defaults/code-talk.yaml +10 -5
- package/dist/docs/ai-custom-tools.md +49 -0
- package/dist/docs/http.md +23 -0
- package/dist/docs/testing/cookbook.md +48 -0
- package/dist/docs/testing/dsl-reference.md +4 -2
- package/dist/docs/testing/flows.md +33 -1
- package/dist/examples/http-integration-config.yaml +16 -0
- package/dist/generated/config-schema.d.ts +51 -6
- package/dist/generated/config-schema.d.ts.map +1 -1
- package/dist/generated/config-schema.json +61 -6
- package/dist/github-comments.d.ts +5 -1
- package/dist/github-comments.d.ts.map +1 -1
- package/dist/index.js +407 -1910
- package/dist/output/traces/run-2026-03-11T06-33-05-398Z.ndjson +138 -0
- package/dist/output/traces/run-2026-03-11T06-33-47-884Z.ndjson +2296 -0
- package/dist/providers/api-tool-executor.d.ts +2 -0
- package/dist/providers/api-tool-executor.d.ts.map +1 -1
- package/dist/providers/http-client-provider.d.ts.map +1 -1
- package/dist/providers/mcp-custom-sse-server.d.ts.map +1 -1
- package/dist/providers/workflow-check-provider.d.ts.map +1 -1
- package/dist/sdk/{a2a-frontend-BPWLYLCG.mjs → a2a-frontend-U3PTNCLR.mjs} +2 -2
- package/dist/sdk/{a2a-frontend-FUJRKHJB.mjs → a2a-frontend-WYBMBBYG.mjs} +2 -2
- package/dist/sdk/{check-provider-registry-G64PWDCZ.mjs → check-provider-registry-3DZOXYIA.mjs} +6 -6
- package/dist/sdk/{check-provider-registry-HW4QPPSA.mjs → check-provider-registry-T5J3H2N7.mjs} +6 -6
- package/dist/sdk/check-provider-registry-ZX76MY2L.mjs +30 -0
- package/dist/sdk/{chunk-OPI632LK.mjs → chunk-4ECMTCOM.mjs} +2 -2
- package/dist/sdk/{chunk-65SHRIQF.mjs → chunk-6YGCACBF.mjs} +2 -2
- package/dist/sdk/{chunk-65SHRIQF.mjs.map → chunk-6YGCACBF.mjs.map} +1 -1
- package/dist/sdk/{chunk-IYXOLUDJ.mjs → chunk-AK64Y6Y2.mjs} +222 -37
- package/dist/sdk/chunk-AK64Y6Y2.mjs.map +1 -0
- package/dist/sdk/chunk-ANEKFNAS.mjs +45424 -0
- package/dist/sdk/chunk-ANEKFNAS.mjs.map +1 -0
- package/dist/sdk/{chunk-Y6PVSFCS.mjs → chunk-B7XHSG3L.mjs} +237 -47
- package/dist/sdk/chunk-B7XHSG3L.mjs.map +1 -0
- package/dist/sdk/{chunk-MM3TGVQ4.mjs → chunk-BMXVAJ2M.mjs} +52 -7
- package/dist/sdk/chunk-BMXVAJ2M.mjs.map +1 -0
- package/dist/sdk/{chunk-EFNNJIMY.mjs → chunk-CDRKH5HH.mjs} +2 -2
- package/dist/sdk/{chunk-OHOBWVPP.mjs → chunk-ENSZDV3O.mjs} +3 -3
- package/dist/sdk/{chunk-GVTWESYN.mjs → chunk-KG6PM4OL.mjs} +3 -3
- package/dist/sdk/chunk-KG6PM4OL.mjs.map +1 -0
- package/dist/sdk/{chunk-WJIV7MKY.mjs → chunk-WZS4ARZB.mjs} +3 -3
- package/dist/sdk/{config-OOUMTCEA.mjs → config-DFOF7LP4.mjs} +2 -2
- package/dist/sdk/{failure-condition-evaluator-HL33X7MH.mjs → failure-condition-evaluator-MMPKQGUA.mjs} +3 -3
- package/dist/sdk/{failure-condition-evaluator-DL6H57NX.mjs → failure-condition-evaluator-P3MS5DRL.mjs} +3 -3
- package/dist/sdk/{github-frontend-F2YCPK6H.mjs → github-frontend-7RLEBJWG.mjs} +11 -3
- package/dist/sdk/github-frontend-7RLEBJWG.mjs.map +1 -0
- package/dist/sdk/{github-frontend-U2U42CKV.mjs → github-frontend-QTKOYB56.mjs} +11 -3
- package/dist/sdk/github-frontend-QTKOYB56.mjs.map +1 -0
- package/dist/sdk/{host-HFOJQIOF.mjs → host-I2TBBKD5.mjs} +3 -3
- package/dist/sdk/{host-6TBS44ER.mjs → host-SE3MQHWG.mjs} +4 -4
- package/dist/sdk/{routing-GF2CF3JT.mjs → routing-2X6QF5IW.mjs} +4 -4
- package/dist/sdk/{routing-SFP4D6O3.mjs → routing-QHXBQS6X.mjs} +4 -4
- package/dist/sdk/{schedule-tool-45NAALKS.mjs → schedule-tool-MKT5FZ6J.mjs} +6 -6
- package/dist/sdk/{schedule-tool-7O7SWSJ4.mjs → schedule-tool-R6JJIDZ6.mjs} +6 -6
- package/dist/sdk/schedule-tool-W4SQ334O.mjs +36 -0
- package/dist/sdk/{schedule-tool-handler-6MPP5DXK.mjs → schedule-tool-handler-AOMZV3Q3.mjs} +6 -6
- package/dist/sdk/{schedule-tool-handler-KYDXJ2ZL.mjs → schedule-tool-handler-MPJFLH4J.mjs} +6 -6
- package/dist/sdk/schedule-tool-handler-WY7WCFE5.mjs +40 -0
- package/dist/sdk/sdk.d.mts +21 -0
- package/dist/sdk/sdk.d.ts +21 -0
- package/dist/sdk/sdk.js +545 -1681
- package/dist/sdk/sdk.js.map +1 -1
- package/dist/sdk/sdk.mjs +5 -5
- package/dist/sdk/{trace-helpers-FKM2MEDW.mjs → trace-helpers-4ADQ4GB3.mjs} +2 -2
- package/dist/sdk/{trace-helpers-L3EOYW5P.mjs → trace-helpers-K47ZVJSU.mjs} +2 -2
- package/dist/sdk/trace-helpers-K47ZVJSU.mjs.map +1 -0
- package/dist/sdk/{workflow-check-provider-JIXZJNV5.mjs → workflow-check-provider-A3YH2UZJ.mjs} +6 -6
- package/dist/sdk/workflow-check-provider-A3YH2UZJ.mjs.map +1 -0
- package/dist/sdk/{workflow-check-provider-OA33MESM.mjs → workflow-check-provider-WHZP7BDF.mjs} +6 -6
- package/dist/sdk/workflow-check-provider-WHZP7BDF.mjs.map +1 -0
- package/dist/sdk/workflow-check-provider-WZN3B2S2.mjs +30 -0
- package/dist/sdk/workflow-check-provider-WZN3B2S2.mjs.map +1 -0
- package/dist/state-machine/context/build-engine-context.d.ts.map +1 -1
- package/dist/test-runner/conversation-sugar.d.ts +3 -0
- package/dist/test-runner/conversation-sugar.d.ts.map +1 -1
- package/dist/test-runner/validator.d.ts.map +1 -1
- package/dist/traces/run-2026-03-11T06-33-05-398Z.ndjson +138 -0
- package/dist/traces/run-2026-03-11T06-33-47-884Z.ndjson +2296 -0
- package/dist/types/config.d.ts +21 -0
- package/dist/types/config.d.ts.map +1 -1
- package/dist/utils/rate-limiter.d.ts +61 -0
- package/dist/utils/rate-limiter.d.ts.map +1 -0
- package/package.json +2 -2
- package/dist/sdk/chunk-GVTWESYN.mjs.map +0 -1
- package/dist/sdk/chunk-IYXOLUDJ.mjs.map +0 -1
- package/dist/sdk/chunk-MM3TGVQ4.mjs.map +0 -1
- package/dist/sdk/chunk-Y6PVSFCS.mjs.map +0 -1
- package/dist/sdk/github-frontend-F2YCPK6H.mjs.map +0 -1
- package/dist/sdk/github-frontend-U2U42CKV.mjs.map +0 -1
- package/dist/sdk/knex-store-QCEW4I4R.mjs +0 -527
- package/dist/sdk/knex-store-QCEW4I4R.mjs.map +0 -1
- package/dist/sdk/loader-Q7K76ZIY.mjs +0 -89
- package/dist/sdk/loader-Q7K76ZIY.mjs.map +0 -1
- package/dist/sdk/opa-policy-engine-QCSSIMUF.mjs +0 -655
- package/dist/sdk/opa-policy-engine-QCSSIMUF.mjs.map +0 -1
- package/dist/sdk/slack-frontend-6SXPTQDI.mjs +0 -895
- package/dist/sdk/slack-frontend-6SXPTQDI.mjs.map +0 -1
- package/dist/sdk/validator-XTZJZZJH.mjs +0 -134
- package/dist/sdk/validator-XTZJZZJH.mjs.map +0 -1
- /package/dist/sdk/{a2a-frontend-BPWLYLCG.mjs.map → a2a-frontend-U3PTNCLR.mjs.map} +0 -0
- /package/dist/sdk/{a2a-frontend-FUJRKHJB.mjs.map → a2a-frontend-WYBMBBYG.mjs.map} +0 -0
- /package/dist/sdk/{check-provider-registry-G64PWDCZ.mjs.map → check-provider-registry-3DZOXYIA.mjs.map} +0 -0
- /package/dist/sdk/{check-provider-registry-HW4QPPSA.mjs.map → check-provider-registry-T5J3H2N7.mjs.map} +0 -0
- /package/dist/sdk/{config-OOUMTCEA.mjs.map → check-provider-registry-ZX76MY2L.mjs.map} +0 -0
- /package/dist/sdk/{chunk-EFNNJIMY.mjs.map → chunk-4ECMTCOM.mjs.map} +0 -0
- /package/dist/sdk/{chunk-OPI632LK.mjs.map → chunk-CDRKH5HH.mjs.map} +0 -0
- /package/dist/sdk/{chunk-OHOBWVPP.mjs.map → chunk-ENSZDV3O.mjs.map} +0 -0
- /package/dist/sdk/{chunk-WJIV7MKY.mjs.map → chunk-WZS4ARZB.mjs.map} +0 -0
- /package/dist/sdk/{failure-condition-evaluator-DL6H57NX.mjs.map → config-DFOF7LP4.mjs.map} +0 -0
- /package/dist/sdk/{failure-condition-evaluator-HL33X7MH.mjs.map → failure-condition-evaluator-MMPKQGUA.mjs.map} +0 -0
- /package/dist/sdk/{routing-GF2CF3JT.mjs.map → failure-condition-evaluator-P3MS5DRL.mjs.map} +0 -0
- /package/dist/sdk/{host-6TBS44ER.mjs.map → host-I2TBBKD5.mjs.map} +0 -0
- /package/dist/sdk/{host-HFOJQIOF.mjs.map → host-SE3MQHWG.mjs.map} +0 -0
- /package/dist/sdk/{routing-SFP4D6O3.mjs.map → routing-2X6QF5IW.mjs.map} +0 -0
- /package/dist/sdk/{schedule-tool-45NAALKS.mjs.map → routing-QHXBQS6X.mjs.map} +0 -0
- /package/dist/sdk/{schedule-tool-7O7SWSJ4.mjs.map → schedule-tool-MKT5FZ6J.mjs.map} +0 -0
- /package/dist/sdk/{schedule-tool-handler-6MPP5DXK.mjs.map → schedule-tool-R6JJIDZ6.mjs.map} +0 -0
- /package/dist/sdk/{schedule-tool-handler-KYDXJ2ZL.mjs.map → schedule-tool-W4SQ334O.mjs.map} +0 -0
- /package/dist/sdk/{trace-helpers-FKM2MEDW.mjs.map → schedule-tool-handler-AOMZV3Q3.mjs.map} +0 -0
- /package/dist/sdk/{trace-helpers-L3EOYW5P.mjs.map → schedule-tool-handler-MPJFLH4J.mjs.map} +0 -0
- /package/dist/sdk/{workflow-check-provider-JIXZJNV5.mjs.map → schedule-tool-handler-WY7WCFE5.mjs.map} +0 -0
- /package/dist/sdk/{workflow-check-provider-OA33MESM.mjs.map → trace-helpers-4ADQ4GB3.mjs.map} +0 -0
package/dist/sdk/sdk.js
CHANGED
|
@@ -704,7 +704,7 @@ var require_package = __commonJS({
|
|
|
704
704
|
"package.json"(exports2, module2) {
|
|
705
705
|
module2.exports = {
|
|
706
706
|
name: "@probelabs/visor",
|
|
707
|
-
version: "0.1.
|
|
707
|
+
version: "0.1.178",
|
|
708
708
|
main: "dist/index.js",
|
|
709
709
|
bin: {
|
|
710
710
|
visor: "./dist/index.js"
|
|
@@ -823,7 +823,7 @@ var require_package = __commonJS({
|
|
|
823
823
|
"@opentelemetry/sdk-node": "^0.203.0",
|
|
824
824
|
"@opentelemetry/sdk-trace-base": "^1.30.1",
|
|
825
825
|
"@opentelemetry/semantic-conventions": "^1.30.1",
|
|
826
|
-
"@probelabs/probe": "^0.6.0-
|
|
826
|
+
"@probelabs/probe": "^0.6.0-rc293",
|
|
827
827
|
"@types/commander": "^2.12.0",
|
|
828
828
|
"@types/uuid": "^10.0.0",
|
|
829
829
|
acorn: "^8.16.0",
|
|
@@ -1152,11 +1152,11 @@ function getTracer() {
|
|
|
1152
1152
|
}
|
|
1153
1153
|
async function withActiveSpan(name, attrs, fn) {
|
|
1154
1154
|
const tracer = getTracer();
|
|
1155
|
-
return await new Promise((
|
|
1155
|
+
return await new Promise((resolve15, reject) => {
|
|
1156
1156
|
const callback = async (span) => {
|
|
1157
1157
|
try {
|
|
1158
1158
|
const res = await fn(span);
|
|
1159
|
-
|
|
1159
|
+
resolve15(res);
|
|
1160
1160
|
} catch (err) {
|
|
1161
1161
|
try {
|
|
1162
1162
|
if (err instanceof Error) span.recordException(err);
|
|
@@ -1281,19 +1281,19 @@ function __getOrCreateNdjsonPath() {
|
|
|
1281
1281
|
try {
|
|
1282
1282
|
if (process.env.VISOR_TELEMETRY_SINK && process.env.VISOR_TELEMETRY_SINK !== "file")
|
|
1283
1283
|
return null;
|
|
1284
|
-
const
|
|
1285
|
-
const
|
|
1284
|
+
const path29 = require("path");
|
|
1285
|
+
const fs25 = require("fs");
|
|
1286
1286
|
if (process.env.VISOR_FALLBACK_TRACE_FILE) {
|
|
1287
1287
|
__ndjsonPath = process.env.VISOR_FALLBACK_TRACE_FILE;
|
|
1288
|
-
const dir =
|
|
1289
|
-
if (!
|
|
1288
|
+
const dir = path29.dirname(__ndjsonPath);
|
|
1289
|
+
if (!fs25.existsSync(dir)) fs25.mkdirSync(dir, { recursive: true });
|
|
1290
1290
|
return __ndjsonPath;
|
|
1291
1291
|
}
|
|
1292
|
-
const outDir = process.env.VISOR_TRACE_DIR ||
|
|
1293
|
-
if (!
|
|
1292
|
+
const outDir = process.env.VISOR_TRACE_DIR || path29.join(process.cwd(), "output", "traces");
|
|
1293
|
+
if (!fs25.existsSync(outDir)) fs25.mkdirSync(outDir, { recursive: true });
|
|
1294
1294
|
if (!__ndjsonPath) {
|
|
1295
1295
|
const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
1296
|
-
__ndjsonPath =
|
|
1296
|
+
__ndjsonPath = path29.join(outDir, `${ts}.ndjson`);
|
|
1297
1297
|
}
|
|
1298
1298
|
return __ndjsonPath;
|
|
1299
1299
|
} catch {
|
|
@@ -1302,11 +1302,11 @@ function __getOrCreateNdjsonPath() {
|
|
|
1302
1302
|
}
|
|
1303
1303
|
function _appendRunMarker() {
|
|
1304
1304
|
try {
|
|
1305
|
-
const
|
|
1305
|
+
const fs25 = require("fs");
|
|
1306
1306
|
const p = __getOrCreateNdjsonPath();
|
|
1307
1307
|
if (!p) return;
|
|
1308
1308
|
const line = { name: "visor.run", attributes: { started: true } };
|
|
1309
|
-
|
|
1309
|
+
fs25.appendFileSync(p, JSON.stringify(line) + "\n", "utf8");
|
|
1310
1310
|
} catch {
|
|
1311
1311
|
}
|
|
1312
1312
|
}
|
|
@@ -3393,7 +3393,7 @@ var init_failure_condition_evaluator = __esm({
|
|
|
3393
3393
|
*/
|
|
3394
3394
|
evaluateExpression(condition, context2) {
|
|
3395
3395
|
try {
|
|
3396
|
-
const
|
|
3396
|
+
const normalize4 = (expr) => {
|
|
3397
3397
|
const trimmed = expr.trim();
|
|
3398
3398
|
if (!/[\n;]/.test(trimmed)) return trimmed;
|
|
3399
3399
|
const parts = trimmed.split(/[\n;]+/).map((s) => s.trim()).filter((s) => s.length > 0 && !s.startsWith("//"));
|
|
@@ -3551,7 +3551,7 @@ var init_failure_condition_evaluator = __esm({
|
|
|
3551
3551
|
try {
|
|
3552
3552
|
exec2 = this.sandbox.compile(`return (${raw});`);
|
|
3553
3553
|
} catch {
|
|
3554
|
-
const normalizedExpr =
|
|
3554
|
+
const normalizedExpr = normalize4(condition);
|
|
3555
3555
|
exec2 = this.sandbox.compile(`return (${normalizedExpr});`);
|
|
3556
3556
|
}
|
|
3557
3557
|
const result = exec2(scope).run();
|
|
@@ -3934,9 +3934,9 @@ function configureLiquidWithExtensions(liquid) {
|
|
|
3934
3934
|
});
|
|
3935
3935
|
liquid.registerFilter("get", (obj, pathExpr) => {
|
|
3936
3936
|
if (obj == null) return void 0;
|
|
3937
|
-
const
|
|
3938
|
-
if (!
|
|
3939
|
-
const parts =
|
|
3937
|
+
const path29 = typeof pathExpr === "string" ? pathExpr : String(pathExpr || "");
|
|
3938
|
+
if (!path29) return obj;
|
|
3939
|
+
const parts = path29.split(".");
|
|
3940
3940
|
let cur = obj;
|
|
3941
3941
|
for (const p of parts) {
|
|
3942
3942
|
if (cur == null) return void 0;
|
|
@@ -4055,9 +4055,9 @@ function configureLiquidWithExtensions(liquid) {
|
|
|
4055
4055
|
}
|
|
4056
4056
|
}
|
|
4057
4057
|
const defaultRole = typeof rolesCfg.default === "string" && rolesCfg.default.trim() ? rolesCfg.default.trim() : void 0;
|
|
4058
|
-
const getNested = (obj,
|
|
4059
|
-
if (!obj || !
|
|
4060
|
-
const parts =
|
|
4058
|
+
const getNested = (obj, path29) => {
|
|
4059
|
+
if (!obj || !path29) return void 0;
|
|
4060
|
+
const parts = path29.split(".");
|
|
4061
4061
|
let cur = obj;
|
|
4062
4062
|
for (const p of parts) {
|
|
4063
4063
|
if (cur == null) return void 0;
|
|
@@ -6609,8 +6609,8 @@ var init_dependency_gating = __esm({
|
|
|
6609
6609
|
async function renderTemplateContent(checkId, checkConfig, reviewSummary) {
|
|
6610
6610
|
try {
|
|
6611
6611
|
const { createExtendedLiquid: createExtendedLiquid2 } = await Promise.resolve().then(() => (init_liquid_extensions(), liquid_extensions_exports));
|
|
6612
|
-
const
|
|
6613
|
-
const
|
|
6612
|
+
const fs25 = await import("fs/promises");
|
|
6613
|
+
const path29 = await import("path");
|
|
6614
6614
|
const schemaRaw = checkConfig.schema || "plain";
|
|
6615
6615
|
const schema = typeof schemaRaw === "string" ? schemaRaw : "code-review";
|
|
6616
6616
|
let templateContent;
|
|
@@ -6618,24 +6618,24 @@ async function renderTemplateContent(checkId, checkConfig, reviewSummary) {
|
|
|
6618
6618
|
templateContent = String(checkConfig.template.content);
|
|
6619
6619
|
} else if (checkConfig.template && checkConfig.template.file) {
|
|
6620
6620
|
const file = String(checkConfig.template.file);
|
|
6621
|
-
const resolved =
|
|
6622
|
-
templateContent = await
|
|
6621
|
+
const resolved = path29.resolve(process.cwd(), file);
|
|
6622
|
+
templateContent = await fs25.readFile(resolved, "utf-8");
|
|
6623
6623
|
} else if (schema && schema !== "plain") {
|
|
6624
6624
|
const sanitized = String(schema).replace(/[^a-zA-Z0-9-]/g, "");
|
|
6625
6625
|
if (sanitized) {
|
|
6626
6626
|
const candidatePaths = [
|
|
6627
|
-
|
|
6627
|
+
path29.join(__dirname, "output", sanitized, "template.liquid"),
|
|
6628
6628
|
// bundled: dist/output/
|
|
6629
|
-
|
|
6629
|
+
path29.join(__dirname, "..", "..", "output", sanitized, "template.liquid"),
|
|
6630
6630
|
// source: output/
|
|
6631
|
-
|
|
6631
|
+
path29.join(process.cwd(), "output", sanitized, "template.liquid"),
|
|
6632
6632
|
// fallback: cwd/output/
|
|
6633
|
-
|
|
6633
|
+
path29.join(process.cwd(), "dist", "output", sanitized, "template.liquid")
|
|
6634
6634
|
// fallback: cwd/dist/output/
|
|
6635
6635
|
];
|
|
6636
6636
|
for (const p of candidatePaths) {
|
|
6637
6637
|
try {
|
|
6638
|
-
templateContent = await
|
|
6638
|
+
templateContent = await fs25.readFile(p, "utf-8");
|
|
6639
6639
|
if (templateContent) break;
|
|
6640
6640
|
} catch {
|
|
6641
6641
|
}
|
|
@@ -7040,7 +7040,7 @@ async function processDiffWithOutline(diffContent) {
|
|
|
7040
7040
|
}
|
|
7041
7041
|
try {
|
|
7042
7042
|
const originalProbePath = process.env.PROBE_PATH;
|
|
7043
|
-
const
|
|
7043
|
+
const fs25 = require("fs");
|
|
7044
7044
|
const possiblePaths = [
|
|
7045
7045
|
// Relative to current working directory (most common in production)
|
|
7046
7046
|
path6.join(process.cwd(), "node_modules/@probelabs/probe/bin/probe-binary"),
|
|
@@ -7051,7 +7051,7 @@ async function processDiffWithOutline(diffContent) {
|
|
|
7051
7051
|
];
|
|
7052
7052
|
let probeBinaryPath;
|
|
7053
7053
|
for (const candidatePath of possiblePaths) {
|
|
7054
|
-
if (
|
|
7054
|
+
if (fs25.existsSync(candidatePath)) {
|
|
7055
7055
|
probeBinaryPath = candidatePath;
|
|
7056
7056
|
break;
|
|
7057
7057
|
}
|
|
@@ -7158,7 +7158,7 @@ async function renderMermaidToPng(mermaidCode) {
|
|
|
7158
7158
|
if (chromiumPath) {
|
|
7159
7159
|
env.PUPPETEER_EXECUTABLE_PATH = chromiumPath;
|
|
7160
7160
|
}
|
|
7161
|
-
const result = await new Promise((
|
|
7161
|
+
const result = await new Promise((resolve15) => {
|
|
7162
7162
|
const proc = (0, import_child_process.spawn)(
|
|
7163
7163
|
"npx",
|
|
7164
7164
|
[
|
|
@@ -7188,13 +7188,13 @@ async function renderMermaidToPng(mermaidCode) {
|
|
|
7188
7188
|
});
|
|
7189
7189
|
proc.on("close", (code) => {
|
|
7190
7190
|
if (code === 0) {
|
|
7191
|
-
|
|
7191
|
+
resolve15({ success: true });
|
|
7192
7192
|
} else {
|
|
7193
|
-
|
|
7193
|
+
resolve15({ success: false, error: stderr || `Exit code ${code}` });
|
|
7194
7194
|
}
|
|
7195
7195
|
});
|
|
7196
7196
|
proc.on("error", (err) => {
|
|
7197
|
-
|
|
7197
|
+
resolve15({ success: false, error: err.message });
|
|
7198
7198
|
});
|
|
7199
7199
|
});
|
|
7200
7200
|
if (!result.success) {
|
|
@@ -8392,8 +8392,8 @@ ${schemaString}`);
|
|
|
8392
8392
|
}
|
|
8393
8393
|
if (process.env.VISOR_DEBUG_AI_SESSIONS === "true") {
|
|
8394
8394
|
try {
|
|
8395
|
-
const
|
|
8396
|
-
const
|
|
8395
|
+
const fs25 = require("fs");
|
|
8396
|
+
const path29 = require("path");
|
|
8397
8397
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
8398
8398
|
const provider = this.config.provider || "auto";
|
|
8399
8399
|
const model = this.config.model || "default";
|
|
@@ -8507,20 +8507,20 @@ ${"=".repeat(60)}
|
|
|
8507
8507
|
`;
|
|
8508
8508
|
readableVersion += `${"=".repeat(60)}
|
|
8509
8509
|
`;
|
|
8510
|
-
const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS ||
|
|
8511
|
-
if (!
|
|
8512
|
-
|
|
8510
|
+
const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS || path29.join(process.cwd(), "debug-artifacts");
|
|
8511
|
+
if (!fs25.existsSync(debugArtifactsDir)) {
|
|
8512
|
+
fs25.mkdirSync(debugArtifactsDir, { recursive: true });
|
|
8513
8513
|
}
|
|
8514
|
-
const debugFile =
|
|
8514
|
+
const debugFile = path29.join(
|
|
8515
8515
|
debugArtifactsDir,
|
|
8516
8516
|
`prompt-${_checkName || "unknown"}-${timestamp}.json`
|
|
8517
8517
|
);
|
|
8518
|
-
|
|
8519
|
-
const readableFile =
|
|
8518
|
+
fs25.writeFileSync(debugFile, debugJson, "utf-8");
|
|
8519
|
+
const readableFile = path29.join(
|
|
8520
8520
|
debugArtifactsDir,
|
|
8521
8521
|
`prompt-${_checkName || "unknown"}-${timestamp}.txt`
|
|
8522
8522
|
);
|
|
8523
|
-
|
|
8523
|
+
fs25.writeFileSync(readableFile, readableVersion, "utf-8");
|
|
8524
8524
|
log(`
|
|
8525
8525
|
\u{1F4BE} Full debug info saved to:`);
|
|
8526
8526
|
log(` JSON: ${debugFile}`);
|
|
@@ -8558,8 +8558,8 @@ ${"=".repeat(60)}
|
|
|
8558
8558
|
log(`\u{1F4E4} Response length: ${response.length} characters`);
|
|
8559
8559
|
if (process.env.VISOR_DEBUG_AI_SESSIONS === "true") {
|
|
8560
8560
|
try {
|
|
8561
|
-
const
|
|
8562
|
-
const
|
|
8561
|
+
const fs25 = require("fs");
|
|
8562
|
+
const path29 = require("path");
|
|
8563
8563
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
8564
8564
|
const agentAny2 = agent;
|
|
8565
8565
|
let fullHistory = [];
|
|
@@ -8570,8 +8570,8 @@ ${"=".repeat(60)}
|
|
|
8570
8570
|
} else if (agentAny2._messages) {
|
|
8571
8571
|
fullHistory = agentAny2._messages;
|
|
8572
8572
|
}
|
|
8573
|
-
const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS ||
|
|
8574
|
-
const sessionBase =
|
|
8573
|
+
const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS || path29.join(process.cwd(), "debug-artifacts");
|
|
8574
|
+
const sessionBase = path29.join(
|
|
8575
8575
|
debugArtifactsDir,
|
|
8576
8576
|
`session-${_checkName || "unknown"}-${timestamp}`
|
|
8577
8577
|
);
|
|
@@ -8583,7 +8583,7 @@ ${"=".repeat(60)}
|
|
|
8583
8583
|
schema: effectiveSchema,
|
|
8584
8584
|
totalMessages: fullHistory.length
|
|
8585
8585
|
};
|
|
8586
|
-
|
|
8586
|
+
fs25.writeFileSync(sessionBase + ".json", JSON.stringify(sessionData, null, 2), "utf-8");
|
|
8587
8587
|
let readable = `=============================================================
|
|
8588
8588
|
`;
|
|
8589
8589
|
readable += `COMPLETE AI SESSION HISTORY (AFTER RESPONSE)
|
|
@@ -8610,7 +8610,7 @@ ${"=".repeat(60)}
|
|
|
8610
8610
|
`;
|
|
8611
8611
|
readable += content + "\n";
|
|
8612
8612
|
});
|
|
8613
|
-
|
|
8613
|
+
fs25.writeFileSync(sessionBase + ".summary.txt", readable, "utf-8");
|
|
8614
8614
|
log(`\u{1F4BE} Complete session history saved:`);
|
|
8615
8615
|
log(` - Contains ALL ${fullHistory.length} messages (prompts + responses)`);
|
|
8616
8616
|
} catch (error) {
|
|
@@ -8619,11 +8619,11 @@ ${"=".repeat(60)}
|
|
|
8619
8619
|
}
|
|
8620
8620
|
if (process.env.VISOR_DEBUG_AI_SESSIONS === "true") {
|
|
8621
8621
|
try {
|
|
8622
|
-
const
|
|
8623
|
-
const
|
|
8622
|
+
const fs25 = require("fs");
|
|
8623
|
+
const path29 = require("path");
|
|
8624
8624
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
8625
|
-
const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS ||
|
|
8626
|
-
const responseFile =
|
|
8625
|
+
const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS || path29.join(process.cwd(), "debug-artifacts");
|
|
8626
|
+
const responseFile = path29.join(
|
|
8627
8627
|
debugArtifactsDir,
|
|
8628
8628
|
`response-${_checkName || "unknown"}-${timestamp}.txt`
|
|
8629
8629
|
);
|
|
@@ -8656,7 +8656,7 @@ ${"=".repeat(60)}
|
|
|
8656
8656
|
`;
|
|
8657
8657
|
responseContent += `${"=".repeat(60)}
|
|
8658
8658
|
`;
|
|
8659
|
-
|
|
8659
|
+
fs25.writeFileSync(responseFile, responseContent, "utf-8");
|
|
8660
8660
|
log(`\u{1F4BE} Response saved to: ${responseFile}`);
|
|
8661
8661
|
} catch (error) {
|
|
8662
8662
|
log(`\u26A0\uFE0F Could not save response file: ${error}`);
|
|
@@ -8672,9 +8672,9 @@ ${"=".repeat(60)}
|
|
|
8672
8672
|
await agentAny._telemetryConfig.shutdown();
|
|
8673
8673
|
log(`\u{1F4CA} OpenTelemetry trace saved to: ${agentAny._traceFilePath}`);
|
|
8674
8674
|
if (process.env.GITHUB_ACTIONS) {
|
|
8675
|
-
const
|
|
8676
|
-
if (
|
|
8677
|
-
const stats =
|
|
8675
|
+
const fs25 = require("fs");
|
|
8676
|
+
if (fs25.existsSync(agentAny._traceFilePath)) {
|
|
8677
|
+
const stats = fs25.statSync(agentAny._traceFilePath);
|
|
8678
8678
|
console.log(
|
|
8679
8679
|
`::notice title=AI Trace Saved::${agentAny._traceFilePath} (${stats.size} bytes)`
|
|
8680
8680
|
);
|
|
@@ -8887,9 +8887,9 @@ ${schemaString}`);
|
|
|
8887
8887
|
const model = this.config.model || "default";
|
|
8888
8888
|
if (process.env.VISOR_DEBUG_AI_SESSIONS === "true") {
|
|
8889
8889
|
try {
|
|
8890
|
-
const
|
|
8891
|
-
const
|
|
8892
|
-
const
|
|
8890
|
+
const fs25 = require("fs");
|
|
8891
|
+
const path29 = require("path");
|
|
8892
|
+
const os2 = require("os");
|
|
8893
8893
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
8894
8894
|
const debugData = {
|
|
8895
8895
|
timestamp,
|
|
@@ -8961,19 +8961,19 @@ ${"=".repeat(60)}
|
|
|
8961
8961
|
`;
|
|
8962
8962
|
readableVersion += `${"=".repeat(60)}
|
|
8963
8963
|
`;
|
|
8964
|
-
const tempDir =
|
|
8965
|
-
const promptFile =
|
|
8966
|
-
|
|
8964
|
+
const tempDir = os2.tmpdir();
|
|
8965
|
+
const promptFile = path29.join(tempDir, `visor-prompt-${timestamp}.txt`);
|
|
8966
|
+
fs25.writeFileSync(promptFile, prompt, "utf-8");
|
|
8967
8967
|
log(`
|
|
8968
8968
|
\u{1F4BE} Prompt saved to: ${promptFile}`);
|
|
8969
|
-
const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS ||
|
|
8969
|
+
const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS || path29.join(process.cwd(), "debug-artifacts");
|
|
8970
8970
|
try {
|
|
8971
|
-
const base =
|
|
8971
|
+
const base = path29.join(
|
|
8972
8972
|
debugArtifactsDir,
|
|
8973
8973
|
`prompt-${_checkName || "unknown"}-${timestamp}`
|
|
8974
8974
|
);
|
|
8975
|
-
|
|
8976
|
-
|
|
8975
|
+
fs25.writeFileSync(base + ".json", debugJson, "utf-8");
|
|
8976
|
+
fs25.writeFileSync(base + ".summary.txt", readableVersion, "utf-8");
|
|
8977
8977
|
log(`
|
|
8978
8978
|
\u{1F4BE} Full debug info saved to directory: ${debugArtifactsDir}`);
|
|
8979
8979
|
} catch {
|
|
@@ -9023,8 +9023,8 @@ $ ${cliCommand}
|
|
|
9023
9023
|
log(`\u{1F4E4} Response length: ${response.length} characters`);
|
|
9024
9024
|
if (process.env.VISOR_DEBUG_AI_SESSIONS === "true") {
|
|
9025
9025
|
try {
|
|
9026
|
-
const
|
|
9027
|
-
const
|
|
9026
|
+
const fs25 = require("fs");
|
|
9027
|
+
const path29 = require("path");
|
|
9028
9028
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
9029
9029
|
const agentAny = agent;
|
|
9030
9030
|
let fullHistory = [];
|
|
@@ -9035,8 +9035,8 @@ $ ${cliCommand}
|
|
|
9035
9035
|
} else if (agentAny._messages) {
|
|
9036
9036
|
fullHistory = agentAny._messages;
|
|
9037
9037
|
}
|
|
9038
|
-
const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS ||
|
|
9039
|
-
const sessionBase =
|
|
9038
|
+
const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS || path29.join(process.cwd(), "debug-artifacts");
|
|
9039
|
+
const sessionBase = path29.join(
|
|
9040
9040
|
debugArtifactsDir,
|
|
9041
9041
|
`session-${_checkName || "unknown"}-${timestamp}`
|
|
9042
9042
|
);
|
|
@@ -9048,7 +9048,7 @@ $ ${cliCommand}
|
|
|
9048
9048
|
schema: effectiveSchema,
|
|
9049
9049
|
totalMessages: fullHistory.length
|
|
9050
9050
|
};
|
|
9051
|
-
|
|
9051
|
+
fs25.writeFileSync(sessionBase + ".json", JSON.stringify(sessionData, null, 2), "utf-8");
|
|
9052
9052
|
let readable = `=============================================================
|
|
9053
9053
|
`;
|
|
9054
9054
|
readable += `COMPLETE AI SESSION HISTORY (AFTER RESPONSE)
|
|
@@ -9075,7 +9075,7 @@ ${"=".repeat(60)}
|
|
|
9075
9075
|
`;
|
|
9076
9076
|
readable += content + "\n";
|
|
9077
9077
|
});
|
|
9078
|
-
|
|
9078
|
+
fs25.writeFileSync(sessionBase + ".summary.txt", readable, "utf-8");
|
|
9079
9079
|
log(`\u{1F4BE} Complete session history saved:`);
|
|
9080
9080
|
log(` - Contains ALL ${fullHistory.length} messages (prompts + responses)`);
|
|
9081
9081
|
} catch (error) {
|
|
@@ -9084,11 +9084,11 @@ ${"=".repeat(60)}
|
|
|
9084
9084
|
}
|
|
9085
9085
|
if (process.env.VISOR_DEBUG_AI_SESSIONS === "true") {
|
|
9086
9086
|
try {
|
|
9087
|
-
const
|
|
9088
|
-
const
|
|
9087
|
+
const fs25 = require("fs");
|
|
9088
|
+
const path29 = require("path");
|
|
9089
9089
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
9090
|
-
const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS ||
|
|
9091
|
-
const responseFile =
|
|
9090
|
+
const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS || path29.join(process.cwd(), "debug-artifacts");
|
|
9091
|
+
const responseFile = path29.join(
|
|
9092
9092
|
debugArtifactsDir,
|
|
9093
9093
|
`response-${_checkName || "unknown"}-${timestamp}.txt`
|
|
9094
9094
|
);
|
|
@@ -9121,7 +9121,7 @@ ${"=".repeat(60)}
|
|
|
9121
9121
|
`;
|
|
9122
9122
|
responseContent += `${"=".repeat(60)}
|
|
9123
9123
|
`;
|
|
9124
|
-
|
|
9124
|
+
fs25.writeFileSync(responseFile, responseContent, "utf-8");
|
|
9125
9125
|
log(`\u{1F4BE} Response saved to: ${responseFile}`);
|
|
9126
9126
|
} catch (error) {
|
|
9127
9127
|
log(`\u26A0\uFE0F Could not save response file: ${error}`);
|
|
@@ -9139,9 +9139,9 @@ ${"=".repeat(60)}
|
|
|
9139
9139
|
await telemetry.shutdown();
|
|
9140
9140
|
log(`\u{1F4CA} OpenTelemetry trace saved to: ${traceFilePath}`);
|
|
9141
9141
|
if (process.env.GITHUB_ACTIONS) {
|
|
9142
|
-
const
|
|
9143
|
-
if (
|
|
9144
|
-
const stats =
|
|
9142
|
+
const fs25 = require("fs");
|
|
9143
|
+
if (fs25.existsSync(traceFilePath)) {
|
|
9144
|
+
const stats = fs25.statSync(traceFilePath);
|
|
9145
9145
|
console.log(
|
|
9146
9146
|
`::notice title=AI Trace Saved::OpenTelemetry trace file size: ${stats.size} bytes`
|
|
9147
9147
|
);
|
|
@@ -9179,8 +9179,8 @@ ${"=".repeat(60)}
|
|
|
9179
9179
|
* Load schema content from schema files or inline definitions
|
|
9180
9180
|
*/
|
|
9181
9181
|
async loadSchemaContent(schema) {
|
|
9182
|
-
const
|
|
9183
|
-
const
|
|
9182
|
+
const fs25 = require("fs").promises;
|
|
9183
|
+
const path29 = require("path");
|
|
9184
9184
|
if (typeof schema === "object" && schema !== null) {
|
|
9185
9185
|
log("\u{1F4CB} Using inline schema object from configuration");
|
|
9186
9186
|
return JSON.stringify(schema);
|
|
@@ -9193,14 +9193,14 @@ ${"=".repeat(60)}
|
|
|
9193
9193
|
}
|
|
9194
9194
|
} catch {
|
|
9195
9195
|
}
|
|
9196
|
-
if ((schema.startsWith("./") || schema.includes(".json")) && !
|
|
9196
|
+
if ((schema.startsWith("./") || schema.includes(".json")) && !path29.isAbsolute(schema)) {
|
|
9197
9197
|
if (schema.includes("..") || schema.includes("\0")) {
|
|
9198
9198
|
throw new Error("Invalid schema path: path traversal not allowed");
|
|
9199
9199
|
}
|
|
9200
9200
|
try {
|
|
9201
|
-
const schemaPath =
|
|
9201
|
+
const schemaPath = path29.resolve(process.cwd(), schema);
|
|
9202
9202
|
log(`\u{1F4CB} Loading custom schema from file: ${schemaPath}`);
|
|
9203
|
-
const schemaContent = await
|
|
9203
|
+
const schemaContent = await fs25.readFile(schemaPath, "utf-8");
|
|
9204
9204
|
return schemaContent.trim();
|
|
9205
9205
|
} catch (error) {
|
|
9206
9206
|
throw new Error(
|
|
@@ -9214,22 +9214,22 @@ ${"=".repeat(60)}
|
|
|
9214
9214
|
}
|
|
9215
9215
|
const candidatePaths = [
|
|
9216
9216
|
// GitHub Action bundle location
|
|
9217
|
-
|
|
9217
|
+
path29.join(__dirname, "output", sanitizedSchemaName, "schema.json"),
|
|
9218
9218
|
// Historical fallback when src/output was inadvertently bundled as output1/
|
|
9219
|
-
|
|
9219
|
+
path29.join(__dirname, "output1", sanitizedSchemaName, "schema.json"),
|
|
9220
9220
|
// Local dev (repo root)
|
|
9221
|
-
|
|
9221
|
+
path29.join(process.cwd(), "output", sanitizedSchemaName, "schema.json")
|
|
9222
9222
|
];
|
|
9223
9223
|
for (const schemaPath of candidatePaths) {
|
|
9224
9224
|
try {
|
|
9225
|
-
const schemaContent = await
|
|
9225
|
+
const schemaContent = await fs25.readFile(schemaPath, "utf-8");
|
|
9226
9226
|
return schemaContent.trim();
|
|
9227
9227
|
} catch {
|
|
9228
9228
|
}
|
|
9229
9229
|
}
|
|
9230
|
-
const distPath =
|
|
9231
|
-
const distAltPath =
|
|
9232
|
-
const cwdPath =
|
|
9230
|
+
const distPath = path29.join(__dirname, "output", sanitizedSchemaName, "schema.json");
|
|
9231
|
+
const distAltPath = path29.join(__dirname, "output1", sanitizedSchemaName, "schema.json");
|
|
9232
|
+
const cwdPath = path29.join(process.cwd(), "output", sanitizedSchemaName, "schema.json");
|
|
9233
9233
|
throw new Error(
|
|
9234
9234
|
`Failed to load schema '${sanitizedSchemaName}'. Tried: ${distPath}, ${distAltPath}, and ${cwdPath}. Ensure build copies 'output/' into dist (build:cli), or provide a custom schema file/path.`
|
|
9235
9235
|
);
|
|
@@ -9471,7 +9471,7 @@ ${"=".repeat(60)}
|
|
|
9471
9471
|
* Generate mock response for testing
|
|
9472
9472
|
*/
|
|
9473
9473
|
async generateMockResponse(_prompt, _checkName, _schema) {
|
|
9474
|
-
await new Promise((
|
|
9474
|
+
await new Promise((resolve15) => setTimeout(resolve15, 500));
|
|
9475
9475
|
const name = (_checkName || "").toLowerCase();
|
|
9476
9476
|
if (name.includes("extract-facts")) {
|
|
9477
9477
|
const arr = Array.from({ length: 6 }, (_, i) => ({
|
|
@@ -9832,7 +9832,7 @@ var init_command_executor = __esm({
|
|
|
9832
9832
|
* Execute command with stdin input
|
|
9833
9833
|
*/
|
|
9834
9834
|
executeWithStdin(command, options) {
|
|
9835
|
-
return new Promise((
|
|
9835
|
+
return new Promise((resolve15, reject) => {
|
|
9836
9836
|
const childProcess = (0, import_child_process2.exec)(
|
|
9837
9837
|
command,
|
|
9838
9838
|
{
|
|
@@ -9844,7 +9844,7 @@ var init_command_executor = __esm({
|
|
|
9844
9844
|
if (error && error.killed && (error.code === "ETIMEDOUT" || error.signal === "SIGTERM")) {
|
|
9845
9845
|
reject(new Error(`Command timed out after ${options.timeout || 3e4}ms`));
|
|
9846
9846
|
} else {
|
|
9847
|
-
|
|
9847
|
+
resolve15({
|
|
9848
9848
|
stdout: stdout || "",
|
|
9849
9849
|
stderr: stderr || "",
|
|
9850
9850
|
exitCode: error ? error.code || 1 : 0
|
|
@@ -9912,6 +9912,162 @@ var init_command_executor = __esm({
|
|
|
9912
9912
|
}
|
|
9913
9913
|
});
|
|
9914
9914
|
|
|
9915
|
+
// src/utils/rate-limiter.ts
|
|
9916
|
+
function windowToMs(per) {
|
|
9917
|
+
switch (per) {
|
|
9918
|
+
case "second":
|
|
9919
|
+
return 1e3;
|
|
9920
|
+
case "minute":
|
|
9921
|
+
return 6e4;
|
|
9922
|
+
case "hour":
|
|
9923
|
+
return 36e5;
|
|
9924
|
+
}
|
|
9925
|
+
}
|
|
9926
|
+
function resolveRateLimitKey(config, fallbackUrl) {
|
|
9927
|
+
if (config.key) {
|
|
9928
|
+
return config.key;
|
|
9929
|
+
}
|
|
9930
|
+
if (fallbackUrl) {
|
|
9931
|
+
try {
|
|
9932
|
+
const url = new URL(fallbackUrl);
|
|
9933
|
+
return url.origin;
|
|
9934
|
+
} catch {
|
|
9935
|
+
return fallbackUrl;
|
|
9936
|
+
}
|
|
9937
|
+
}
|
|
9938
|
+
return "__default__";
|
|
9939
|
+
}
|
|
9940
|
+
async function rateLimitedFetch(url, options, rateLimitConfig) {
|
|
9941
|
+
if (!rateLimitConfig) {
|
|
9942
|
+
return fetch(url, options);
|
|
9943
|
+
}
|
|
9944
|
+
const key = resolveRateLimitKey(rateLimitConfig, url);
|
|
9945
|
+
const registry = RateLimiterRegistry.getInstance();
|
|
9946
|
+
const bucket = registry.getOrCreate(key, rateLimitConfig);
|
|
9947
|
+
const maxRetries = rateLimitConfig.max_retries ?? 3;
|
|
9948
|
+
const backoff = rateLimitConfig.backoff ?? "exponential";
|
|
9949
|
+
const initialDelay = rateLimitConfig.initial_delay_ms ?? 1e3;
|
|
9950
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
9951
|
+
await bucket.acquire();
|
|
9952
|
+
const response = await fetch(url, options);
|
|
9953
|
+
if (response.status !== 429) {
|
|
9954
|
+
return response;
|
|
9955
|
+
}
|
|
9956
|
+
if (attempt === maxRetries) {
|
|
9957
|
+
logger.warn(`[rate-limiter] Exhausted ${maxRetries} retries for ${url} (bucket: ${key})`);
|
|
9958
|
+
return response;
|
|
9959
|
+
}
|
|
9960
|
+
let delayMs;
|
|
9961
|
+
const retryAfter = response.headers.get("retry-after");
|
|
9962
|
+
if (retryAfter) {
|
|
9963
|
+
const parsed = Number(retryAfter);
|
|
9964
|
+
if (!isNaN(parsed)) {
|
|
9965
|
+
delayMs = parsed * 1e3;
|
|
9966
|
+
} else {
|
|
9967
|
+
const date = new Date(retryAfter).getTime();
|
|
9968
|
+
delayMs = Math.max(0, date - Date.now());
|
|
9969
|
+
}
|
|
9970
|
+
} else {
|
|
9971
|
+
delayMs = backoff === "exponential" ? initialDelay * Math.pow(2, attempt) : initialDelay;
|
|
9972
|
+
}
|
|
9973
|
+
logger.verbose(
|
|
9974
|
+
`[rate-limiter] 429 on ${url} (bucket: ${key}), retry ${attempt + 1}/${maxRetries} in ${delayMs}ms`
|
|
9975
|
+
);
|
|
9976
|
+
await new Promise((resolve15) => setTimeout(resolve15, delayMs));
|
|
9977
|
+
}
|
|
9978
|
+
return fetch(url, options);
|
|
9979
|
+
}
|
|
9980
|
+
var TokenBucket, REGISTRY_KEY, RateLimiterRegistry;
|
|
9981
|
+
var init_rate_limiter = __esm({
|
|
9982
|
+
"src/utils/rate-limiter.ts"() {
|
|
9983
|
+
"use strict";
|
|
9984
|
+
init_logger();
|
|
9985
|
+
TokenBucket = class {
|
|
9986
|
+
tokens;
|
|
9987
|
+
capacity;
|
|
9988
|
+
refillRate;
|
|
9989
|
+
// tokens per ms
|
|
9990
|
+
lastRefill;
|
|
9991
|
+
waitQueue = [];
|
|
9992
|
+
constructor(capacity, windowMs) {
|
|
9993
|
+
this.capacity = capacity;
|
|
9994
|
+
this.tokens = capacity;
|
|
9995
|
+
this.refillRate = capacity / windowMs;
|
|
9996
|
+
this.lastRefill = Date.now();
|
|
9997
|
+
}
|
|
9998
|
+
refill() {
|
|
9999
|
+
const now = Date.now();
|
|
10000
|
+
const elapsed = now - this.lastRefill;
|
|
10001
|
+
const newTokens = elapsed * this.refillRate;
|
|
10002
|
+
this.tokens = Math.min(this.capacity, this.tokens + newTokens);
|
|
10003
|
+
this.lastRefill = now;
|
|
10004
|
+
}
|
|
10005
|
+
/**
|
|
10006
|
+
* Non-blocking: try to consume one token.
|
|
10007
|
+
*/
|
|
10008
|
+
tryConsume() {
|
|
10009
|
+
this.refill();
|
|
10010
|
+
if (this.tokens >= 1) {
|
|
10011
|
+
this.tokens -= 1;
|
|
10012
|
+
return true;
|
|
10013
|
+
}
|
|
10014
|
+
return false;
|
|
10015
|
+
}
|
|
10016
|
+
/**
|
|
10017
|
+
* Blocking: wait until a token is available, then consume it.
|
|
10018
|
+
* Requests are served FIFO.
|
|
10019
|
+
*/
|
|
10020
|
+
async acquire() {
|
|
10021
|
+
if (this.tryConsume()) {
|
|
10022
|
+
return;
|
|
10023
|
+
}
|
|
10024
|
+
const waitMs = Math.ceil((1 - this.tokens) / this.refillRate);
|
|
10025
|
+
return new Promise((resolve15) => {
|
|
10026
|
+
const entry = { resolve: resolve15 };
|
|
10027
|
+
this.waitQueue.push(entry);
|
|
10028
|
+
setTimeout(() => {
|
|
10029
|
+
const idx = this.waitQueue.indexOf(entry);
|
|
10030
|
+
if (idx >= 0) {
|
|
10031
|
+
this.waitQueue.splice(idx, 1);
|
|
10032
|
+
}
|
|
10033
|
+
this.refill();
|
|
10034
|
+
if (this.tokens >= 1) {
|
|
10035
|
+
this.tokens -= 1;
|
|
10036
|
+
}
|
|
10037
|
+
resolve15();
|
|
10038
|
+
}, waitMs);
|
|
10039
|
+
});
|
|
10040
|
+
}
|
|
10041
|
+
};
|
|
10042
|
+
REGISTRY_KEY = Symbol.for("visor.rateLimiterRegistry");
|
|
10043
|
+
RateLimiterRegistry = class _RateLimiterRegistry {
|
|
10044
|
+
buckets = /* @__PURE__ */ new Map();
|
|
10045
|
+
static getInstance() {
|
|
10046
|
+
const g = globalThis;
|
|
10047
|
+
if (!g[REGISTRY_KEY]) {
|
|
10048
|
+
g[REGISTRY_KEY] = new _RateLimiterRegistry();
|
|
10049
|
+
}
|
|
10050
|
+
return g[REGISTRY_KEY];
|
|
10051
|
+
}
|
|
10052
|
+
getOrCreate(key, config) {
|
|
10053
|
+
let bucket = this.buckets.get(key);
|
|
10054
|
+
if (!bucket) {
|
|
10055
|
+
const windowMs = windowToMs(config.per);
|
|
10056
|
+
bucket = new TokenBucket(config.requests, windowMs);
|
|
10057
|
+
this.buckets.set(key, bucket);
|
|
10058
|
+
logger.verbose(
|
|
10059
|
+
`[rate-limiter] Created bucket "${key}": ${config.requests} req/${config.per}`
|
|
10060
|
+
);
|
|
10061
|
+
}
|
|
10062
|
+
return bucket;
|
|
10063
|
+
}
|
|
10064
|
+
cleanup() {
|
|
10065
|
+
this.buckets.clear();
|
|
10066
|
+
}
|
|
10067
|
+
};
|
|
10068
|
+
}
|
|
10069
|
+
});
|
|
10070
|
+
|
|
9915
10071
|
// src/providers/api-tool-executor.ts
|
|
9916
10072
|
function isHttpUrl(value) {
|
|
9917
10073
|
return value.startsWith("http://") || value.startsWith("https://");
|
|
@@ -10140,7 +10296,8 @@ function getApiToolConfig(tool) {
|
|
|
10140
10296
|
apiKey: tool.apiKey ?? tool.api_key,
|
|
10141
10297
|
securitySchemeName: tool.securitySchemeName ?? tool.security_scheme_name,
|
|
10142
10298
|
securityCredentials: tool.securityCredentials || tool.security_credentials || {},
|
|
10143
|
-
requestTimeoutMs: tool.requestTimeoutMs ?? tool.request_timeout_ms ?? tool.timeout ?? 3e4
|
|
10299
|
+
requestTimeoutMs: tool.requestTimeoutMs ?? tool.request_timeout_ms ?? tool.timeout ?? 3e4,
|
|
10300
|
+
rateLimitConfig: tool.rate_limit
|
|
10144
10301
|
};
|
|
10145
10302
|
}
|
|
10146
10303
|
function buildOutputSchema(operation) {
|
|
@@ -10572,12 +10729,16 @@ async function executeMappedApiTool(mappedTool, args) {
|
|
|
10572
10729
|
const controller = new AbortController();
|
|
10573
10730
|
const timeout = setTimeout(() => controller.abort(), apiToolConfig.requestTimeoutMs);
|
|
10574
10731
|
try {
|
|
10575
|
-
const response = await
|
|
10576
|
-
|
|
10577
|
-
|
|
10578
|
-
|
|
10579
|
-
|
|
10580
|
-
|
|
10732
|
+
const response = await rateLimitedFetch(
|
|
10733
|
+
endpoint.toString(),
|
|
10734
|
+
{
|
|
10735
|
+
method,
|
|
10736
|
+
headers,
|
|
10737
|
+
body: requestBodyValue === void 0 ? void 0 : headers["Content-Type"]?.includes("application/json") ? JSON.stringify(requestBodyValue) : String(requestBodyValue),
|
|
10738
|
+
signal: controller.signal
|
|
10739
|
+
},
|
|
10740
|
+
apiToolConfig.rateLimitConfig
|
|
10741
|
+
);
|
|
10581
10742
|
const raw = await response.text();
|
|
10582
10743
|
let body = raw;
|
|
10583
10744
|
const contentType = response.headers.get("content-type") || "";
|
|
@@ -10621,6 +10782,7 @@ var init_api_tool_executor = __esm({
|
|
|
10621
10782
|
import_jsonpath_plus = require("jsonpath-plus");
|
|
10622
10783
|
import_minimatch = require("minimatch");
|
|
10623
10784
|
init_logger();
|
|
10785
|
+
init_rate_limiter();
|
|
10624
10786
|
HTTP_METHODS = /* @__PURE__ */ new Set(["get", "put", "post", "delete", "options", "head", "patch", "trace"]);
|
|
10625
10787
|
ApiToolRegistry = class {
|
|
10626
10788
|
bundleCache = /* @__PURE__ */ new Map();
|
|
@@ -12978,6 +13140,10 @@ var init_config_schema = __esm({
|
|
|
12978
13140
|
"^x-": {}
|
|
12979
13141
|
}
|
|
12980
13142
|
},
|
|
13143
|
+
rate_limit: {
|
|
13144
|
+
$ref: "#/definitions/RateLimitConfig",
|
|
13145
|
+
description: "Rate limiting configuration for HTTP/API tools"
|
|
13146
|
+
},
|
|
12981
13147
|
workflow: {
|
|
12982
13148
|
type: "string",
|
|
12983
13149
|
description: "Workflow ID (registry lookup) or file path (for type: 'workflow')"
|
|
@@ -13014,6 +13180,43 @@ var init_config_schema = __esm({
|
|
|
13014
13180
|
type: "string"
|
|
13015
13181
|
}
|
|
13016
13182
|
},
|
|
13183
|
+
RateLimitConfig: {
|
|
13184
|
+
type: "object",
|
|
13185
|
+
properties: {
|
|
13186
|
+
key: {
|
|
13187
|
+
type: "string",
|
|
13188
|
+
description: "Shared bucket name; defaults to URL origin"
|
|
13189
|
+
},
|
|
13190
|
+
requests: {
|
|
13191
|
+
type: "number",
|
|
13192
|
+
description: "Max requests per window"
|
|
13193
|
+
},
|
|
13194
|
+
per: {
|
|
13195
|
+
type: "string",
|
|
13196
|
+
enum: ["second", "minute", "hour"],
|
|
13197
|
+
description: "Time window unit"
|
|
13198
|
+
},
|
|
13199
|
+
max_retries: {
|
|
13200
|
+
type: "number",
|
|
13201
|
+
description: "Max retries on 429 (default: 3)"
|
|
13202
|
+
},
|
|
13203
|
+
backoff: {
|
|
13204
|
+
type: "string",
|
|
13205
|
+
enum: ["fixed", "exponential"],
|
|
13206
|
+
description: "Backoff strategy (default: exponential)"
|
|
13207
|
+
},
|
|
13208
|
+
initial_delay_ms: {
|
|
13209
|
+
type: "number",
|
|
13210
|
+
description: "Base delay for backoff in ms (default: 1000)"
|
|
13211
|
+
}
|
|
13212
|
+
},
|
|
13213
|
+
required: ["requests", "per"],
|
|
13214
|
+
additionalProperties: false,
|
|
13215
|
+
description: "Rate limit configuration for HTTP/API requests.",
|
|
13216
|
+
patternProperties: {
|
|
13217
|
+
"^x-": {}
|
|
13218
|
+
}
|
|
13219
|
+
},
|
|
13017
13220
|
WorkflowInput: {
|
|
13018
13221
|
type: "object",
|
|
13019
13222
|
properties: {
|
|
@@ -13116,6 +13319,10 @@ var init_config_schema = __esm({
|
|
|
13116
13319
|
$ref: "#/definitions/Record%3Cstring%2Cstring%3E",
|
|
13117
13320
|
description: "HTTP headers"
|
|
13118
13321
|
},
|
|
13322
|
+
rate_limit: {
|
|
13323
|
+
$ref: "#/definitions/RateLimitConfig",
|
|
13324
|
+
description: "Rate limiting configuration for http_client checks"
|
|
13325
|
+
},
|
|
13119
13326
|
endpoint: {
|
|
13120
13327
|
type: "string",
|
|
13121
13328
|
description: "HTTP endpoint path - required for http_input checks"
|
|
@@ -13517,7 +13724,7 @@ var init_config_schema = __esm({
|
|
|
13517
13724
|
description: "Arguments/inputs for the workflow"
|
|
13518
13725
|
},
|
|
13519
13726
|
overrides: {
|
|
13520
|
-
$ref: "#/definitions/Record%3Cstring%2CPartial%3Cinterface-src_types_config.ts-
|
|
13727
|
+
$ref: "#/definitions/Record%3Cstring%2CPartial%3Cinterface-src_types_config.ts-14532-29218-src_types_config.ts-0-57785%3E%3E",
|
|
13521
13728
|
description: "Override specific step configurations in the workflow"
|
|
13522
13729
|
},
|
|
13523
13730
|
output_mapping: {
|
|
@@ -13533,7 +13740,7 @@ var init_config_schema = __esm({
|
|
|
13533
13740
|
description: "Config file path - alternative to workflow ID (loads a Visor config file as workflow)"
|
|
13534
13741
|
},
|
|
13535
13742
|
workflow_overrides: {
|
|
13536
|
-
$ref: "#/definitions/Record%3Cstring%2CPartial%3Cinterface-src_types_config.ts-
|
|
13743
|
+
$ref: "#/definitions/Record%3Cstring%2CPartial%3Cinterface-src_types_config.ts-14532-29218-src_types_config.ts-0-57785%3E%3E",
|
|
13537
13744
|
description: "Alias for overrides - workflow step overrides (backward compatibility)"
|
|
13538
13745
|
},
|
|
13539
13746
|
ref: {
|
|
@@ -14235,7 +14442,7 @@ var init_config_schema = __esm({
|
|
|
14235
14442
|
description: "Custom output name (defaults to workflow name)"
|
|
14236
14443
|
},
|
|
14237
14444
|
overrides: {
|
|
14238
|
-
$ref: "#/definitions/Record%3Cstring%2CPartial%3Cinterface-src_types_config.ts-
|
|
14445
|
+
$ref: "#/definitions/Record%3Cstring%2CPartial%3Cinterface-src_types_config.ts-14532-29218-src_types_config.ts-0-57785%3E%3E",
|
|
14239
14446
|
description: "Step overrides"
|
|
14240
14447
|
},
|
|
14241
14448
|
output_mapping: {
|
|
@@ -14250,13 +14457,13 @@ var init_config_schema = __esm({
|
|
|
14250
14457
|
"^x-": {}
|
|
14251
14458
|
}
|
|
14252
14459
|
},
|
|
14253
|
-
"Record<string,Partial<interface-src_types_config.ts-
|
|
14460
|
+
"Record<string,Partial<interface-src_types_config.ts-14532-29218-src_types_config.ts-0-57785>>": {
|
|
14254
14461
|
type: "object",
|
|
14255
14462
|
additionalProperties: {
|
|
14256
|
-
$ref: "#/definitions/Partial%3Cinterface-src_types_config.ts-
|
|
14463
|
+
$ref: "#/definitions/Partial%3Cinterface-src_types_config.ts-14532-29218-src_types_config.ts-0-57785%3E"
|
|
14257
14464
|
}
|
|
14258
14465
|
},
|
|
14259
|
-
"Partial<interface-src_types_config.ts-
|
|
14466
|
+
"Partial<interface-src_types_config.ts-14532-29218-src_types_config.ts-0-57785>": {
|
|
14260
14467
|
type: "object",
|
|
14261
14468
|
additionalProperties: false
|
|
14262
14469
|
},
|
|
@@ -18316,6 +18523,14 @@ var init_workflow_check_provider = __esm({
|
|
|
18316
18523
|
inputs,
|
|
18317
18524
|
config.checkName || workflow.id
|
|
18318
18525
|
);
|
|
18526
|
+
const parentTimeout = config.timeout || config.ai?.timeout;
|
|
18527
|
+
if (parentTimeout && workflowConfig.checks) {
|
|
18528
|
+
for (const stepCfg of Object.values(workflowConfig.checks)) {
|
|
18529
|
+
if (!stepCfg.timeout && !stepCfg.ai?.timeout) {
|
|
18530
|
+
stepCfg.timeout = parentTimeout;
|
|
18531
|
+
}
|
|
18532
|
+
}
|
|
18533
|
+
}
|
|
18319
18534
|
const parentMemoryCfg = parentContext?.memory && parentContext.memory.getConfig && parentContext.memory.getConfig() || parentContext?.config?.memory;
|
|
18320
18535
|
const childJournal = new ExecutionJournal2();
|
|
18321
18536
|
const childMemory = MemoryStore2.createIsolated(parentMemoryCfg);
|
|
@@ -18636,17 +18851,17 @@ var init_workflow_check_provider = __esm({
|
|
|
18636
18851
|
* so it can be executed by the state machine as a nested workflow.
|
|
18637
18852
|
*/
|
|
18638
18853
|
async loadWorkflowFromConfigPath(sourcePath, baseDir) {
|
|
18639
|
-
const
|
|
18640
|
-
const
|
|
18854
|
+
const path29 = require("path");
|
|
18855
|
+
const fs25 = require("fs");
|
|
18641
18856
|
const yaml5 = require("js-yaml");
|
|
18642
|
-
const resolved =
|
|
18643
|
-
if (!
|
|
18857
|
+
const resolved = path29.isAbsolute(sourcePath) ? sourcePath : path29.resolve(baseDir, sourcePath);
|
|
18858
|
+
if (!fs25.existsSync(resolved)) {
|
|
18644
18859
|
throw new Error(`Workflow config not found at: ${resolved}`);
|
|
18645
18860
|
}
|
|
18646
|
-
const rawContent =
|
|
18861
|
+
const rawContent = fs25.readFileSync(resolved, "utf8");
|
|
18647
18862
|
const rawData = yaml5.load(rawContent);
|
|
18648
18863
|
if (rawData.imports && Array.isArray(rawData.imports)) {
|
|
18649
|
-
const configDir =
|
|
18864
|
+
const configDir = path29.dirname(resolved);
|
|
18650
18865
|
for (const source of rawData.imports) {
|
|
18651
18866
|
const results = await this.registry.import(source, {
|
|
18652
18867
|
basePath: configDir,
|
|
@@ -18676,8 +18891,8 @@ ${errors}`);
|
|
|
18676
18891
|
if (!steps || Object.keys(steps).length === 0) {
|
|
18677
18892
|
throw new Error(`Config '${resolved}' does not contain any steps to execute as a workflow`);
|
|
18678
18893
|
}
|
|
18679
|
-
const id =
|
|
18680
|
-
const name = loaded.name || `Workflow from ${
|
|
18894
|
+
const id = path29.basename(resolved).replace(/\.(ya?ml)$/i, "");
|
|
18895
|
+
const name = loaded.name || `Workflow from ${path29.basename(resolved)}`;
|
|
18681
18896
|
const workflowDef = {
|
|
18682
18897
|
id,
|
|
18683
18898
|
name,
|
|
@@ -19486,8 +19701,8 @@ async function createStoreBackend(storageConfig, haConfig) {
|
|
|
19486
19701
|
case "mssql": {
|
|
19487
19702
|
try {
|
|
19488
19703
|
const loaderPath = "../../enterprise/loader";
|
|
19489
|
-
const { loadEnterpriseStoreBackend
|
|
19490
|
-
return await
|
|
19704
|
+
const { loadEnterpriseStoreBackend } = await import(loaderPath);
|
|
19705
|
+
return await loadEnterpriseStoreBackend(driver, storageConfig, haConfig);
|
|
19491
19706
|
} catch (err) {
|
|
19492
19707
|
const msg = err instanceof Error ? err.message : String(err);
|
|
19493
19708
|
logger.error(`[StoreFactory] Failed to load enterprise ${driver} backend: ${msg}`);
|
|
@@ -22121,6 +22336,7 @@ var init_mcp_custom_sse_server = __esm({
|
|
|
22121
22336
|
init_schedule_tool();
|
|
22122
22337
|
init_schedule_tool_handler();
|
|
22123
22338
|
init_env_resolver();
|
|
22339
|
+
init_rate_limiter();
|
|
22124
22340
|
CustomToolsSSEServer = class _CustomToolsSSEServer {
|
|
22125
22341
|
server = null;
|
|
22126
22342
|
port = 0;
|
|
@@ -22181,7 +22397,7 @@ var init_mcp_custom_sse_server = __esm({
|
|
|
22181
22397
|
* Returns the actual bound port number
|
|
22182
22398
|
*/
|
|
22183
22399
|
async start() {
|
|
22184
|
-
return new Promise((
|
|
22400
|
+
return new Promise((resolve15, reject) => {
|
|
22185
22401
|
try {
|
|
22186
22402
|
this.server = import_http.default.createServer((req, res) => {
|
|
22187
22403
|
this.handleRequest(req, res).catch((error) => {
|
|
@@ -22215,7 +22431,7 @@ var init_mcp_custom_sse_server = __esm({
|
|
|
22215
22431
|
);
|
|
22216
22432
|
}
|
|
22217
22433
|
this.startKeepalive();
|
|
22218
|
-
|
|
22434
|
+
resolve15(this.port);
|
|
22219
22435
|
});
|
|
22220
22436
|
} catch (error) {
|
|
22221
22437
|
reject(error);
|
|
@@ -22278,7 +22494,7 @@ var init_mcp_custom_sse_server = __esm({
|
|
|
22278
22494
|
logger.debug(
|
|
22279
22495
|
`[CustomToolsSSEServer:${this.sessionId}] Grace period before stop: ${waitMs}ms (activeToolCalls=${this.activeToolCalls})`
|
|
22280
22496
|
);
|
|
22281
|
-
await new Promise((
|
|
22497
|
+
await new Promise((resolve15) => setTimeout(resolve15, waitMs));
|
|
22282
22498
|
}
|
|
22283
22499
|
}
|
|
22284
22500
|
if (this.activeToolCalls > 0) {
|
|
@@ -22287,7 +22503,7 @@ var init_mcp_custom_sse_server = __esm({
|
|
|
22287
22503
|
`[CustomToolsSSEServer:${this.sessionId}] Waiting for ${this.activeToolCalls} active tool call(s) before stop`
|
|
22288
22504
|
);
|
|
22289
22505
|
while (this.activeToolCalls > 0 && Date.now() - startedAt < effectiveDrainTimeoutMs) {
|
|
22290
|
-
await new Promise((
|
|
22506
|
+
await new Promise((resolve15) => setTimeout(resolve15, 250));
|
|
22291
22507
|
}
|
|
22292
22508
|
if (this.activeToolCalls > 0) {
|
|
22293
22509
|
logger.warn(
|
|
@@ -22312,21 +22528,21 @@ var init_mcp_custom_sse_server = __esm({
|
|
|
22312
22528
|
}
|
|
22313
22529
|
this.connections.clear();
|
|
22314
22530
|
if (this.server) {
|
|
22315
|
-
await new Promise((
|
|
22531
|
+
await new Promise((resolve15, reject) => {
|
|
22316
22532
|
const timeout = setTimeout(() => {
|
|
22317
22533
|
if (this.debug) {
|
|
22318
22534
|
logger.debug(
|
|
22319
22535
|
`[CustomToolsSSEServer:${this.sessionId}] Force closing server after timeout`
|
|
22320
22536
|
);
|
|
22321
22537
|
}
|
|
22322
|
-
this.server?.close(() =>
|
|
22538
|
+
this.server?.close(() => resolve15());
|
|
22323
22539
|
}, 5e3);
|
|
22324
22540
|
this.server.close((error) => {
|
|
22325
22541
|
clearTimeout(timeout);
|
|
22326
22542
|
if (error) {
|
|
22327
22543
|
reject(error);
|
|
22328
22544
|
} else {
|
|
22329
|
-
|
|
22545
|
+
resolve15();
|
|
22330
22546
|
}
|
|
22331
22547
|
});
|
|
22332
22548
|
});
|
|
@@ -22783,7 +22999,7 @@ var init_mcp_custom_sse_server = __esm({
|
|
|
22783
22999
|
logger.warn(
|
|
22784
23000
|
`[CustomToolsSSEServer:${this.sessionId}] Tool ${toolName} failed (attempt ${attempt + 1}/${retryCount + 1}): ${errorMsg}. Retrying in ${delay}ms`
|
|
22785
23001
|
);
|
|
22786
|
-
await new Promise((
|
|
23002
|
+
await new Promise((resolve15) => setTimeout(resolve15, delay));
|
|
22787
23003
|
attempt++;
|
|
22788
23004
|
}
|
|
22789
23005
|
}
|
|
@@ -22877,7 +23093,8 @@ var init_mcp_custom_sse_server = __esm({
|
|
|
22877
23093
|
resolvedHeaders["Content-Type"] = "application/json";
|
|
22878
23094
|
}
|
|
22879
23095
|
}
|
|
22880
|
-
const
|
|
23096
|
+
const rateLimitConfig = tool.rate_limit;
|
|
23097
|
+
const response = await rateLimitedFetch(url, requestOptions, rateLimitConfig);
|
|
22881
23098
|
clearTimeout(timeoutId);
|
|
22882
23099
|
if (!response.ok) {
|
|
22883
23100
|
let errorBody = "";
|
|
@@ -23255,9 +23472,9 @@ var init_ai_check_provider = __esm({
|
|
|
23255
23472
|
} else {
|
|
23256
23473
|
resolvedPath = import_path8.default.resolve(process.cwd(), str);
|
|
23257
23474
|
}
|
|
23258
|
-
const
|
|
23475
|
+
const fs25 = require("fs").promises;
|
|
23259
23476
|
try {
|
|
23260
|
-
const stat2 = await
|
|
23477
|
+
const stat2 = await fs25.stat(resolvedPath);
|
|
23261
23478
|
return stat2.isFile();
|
|
23262
23479
|
} catch {
|
|
23263
23480
|
return hasFileExtension && (isRelativePath || isAbsolutePath || hasPathSeparators);
|
|
@@ -25520,6 +25737,7 @@ var init_http_client_provider = __esm({
|
|
|
25520
25737
|
init_template_context();
|
|
25521
25738
|
init_oauth2_token_cache();
|
|
25522
25739
|
init_logger();
|
|
25740
|
+
init_rate_limiter();
|
|
25523
25741
|
fs15 = __toESM(require("fs"));
|
|
25524
25742
|
path19 = __toESM(require("path"));
|
|
25525
25743
|
HttpClientProvider = class extends CheckProvider {
|
|
@@ -25676,6 +25894,7 @@ var init_http_client_provider = __esm({
|
|
|
25676
25894
|
`[http_client] Body: ${requestBody.substring(0, 500)}${requestBody.length > 500 ? "..." : ""}`
|
|
25677
25895
|
);
|
|
25678
25896
|
}
|
|
25897
|
+
const rateLimitConfig = config.rate_limit;
|
|
25679
25898
|
if (resolvedOutputFile) {
|
|
25680
25899
|
const fileResult = await this.downloadToFile(
|
|
25681
25900
|
renderedUrl,
|
|
@@ -25683,11 +25902,19 @@ var init_http_client_provider = __esm({
|
|
|
25683
25902
|
resolvedHeaders,
|
|
25684
25903
|
requestBody,
|
|
25685
25904
|
timeout,
|
|
25686
|
-
resolvedOutputFile
|
|
25905
|
+
resolvedOutputFile,
|
|
25906
|
+
rateLimitConfig
|
|
25687
25907
|
);
|
|
25688
25908
|
return fileResult;
|
|
25689
25909
|
}
|
|
25690
|
-
const data = await this.fetchData(
|
|
25910
|
+
const data = await this.fetchData(
|
|
25911
|
+
renderedUrl,
|
|
25912
|
+
method,
|
|
25913
|
+
resolvedHeaders,
|
|
25914
|
+
requestBody,
|
|
25915
|
+
timeout,
|
|
25916
|
+
rateLimitConfig
|
|
25917
|
+
);
|
|
25691
25918
|
let processedData = data;
|
|
25692
25919
|
if (transform) {
|
|
25693
25920
|
try {
|
|
@@ -25770,7 +25997,7 @@ var init_http_client_provider = __esm({
|
|
|
25770
25997
|
};
|
|
25771
25998
|
}
|
|
25772
25999
|
}
|
|
25773
|
-
async fetchData(url, method, headers, body, timeout = 3e4) {
|
|
26000
|
+
async fetchData(url, method, headers, body, timeout = 3e4, rateLimitConfig) {
|
|
25774
26001
|
if (typeof fetch === "undefined") {
|
|
25775
26002
|
throw new Error("HTTP client provider requires Node.js 18+ or node-fetch package");
|
|
25776
26003
|
}
|
|
@@ -25793,7 +26020,7 @@ var init_http_client_provider = __esm({
|
|
|
25793
26020
|
};
|
|
25794
26021
|
}
|
|
25795
26022
|
}
|
|
25796
|
-
const response = await
|
|
26023
|
+
const response = await rateLimitedFetch(url, requestOptions, rateLimitConfig);
|
|
25797
26024
|
clearTimeout(timeoutId);
|
|
25798
26025
|
logger.verbose(`[http_client] Response: ${response.status} ${response.statusText}`);
|
|
25799
26026
|
if (!response.ok) {
|
|
@@ -25825,7 +26052,7 @@ var init_http_client_provider = __esm({
|
|
|
25825
26052
|
throw error;
|
|
25826
26053
|
}
|
|
25827
26054
|
}
|
|
25828
|
-
async downloadToFile(url, method, headers, body, timeout, outputFile) {
|
|
26055
|
+
async downloadToFile(url, method, headers, body, timeout, outputFile, rateLimitConfig) {
|
|
25829
26056
|
if (typeof fetch === "undefined") {
|
|
25830
26057
|
throw new Error("HTTP client provider requires Node.js 18+ or node-fetch package");
|
|
25831
26058
|
}
|
|
@@ -25846,7 +26073,7 @@ var init_http_client_provider = __esm({
|
|
|
25846
26073
|
};
|
|
25847
26074
|
}
|
|
25848
26075
|
}
|
|
25849
|
-
const response = await
|
|
26076
|
+
const response = await rateLimitedFetch(url, requestOptions, rateLimitConfig);
|
|
25850
26077
|
clearTimeout(timeoutId);
|
|
25851
26078
|
if (!response.ok) {
|
|
25852
26079
|
return {
|
|
@@ -29408,14 +29635,14 @@ var require_util = __commonJS({
|
|
|
29408
29635
|
}
|
|
29409
29636
|
const port = url.port != null ? url.port : url.protocol === "https:" ? 443 : 80;
|
|
29410
29637
|
let origin = url.origin != null ? url.origin : `${url.protocol}//${url.hostname}:${port}`;
|
|
29411
|
-
let
|
|
29638
|
+
let path29 = url.path != null ? url.path : `${url.pathname || ""}${url.search || ""}`;
|
|
29412
29639
|
if (origin.endsWith("/")) {
|
|
29413
29640
|
origin = origin.substring(0, origin.length - 1);
|
|
29414
29641
|
}
|
|
29415
|
-
if (
|
|
29416
|
-
|
|
29642
|
+
if (path29 && !path29.startsWith("/")) {
|
|
29643
|
+
path29 = `/${path29}`;
|
|
29417
29644
|
}
|
|
29418
|
-
url = new URL(origin +
|
|
29645
|
+
url = new URL(origin + path29);
|
|
29419
29646
|
}
|
|
29420
29647
|
return url;
|
|
29421
29648
|
}
|
|
@@ -31029,20 +31256,20 @@ var require_parseParams = __commonJS({
|
|
|
31029
31256
|
var require_basename = __commonJS({
|
|
31030
31257
|
"node_modules/@fastify/busboy/lib/utils/basename.js"(exports2, module2) {
|
|
31031
31258
|
"use strict";
|
|
31032
|
-
module2.exports = function basename4(
|
|
31033
|
-
if (typeof
|
|
31259
|
+
module2.exports = function basename4(path29) {
|
|
31260
|
+
if (typeof path29 !== "string") {
|
|
31034
31261
|
return "";
|
|
31035
31262
|
}
|
|
31036
|
-
for (var i =
|
|
31037
|
-
switch (
|
|
31263
|
+
for (var i = path29.length - 1; i >= 0; --i) {
|
|
31264
|
+
switch (path29.charCodeAt(i)) {
|
|
31038
31265
|
case 47:
|
|
31039
31266
|
// '/'
|
|
31040
31267
|
case 92:
|
|
31041
|
-
|
|
31042
|
-
return
|
|
31268
|
+
path29 = path29.slice(i + 1);
|
|
31269
|
+
return path29 === ".." || path29 === "." ? "" : path29;
|
|
31043
31270
|
}
|
|
31044
31271
|
}
|
|
31045
|
-
return
|
|
31272
|
+
return path29 === ".." || path29 === "." ? "" : path29;
|
|
31046
31273
|
};
|
|
31047
31274
|
}
|
|
31048
31275
|
});
|
|
@@ -32046,11 +32273,11 @@ var require_util2 = __commonJS({
|
|
|
32046
32273
|
var assert = require("assert");
|
|
32047
32274
|
var { isUint8Array } = require("util/types");
|
|
32048
32275
|
var supportedHashes = [];
|
|
32049
|
-
var
|
|
32276
|
+
var crypto7;
|
|
32050
32277
|
try {
|
|
32051
|
-
|
|
32278
|
+
crypto7 = require("crypto");
|
|
32052
32279
|
const possibleRelevantHashes = ["sha256", "sha384", "sha512"];
|
|
32053
|
-
supportedHashes =
|
|
32280
|
+
supportedHashes = crypto7.getHashes().filter((hash) => possibleRelevantHashes.includes(hash));
|
|
32054
32281
|
} catch {
|
|
32055
32282
|
}
|
|
32056
32283
|
function responseURL(response) {
|
|
@@ -32327,7 +32554,7 @@ var require_util2 = __commonJS({
|
|
|
32327
32554
|
}
|
|
32328
32555
|
}
|
|
32329
32556
|
function bytesMatch(bytes, metadataList) {
|
|
32330
|
-
if (
|
|
32557
|
+
if (crypto7 === void 0) {
|
|
32331
32558
|
return true;
|
|
32332
32559
|
}
|
|
32333
32560
|
const parsedMetadata = parseMetadata(metadataList);
|
|
@@ -32342,7 +32569,7 @@ var require_util2 = __commonJS({
|
|
|
32342
32569
|
for (const item of metadata) {
|
|
32343
32570
|
const algorithm = item.algo;
|
|
32344
32571
|
const expectedValue = item.hash;
|
|
32345
|
-
let actualValue =
|
|
32572
|
+
let actualValue = crypto7.createHash(algorithm).update(bytes).digest("base64");
|
|
32346
32573
|
if (actualValue[actualValue.length - 1] === "=") {
|
|
32347
32574
|
if (actualValue[actualValue.length - 2] === "=") {
|
|
32348
32575
|
actualValue = actualValue.slice(0, -2);
|
|
@@ -32435,8 +32662,8 @@ var require_util2 = __commonJS({
|
|
|
32435
32662
|
function createDeferredPromise() {
|
|
32436
32663
|
let res;
|
|
32437
32664
|
let rej;
|
|
32438
|
-
const promise = new Promise((
|
|
32439
|
-
res =
|
|
32665
|
+
const promise = new Promise((resolve15, reject) => {
|
|
32666
|
+
res = resolve15;
|
|
32440
32667
|
rej = reject;
|
|
32441
32668
|
});
|
|
32442
32669
|
return { promise, resolve: res, reject: rej };
|
|
@@ -33689,8 +33916,8 @@ var require_body = __commonJS({
|
|
|
33689
33916
|
var { parseMIMEType, serializeAMimeType } = require_dataURL();
|
|
33690
33917
|
var random;
|
|
33691
33918
|
try {
|
|
33692
|
-
const
|
|
33693
|
-
random = (max) =>
|
|
33919
|
+
const crypto7 = require("crypto");
|
|
33920
|
+
random = (max) => crypto7.randomInt(0, max);
|
|
33694
33921
|
} catch {
|
|
33695
33922
|
random = (max) => Math.floor(Math.random(max));
|
|
33696
33923
|
}
|
|
@@ -33941,8 +34168,8 @@ Content-Type: ${value.type || "application/octet-stream"}\r
|
|
|
33941
34168
|
});
|
|
33942
34169
|
}
|
|
33943
34170
|
});
|
|
33944
|
-
const busboyResolve = new Promise((
|
|
33945
|
-
busboy.on("finish",
|
|
34171
|
+
const busboyResolve = new Promise((resolve15, reject) => {
|
|
34172
|
+
busboy.on("finish", resolve15);
|
|
33946
34173
|
busboy.on("error", (err) => reject(new TypeError(err)));
|
|
33947
34174
|
});
|
|
33948
34175
|
if (this.body !== null) for await (const chunk of consumeBody(this[kState].body)) busboy.write(chunk);
|
|
@@ -34073,7 +34300,7 @@ var require_request = __commonJS({
|
|
|
34073
34300
|
}
|
|
34074
34301
|
var Request2 = class _Request {
|
|
34075
34302
|
constructor(origin, {
|
|
34076
|
-
path:
|
|
34303
|
+
path: path29,
|
|
34077
34304
|
method,
|
|
34078
34305
|
body,
|
|
34079
34306
|
headers,
|
|
@@ -34087,11 +34314,11 @@ var require_request = __commonJS({
|
|
|
34087
34314
|
throwOnError,
|
|
34088
34315
|
expectContinue
|
|
34089
34316
|
}, handler) {
|
|
34090
|
-
if (typeof
|
|
34317
|
+
if (typeof path29 !== "string") {
|
|
34091
34318
|
throw new InvalidArgumentError("path must be a string");
|
|
34092
|
-
} else if (
|
|
34319
|
+
} else if (path29[0] !== "/" && !(path29.startsWith("http://") || path29.startsWith("https://")) && method !== "CONNECT") {
|
|
34093
34320
|
throw new InvalidArgumentError("path must be an absolute URL or start with a slash");
|
|
34094
|
-
} else if (invalidPathRegex.exec(
|
|
34321
|
+
} else if (invalidPathRegex.exec(path29) !== null) {
|
|
34095
34322
|
throw new InvalidArgumentError("invalid request path");
|
|
34096
34323
|
}
|
|
34097
34324
|
if (typeof method !== "string") {
|
|
@@ -34154,7 +34381,7 @@ var require_request = __commonJS({
|
|
|
34154
34381
|
this.completed = false;
|
|
34155
34382
|
this.aborted = false;
|
|
34156
34383
|
this.upgrade = upgrade || null;
|
|
34157
|
-
this.path = query ? util.buildURL(
|
|
34384
|
+
this.path = query ? util.buildURL(path29, query) : path29;
|
|
34158
34385
|
this.origin = origin;
|
|
34159
34386
|
this.idempotent = idempotent == null ? method === "HEAD" || method === "GET" : idempotent;
|
|
34160
34387
|
this.blocking = blocking == null ? false : blocking;
|
|
@@ -34476,9 +34703,9 @@ var require_dispatcher_base = __commonJS({
|
|
|
34476
34703
|
}
|
|
34477
34704
|
close(callback) {
|
|
34478
34705
|
if (callback === void 0) {
|
|
34479
|
-
return new Promise((
|
|
34706
|
+
return new Promise((resolve15, reject) => {
|
|
34480
34707
|
this.close((err, data) => {
|
|
34481
|
-
return err ? reject(err) :
|
|
34708
|
+
return err ? reject(err) : resolve15(data);
|
|
34482
34709
|
});
|
|
34483
34710
|
});
|
|
34484
34711
|
}
|
|
@@ -34516,12 +34743,12 @@ var require_dispatcher_base = __commonJS({
|
|
|
34516
34743
|
err = null;
|
|
34517
34744
|
}
|
|
34518
34745
|
if (callback === void 0) {
|
|
34519
|
-
return new Promise((
|
|
34746
|
+
return new Promise((resolve15, reject) => {
|
|
34520
34747
|
this.destroy(err, (err2, data) => {
|
|
34521
34748
|
return err2 ? (
|
|
34522
34749
|
/* istanbul ignore next: should never error */
|
|
34523
34750
|
reject(err2)
|
|
34524
|
-
) :
|
|
34751
|
+
) : resolve15(data);
|
|
34525
34752
|
});
|
|
34526
34753
|
});
|
|
34527
34754
|
}
|
|
@@ -35162,9 +35389,9 @@ var require_RedirectHandler = __commonJS({
|
|
|
35162
35389
|
return this.handler.onHeaders(statusCode, headers, resume, statusText);
|
|
35163
35390
|
}
|
|
35164
35391
|
const { origin, pathname, search } = util.parseURL(new URL(this.location, this.opts.origin && new URL(this.opts.path, this.opts.origin)));
|
|
35165
|
-
const
|
|
35392
|
+
const path29 = search ? `${pathname}${search}` : pathname;
|
|
35166
35393
|
this.opts.headers = cleanRequestHeaders(this.opts.headers, statusCode === 303, this.opts.origin !== origin);
|
|
35167
|
-
this.opts.path =
|
|
35394
|
+
this.opts.path = path29;
|
|
35168
35395
|
this.opts.origin = origin;
|
|
35169
35396
|
this.opts.maxRedirections = 0;
|
|
35170
35397
|
this.opts.query = null;
|
|
@@ -35583,16 +35810,16 @@ var require_client = __commonJS({
|
|
|
35583
35810
|
return this[kNeedDrain] < 2;
|
|
35584
35811
|
}
|
|
35585
35812
|
async [kClose]() {
|
|
35586
|
-
return new Promise((
|
|
35813
|
+
return new Promise((resolve15) => {
|
|
35587
35814
|
if (!this[kSize]) {
|
|
35588
|
-
|
|
35815
|
+
resolve15(null);
|
|
35589
35816
|
} else {
|
|
35590
|
-
this[kClosedResolve] =
|
|
35817
|
+
this[kClosedResolve] = resolve15;
|
|
35591
35818
|
}
|
|
35592
35819
|
});
|
|
35593
35820
|
}
|
|
35594
35821
|
async [kDestroy](err) {
|
|
35595
|
-
return new Promise((
|
|
35822
|
+
return new Promise((resolve15) => {
|
|
35596
35823
|
const requests = this[kQueue].splice(this[kPendingIdx]);
|
|
35597
35824
|
for (let i = 0; i < requests.length; i++) {
|
|
35598
35825
|
const request = requests[i];
|
|
@@ -35603,7 +35830,7 @@ var require_client = __commonJS({
|
|
|
35603
35830
|
this[kClosedResolve]();
|
|
35604
35831
|
this[kClosedResolve] = null;
|
|
35605
35832
|
}
|
|
35606
|
-
|
|
35833
|
+
resolve15();
|
|
35607
35834
|
};
|
|
35608
35835
|
if (this[kHTTP2Session] != null) {
|
|
35609
35836
|
util.destroy(this[kHTTP2Session], err);
|
|
@@ -36183,7 +36410,7 @@ var require_client = __commonJS({
|
|
|
36183
36410
|
});
|
|
36184
36411
|
}
|
|
36185
36412
|
try {
|
|
36186
|
-
const socket = await new Promise((
|
|
36413
|
+
const socket = await new Promise((resolve15, reject) => {
|
|
36187
36414
|
client[kConnector]({
|
|
36188
36415
|
host,
|
|
36189
36416
|
hostname,
|
|
@@ -36195,7 +36422,7 @@ var require_client = __commonJS({
|
|
|
36195
36422
|
if (err) {
|
|
36196
36423
|
reject(err);
|
|
36197
36424
|
} else {
|
|
36198
|
-
|
|
36425
|
+
resolve15(socket2);
|
|
36199
36426
|
}
|
|
36200
36427
|
});
|
|
36201
36428
|
});
|
|
@@ -36406,7 +36633,7 @@ var require_client = __commonJS({
|
|
|
36406
36633
|
writeH2(client, client[kHTTP2Session], request);
|
|
36407
36634
|
return;
|
|
36408
36635
|
}
|
|
36409
|
-
const { body, method, path:
|
|
36636
|
+
const { body, method, path: path29, host, upgrade, headers, blocking, reset } = request;
|
|
36410
36637
|
const expectsPayload = method === "PUT" || method === "POST" || method === "PATCH";
|
|
36411
36638
|
if (body && typeof body.read === "function") {
|
|
36412
36639
|
body.read(0);
|
|
@@ -36456,7 +36683,7 @@ var require_client = __commonJS({
|
|
|
36456
36683
|
if (blocking) {
|
|
36457
36684
|
socket[kBlocking] = true;
|
|
36458
36685
|
}
|
|
36459
|
-
let header = `${method} ${
|
|
36686
|
+
let header = `${method} ${path29} HTTP/1.1\r
|
|
36460
36687
|
`;
|
|
36461
36688
|
if (typeof host === "string") {
|
|
36462
36689
|
header += `host: ${host}\r
|
|
@@ -36519,7 +36746,7 @@ upgrade: ${upgrade}\r
|
|
|
36519
36746
|
return true;
|
|
36520
36747
|
}
|
|
36521
36748
|
function writeH2(client, session, request) {
|
|
36522
|
-
const { body, method, path:
|
|
36749
|
+
const { body, method, path: path29, host, upgrade, expectContinue, signal, headers: reqHeaders } = request;
|
|
36523
36750
|
let headers;
|
|
36524
36751
|
if (typeof reqHeaders === "string") headers = Request2[kHTTP2CopyHeaders](reqHeaders.trim());
|
|
36525
36752
|
else headers = reqHeaders;
|
|
@@ -36562,7 +36789,7 @@ upgrade: ${upgrade}\r
|
|
|
36562
36789
|
});
|
|
36563
36790
|
return true;
|
|
36564
36791
|
}
|
|
36565
|
-
headers[HTTP2_HEADER_PATH] =
|
|
36792
|
+
headers[HTTP2_HEADER_PATH] = path29;
|
|
36566
36793
|
headers[HTTP2_HEADER_SCHEME] = "https";
|
|
36567
36794
|
const expectsPayload = method === "PUT" || method === "POST" || method === "PATCH";
|
|
36568
36795
|
if (body && typeof body.read === "function") {
|
|
@@ -36819,12 +37046,12 @@ upgrade: ${upgrade}\r
|
|
|
36819
37046
|
cb();
|
|
36820
37047
|
}
|
|
36821
37048
|
}
|
|
36822
|
-
const waitForDrain = () => new Promise((
|
|
37049
|
+
const waitForDrain = () => new Promise((resolve15, reject) => {
|
|
36823
37050
|
assert(callback === null);
|
|
36824
37051
|
if (socket[kError]) {
|
|
36825
37052
|
reject(socket[kError]);
|
|
36826
37053
|
} else {
|
|
36827
|
-
callback =
|
|
37054
|
+
callback = resolve15;
|
|
36828
37055
|
}
|
|
36829
37056
|
});
|
|
36830
37057
|
if (client[kHTTPConnVersion] === "h2") {
|
|
@@ -37170,8 +37397,8 @@ var require_pool_base = __commonJS({
|
|
|
37170
37397
|
if (this[kQueue].isEmpty()) {
|
|
37171
37398
|
return Promise.all(this[kClients].map((c) => c.close()));
|
|
37172
37399
|
} else {
|
|
37173
|
-
return new Promise((
|
|
37174
|
-
this[kClosedResolve] =
|
|
37400
|
+
return new Promise((resolve15) => {
|
|
37401
|
+
this[kClosedResolve] = resolve15;
|
|
37175
37402
|
});
|
|
37176
37403
|
}
|
|
37177
37404
|
}
|
|
@@ -37749,7 +37976,7 @@ var require_readable = __commonJS({
|
|
|
37749
37976
|
if (this.closed) {
|
|
37750
37977
|
return Promise.resolve(null);
|
|
37751
37978
|
}
|
|
37752
|
-
return new Promise((
|
|
37979
|
+
return new Promise((resolve15, reject) => {
|
|
37753
37980
|
const signalListenerCleanup = signal ? util.addAbortListener(signal, () => {
|
|
37754
37981
|
this.destroy();
|
|
37755
37982
|
}) : noop;
|
|
@@ -37758,7 +37985,7 @@ var require_readable = __commonJS({
|
|
|
37758
37985
|
if (signal && signal.aborted) {
|
|
37759
37986
|
reject(signal.reason || Object.assign(new Error("The operation was aborted"), { name: "AbortError" }));
|
|
37760
37987
|
} else {
|
|
37761
|
-
|
|
37988
|
+
resolve15(null);
|
|
37762
37989
|
}
|
|
37763
37990
|
}).on("error", noop).on("data", function(chunk) {
|
|
37764
37991
|
limit -= chunk.length;
|
|
@@ -37780,11 +38007,11 @@ var require_readable = __commonJS({
|
|
|
37780
38007
|
throw new TypeError("unusable");
|
|
37781
38008
|
}
|
|
37782
38009
|
assert(!stream[kConsume]);
|
|
37783
|
-
return new Promise((
|
|
38010
|
+
return new Promise((resolve15, reject) => {
|
|
37784
38011
|
stream[kConsume] = {
|
|
37785
38012
|
type,
|
|
37786
38013
|
stream,
|
|
37787
|
-
resolve:
|
|
38014
|
+
resolve: resolve15,
|
|
37788
38015
|
reject,
|
|
37789
38016
|
length: 0,
|
|
37790
38017
|
body: []
|
|
@@ -37819,12 +38046,12 @@ var require_readable = __commonJS({
|
|
|
37819
38046
|
}
|
|
37820
38047
|
}
|
|
37821
38048
|
function consumeEnd(consume2) {
|
|
37822
|
-
const { type, body, resolve:
|
|
38049
|
+
const { type, body, resolve: resolve15, stream, length } = consume2;
|
|
37823
38050
|
try {
|
|
37824
38051
|
if (type === "text") {
|
|
37825
|
-
|
|
38052
|
+
resolve15(toUSVString(Buffer.concat(body)));
|
|
37826
38053
|
} else if (type === "json") {
|
|
37827
|
-
|
|
38054
|
+
resolve15(JSON.parse(Buffer.concat(body)));
|
|
37828
38055
|
} else if (type === "arrayBuffer") {
|
|
37829
38056
|
const dst = new Uint8Array(length);
|
|
37830
38057
|
let pos = 0;
|
|
@@ -37832,12 +38059,12 @@ var require_readable = __commonJS({
|
|
|
37832
38059
|
dst.set(buf, pos);
|
|
37833
38060
|
pos += buf.byteLength;
|
|
37834
38061
|
}
|
|
37835
|
-
|
|
38062
|
+
resolve15(dst.buffer);
|
|
37836
38063
|
} else if (type === "blob") {
|
|
37837
38064
|
if (!Blob2) {
|
|
37838
38065
|
Blob2 = require("buffer").Blob;
|
|
37839
38066
|
}
|
|
37840
|
-
|
|
38067
|
+
resolve15(new Blob2(body, { type: stream[kContentType] }));
|
|
37841
38068
|
}
|
|
37842
38069
|
consumeFinish(consume2);
|
|
37843
38070
|
} catch (err) {
|
|
@@ -38094,9 +38321,9 @@ var require_api_request = __commonJS({
|
|
|
38094
38321
|
};
|
|
38095
38322
|
function request(opts, callback) {
|
|
38096
38323
|
if (callback === void 0) {
|
|
38097
|
-
return new Promise((
|
|
38324
|
+
return new Promise((resolve15, reject) => {
|
|
38098
38325
|
request.call(this, opts, (err, data) => {
|
|
38099
|
-
return err ? reject(err) :
|
|
38326
|
+
return err ? reject(err) : resolve15(data);
|
|
38100
38327
|
});
|
|
38101
38328
|
});
|
|
38102
38329
|
}
|
|
@@ -38269,9 +38496,9 @@ var require_api_stream = __commonJS({
|
|
|
38269
38496
|
};
|
|
38270
38497
|
function stream(opts, factory, callback) {
|
|
38271
38498
|
if (callback === void 0) {
|
|
38272
|
-
return new Promise((
|
|
38499
|
+
return new Promise((resolve15, reject) => {
|
|
38273
38500
|
stream.call(this, opts, factory, (err, data) => {
|
|
38274
|
-
return err ? reject(err) :
|
|
38501
|
+
return err ? reject(err) : resolve15(data);
|
|
38275
38502
|
});
|
|
38276
38503
|
});
|
|
38277
38504
|
}
|
|
@@ -38552,9 +38779,9 @@ var require_api_upgrade = __commonJS({
|
|
|
38552
38779
|
};
|
|
38553
38780
|
function upgrade(opts, callback) {
|
|
38554
38781
|
if (callback === void 0) {
|
|
38555
|
-
return new Promise((
|
|
38782
|
+
return new Promise((resolve15, reject) => {
|
|
38556
38783
|
upgrade.call(this, opts, (err, data) => {
|
|
38557
|
-
return err ? reject(err) :
|
|
38784
|
+
return err ? reject(err) : resolve15(data);
|
|
38558
38785
|
});
|
|
38559
38786
|
});
|
|
38560
38787
|
}
|
|
@@ -38643,9 +38870,9 @@ var require_api_connect = __commonJS({
|
|
|
38643
38870
|
};
|
|
38644
38871
|
function connect(opts, callback) {
|
|
38645
38872
|
if (callback === void 0) {
|
|
38646
|
-
return new Promise((
|
|
38873
|
+
return new Promise((resolve15, reject) => {
|
|
38647
38874
|
connect.call(this, opts, (err, data) => {
|
|
38648
|
-
return err ? reject(err) :
|
|
38875
|
+
return err ? reject(err) : resolve15(data);
|
|
38649
38876
|
});
|
|
38650
38877
|
});
|
|
38651
38878
|
}
|
|
@@ -38805,20 +39032,20 @@ var require_mock_utils = __commonJS({
|
|
|
38805
39032
|
}
|
|
38806
39033
|
return true;
|
|
38807
39034
|
}
|
|
38808
|
-
function safeUrl(
|
|
38809
|
-
if (typeof
|
|
38810
|
-
return
|
|
39035
|
+
function safeUrl(path29) {
|
|
39036
|
+
if (typeof path29 !== "string") {
|
|
39037
|
+
return path29;
|
|
38811
39038
|
}
|
|
38812
|
-
const pathSegments =
|
|
39039
|
+
const pathSegments = path29.split("?");
|
|
38813
39040
|
if (pathSegments.length !== 2) {
|
|
38814
|
-
return
|
|
39041
|
+
return path29;
|
|
38815
39042
|
}
|
|
38816
39043
|
const qp = new URLSearchParams(pathSegments.pop());
|
|
38817
39044
|
qp.sort();
|
|
38818
39045
|
return [...pathSegments, qp.toString()].join("?");
|
|
38819
39046
|
}
|
|
38820
|
-
function matchKey(mockDispatch2, { path:
|
|
38821
|
-
const pathMatch = matchValue(mockDispatch2.path,
|
|
39047
|
+
function matchKey(mockDispatch2, { path: path29, method, body, headers }) {
|
|
39048
|
+
const pathMatch = matchValue(mockDispatch2.path, path29);
|
|
38822
39049
|
const methodMatch = matchValue(mockDispatch2.method, method);
|
|
38823
39050
|
const bodyMatch = typeof mockDispatch2.body !== "undefined" ? matchValue(mockDispatch2.body, body) : true;
|
|
38824
39051
|
const headersMatch = matchHeaders(mockDispatch2, headers);
|
|
@@ -38836,7 +39063,7 @@ var require_mock_utils = __commonJS({
|
|
|
38836
39063
|
function getMockDispatch(mockDispatches, key) {
|
|
38837
39064
|
const basePath = key.query ? buildURL(key.path, key.query) : key.path;
|
|
38838
39065
|
const resolvedPath = typeof basePath === "string" ? safeUrl(basePath) : basePath;
|
|
38839
|
-
let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path:
|
|
39066
|
+
let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path: path29 }) => matchValue(safeUrl(path29), resolvedPath));
|
|
38840
39067
|
if (matchedMockDispatches.length === 0) {
|
|
38841
39068
|
throw new MockNotMatchedError(`Mock dispatch not matched for path '${resolvedPath}'`);
|
|
38842
39069
|
}
|
|
@@ -38873,9 +39100,9 @@ var require_mock_utils = __commonJS({
|
|
|
38873
39100
|
}
|
|
38874
39101
|
}
|
|
38875
39102
|
function buildKey(opts) {
|
|
38876
|
-
const { path:
|
|
39103
|
+
const { path: path29, method, body, headers, query } = opts;
|
|
38877
39104
|
return {
|
|
38878
|
-
path:
|
|
39105
|
+
path: path29,
|
|
38879
39106
|
method,
|
|
38880
39107
|
body,
|
|
38881
39108
|
headers,
|
|
@@ -39324,10 +39551,10 @@ var require_pending_interceptors_formatter = __commonJS({
|
|
|
39324
39551
|
}
|
|
39325
39552
|
format(pendingInterceptors) {
|
|
39326
39553
|
const withPrettyHeaders = pendingInterceptors.map(
|
|
39327
|
-
({ method, path:
|
|
39554
|
+
({ method, path: path29, data: { statusCode }, persist, times, timesInvoked, origin }) => ({
|
|
39328
39555
|
Method: method,
|
|
39329
39556
|
Origin: origin,
|
|
39330
|
-
Path:
|
|
39557
|
+
Path: path29,
|
|
39331
39558
|
"Status code": statusCode,
|
|
39332
39559
|
Persistent: persist ? "\u2705" : "\u274C",
|
|
39333
39560
|
Invocations: timesInvoked,
|
|
@@ -42268,7 +42495,7 @@ var require_fetch = __commonJS({
|
|
|
42268
42495
|
async function dispatch({ body }) {
|
|
42269
42496
|
const url = requestCurrentURL(request);
|
|
42270
42497
|
const agent = fetchParams.controller.dispatcher;
|
|
42271
|
-
return new Promise((
|
|
42498
|
+
return new Promise((resolve15, reject) => agent.dispatch(
|
|
42272
42499
|
{
|
|
42273
42500
|
path: url.pathname + url.search,
|
|
42274
42501
|
origin: url.origin,
|
|
@@ -42344,7 +42571,7 @@ var require_fetch = __commonJS({
|
|
|
42344
42571
|
}
|
|
42345
42572
|
}
|
|
42346
42573
|
}
|
|
42347
|
-
|
|
42574
|
+
resolve15({
|
|
42348
42575
|
status,
|
|
42349
42576
|
statusText,
|
|
42350
42577
|
headersList: headers[kHeadersList],
|
|
@@ -42387,7 +42614,7 @@ var require_fetch = __commonJS({
|
|
|
42387
42614
|
const val = headersList[n + 1].toString("latin1");
|
|
42388
42615
|
headers[kHeadersList].append(key, val);
|
|
42389
42616
|
}
|
|
42390
|
-
|
|
42617
|
+
resolve15({
|
|
42391
42618
|
status,
|
|
42392
42619
|
statusText: STATUS_CODES[status],
|
|
42393
42620
|
headersList: headers[kHeadersList],
|
|
@@ -43948,8 +44175,8 @@ var require_util6 = __commonJS({
|
|
|
43948
44175
|
}
|
|
43949
44176
|
}
|
|
43950
44177
|
}
|
|
43951
|
-
function validateCookiePath(
|
|
43952
|
-
for (const char of
|
|
44178
|
+
function validateCookiePath(path29) {
|
|
44179
|
+
for (const char of path29) {
|
|
43953
44180
|
const code = char.charCodeAt(0);
|
|
43954
44181
|
if (code < 33 || char === ";") {
|
|
43955
44182
|
throw new Error("Invalid cookie path");
|
|
@@ -44746,9 +44973,9 @@ var require_connection = __commonJS({
|
|
|
44746
44973
|
channels.open = diagnosticsChannel.channel("undici:websocket:open");
|
|
44747
44974
|
channels.close = diagnosticsChannel.channel("undici:websocket:close");
|
|
44748
44975
|
channels.socketError = diagnosticsChannel.channel("undici:websocket:socket_error");
|
|
44749
|
-
var
|
|
44976
|
+
var crypto7;
|
|
44750
44977
|
try {
|
|
44751
|
-
|
|
44978
|
+
crypto7 = require("crypto");
|
|
44752
44979
|
} catch {
|
|
44753
44980
|
}
|
|
44754
44981
|
function establishWebSocketConnection(url, protocols, ws, onEstablish, options) {
|
|
@@ -44767,7 +44994,7 @@ var require_connection = __commonJS({
|
|
|
44767
44994
|
const headersList = new Headers(options.headers)[kHeadersList];
|
|
44768
44995
|
request.headersList = headersList;
|
|
44769
44996
|
}
|
|
44770
|
-
const keyValue =
|
|
44997
|
+
const keyValue = crypto7.randomBytes(16).toString("base64");
|
|
44771
44998
|
request.headersList.append("sec-websocket-key", keyValue);
|
|
44772
44999
|
request.headersList.append("sec-websocket-version", "13");
|
|
44773
45000
|
for (const protocol of protocols) {
|
|
@@ -44796,7 +45023,7 @@ var require_connection = __commonJS({
|
|
|
44796
45023
|
return;
|
|
44797
45024
|
}
|
|
44798
45025
|
const secWSAccept = response.headersList.get("Sec-WebSocket-Accept");
|
|
44799
|
-
const digest =
|
|
45026
|
+
const digest = crypto7.createHash("sha1").update(keyValue + uid).digest("base64");
|
|
44800
45027
|
if (secWSAccept !== digest) {
|
|
44801
45028
|
failWebsocketConnection(ws, "Incorrect hash received in Sec-WebSocket-Accept header.");
|
|
44802
45029
|
return;
|
|
@@ -44876,9 +45103,9 @@ var require_frame = __commonJS({
|
|
|
44876
45103
|
"node_modules/undici/lib/websocket/frame.js"(exports2, module2) {
|
|
44877
45104
|
"use strict";
|
|
44878
45105
|
var { maxUnsigned16Bit } = require_constants5();
|
|
44879
|
-
var
|
|
45106
|
+
var crypto7;
|
|
44880
45107
|
try {
|
|
44881
|
-
|
|
45108
|
+
crypto7 = require("crypto");
|
|
44882
45109
|
} catch {
|
|
44883
45110
|
}
|
|
44884
45111
|
var WebsocketFrameSend = class {
|
|
@@ -44887,7 +45114,7 @@ var require_frame = __commonJS({
|
|
|
44887
45114
|
*/
|
|
44888
45115
|
constructor(data) {
|
|
44889
45116
|
this.frameData = data;
|
|
44890
|
-
this.maskKey =
|
|
45117
|
+
this.maskKey = crypto7.randomBytes(4);
|
|
44891
45118
|
}
|
|
44892
45119
|
createFrame(opcode) {
|
|
44893
45120
|
const bodyLength = this.frameData?.byteLength ?? 0;
|
|
@@ -45629,11 +45856,11 @@ var require_undici = __commonJS({
|
|
|
45629
45856
|
if (typeof opts.path !== "string") {
|
|
45630
45857
|
throw new InvalidArgumentError("invalid opts.path");
|
|
45631
45858
|
}
|
|
45632
|
-
let
|
|
45859
|
+
let path29 = opts.path;
|
|
45633
45860
|
if (!opts.path.startsWith("/")) {
|
|
45634
|
-
|
|
45861
|
+
path29 = `/${path29}`;
|
|
45635
45862
|
}
|
|
45636
|
-
url = new URL(util.parseOrigin(url).origin +
|
|
45863
|
+
url = new URL(util.parseOrigin(url).origin + path29);
|
|
45637
45864
|
} else {
|
|
45638
45865
|
if (!opts) {
|
|
45639
45866
|
opts = typeof url === "object" ? url : {};
|
|
@@ -46202,7 +46429,7 @@ var init_mcp_check_provider = __esm({
|
|
|
46202
46429
|
logger.warn(
|
|
46203
46430
|
`MCP ${transportName} failed (attempt ${attempt + 1}/${maxRetries + 1}), retrying in ${delay}ms: ${error instanceof Error ? error.message : String(error)}`
|
|
46204
46431
|
);
|
|
46205
|
-
await new Promise((
|
|
46432
|
+
await new Promise((resolve15) => setTimeout(resolve15, delay));
|
|
46206
46433
|
attempt += 1;
|
|
46207
46434
|
} finally {
|
|
46208
46435
|
try {
|
|
@@ -46495,7 +46722,7 @@ async function acquirePromptLock() {
|
|
|
46495
46722
|
);
|
|
46496
46723
|
}, 1e4);
|
|
46497
46724
|
try {
|
|
46498
|
-
await new Promise((
|
|
46725
|
+
await new Promise((resolve15) => waiters.push(resolve15));
|
|
46499
46726
|
} finally {
|
|
46500
46727
|
clearInterval(reminder);
|
|
46501
46728
|
const waitedMs = Date.now() - queuedAt;
|
|
@@ -46514,7 +46741,7 @@ function releasePromptLock() {
|
|
|
46514
46741
|
}
|
|
46515
46742
|
async function interactivePrompt(options) {
|
|
46516
46743
|
await acquirePromptLock();
|
|
46517
|
-
return new Promise((
|
|
46744
|
+
return new Promise((resolve15, reject) => {
|
|
46518
46745
|
const dbg = process.env.VISOR_DEBUG === "true";
|
|
46519
46746
|
try {
|
|
46520
46747
|
if (dbg) {
|
|
@@ -46601,12 +46828,12 @@ async function interactivePrompt(options) {
|
|
|
46601
46828
|
};
|
|
46602
46829
|
const finish = (value) => {
|
|
46603
46830
|
cleanup();
|
|
46604
|
-
|
|
46831
|
+
resolve15(value);
|
|
46605
46832
|
};
|
|
46606
46833
|
if (options.timeout && options.timeout > 0) {
|
|
46607
46834
|
timeoutId = setTimeout(() => {
|
|
46608
46835
|
cleanup();
|
|
46609
|
-
if (defaultValue !== void 0) return
|
|
46836
|
+
if (defaultValue !== void 0) return resolve15(defaultValue);
|
|
46610
46837
|
return reject(new Error("Input timeout"));
|
|
46611
46838
|
}, options.timeout);
|
|
46612
46839
|
}
|
|
@@ -46738,7 +46965,7 @@ async function interactivePrompt(options) {
|
|
|
46738
46965
|
});
|
|
46739
46966
|
}
|
|
46740
46967
|
async function simplePrompt(prompt) {
|
|
46741
|
-
return new Promise((
|
|
46968
|
+
return new Promise((resolve15) => {
|
|
46742
46969
|
const rl = readline.createInterface({
|
|
46743
46970
|
input: process.stdin,
|
|
46744
46971
|
output: process.stdout
|
|
@@ -46754,7 +46981,7 @@ async function simplePrompt(prompt) {
|
|
|
46754
46981
|
rl.question(`${prompt}
|
|
46755
46982
|
> `, (answer) => {
|
|
46756
46983
|
rl.close();
|
|
46757
|
-
|
|
46984
|
+
resolve15(answer.trim());
|
|
46758
46985
|
});
|
|
46759
46986
|
});
|
|
46760
46987
|
}
|
|
@@ -46922,7 +47149,7 @@ function isStdinAvailable() {
|
|
|
46922
47149
|
return !process.stdin.isTTY;
|
|
46923
47150
|
}
|
|
46924
47151
|
async function readStdin(timeout, maxSize = 1024 * 1024) {
|
|
46925
|
-
return new Promise((
|
|
47152
|
+
return new Promise((resolve15, reject) => {
|
|
46926
47153
|
let data = "";
|
|
46927
47154
|
let timeoutId;
|
|
46928
47155
|
if (timeout) {
|
|
@@ -46949,7 +47176,7 @@ async function readStdin(timeout, maxSize = 1024 * 1024) {
|
|
|
46949
47176
|
};
|
|
46950
47177
|
const onEnd = () => {
|
|
46951
47178
|
cleanup();
|
|
46952
|
-
|
|
47179
|
+
resolve15(data.trim());
|
|
46953
47180
|
};
|
|
46954
47181
|
const onError = (err) => {
|
|
46955
47182
|
cleanup();
|
|
@@ -51668,23 +51895,23 @@ __export(renderer_schema_exports, {
|
|
|
51668
51895
|
});
|
|
51669
51896
|
async function loadRendererSchema(name) {
|
|
51670
51897
|
try {
|
|
51671
|
-
const
|
|
51672
|
-
const
|
|
51898
|
+
const fs25 = await import("fs/promises");
|
|
51899
|
+
const path29 = await import("path");
|
|
51673
51900
|
const sanitized = String(name).replace(/[^a-zA-Z0-9-]/g, "");
|
|
51674
51901
|
if (!sanitized) return void 0;
|
|
51675
51902
|
const candidates = [
|
|
51676
51903
|
// When bundled with ncc, __dirname is dist/ and output/ is at dist/output/
|
|
51677
|
-
|
|
51904
|
+
path29.join(__dirname, "output", sanitized, "schema.json"),
|
|
51678
51905
|
// When running from source, __dirname is src/state-machine/dispatch/ and output/ is at output/
|
|
51679
|
-
|
|
51906
|
+
path29.join(__dirname, "..", "..", "output", sanitized, "schema.json"),
|
|
51680
51907
|
// When running from a checkout with output/ folder copied to CWD
|
|
51681
|
-
|
|
51908
|
+
path29.join(process.cwd(), "output", sanitized, "schema.json"),
|
|
51682
51909
|
// Fallback: cwd/dist/output/
|
|
51683
|
-
|
|
51910
|
+
path29.join(process.cwd(), "dist", "output", sanitized, "schema.json")
|
|
51684
51911
|
];
|
|
51685
51912
|
for (const p of candidates) {
|
|
51686
51913
|
try {
|
|
51687
|
-
const raw = await
|
|
51914
|
+
const raw = await fs25.readFile(p, "utf-8");
|
|
51688
51915
|
return JSON.parse(raw);
|
|
51689
51916
|
} catch {
|
|
51690
51917
|
}
|
|
@@ -52371,11 +52598,12 @@ async function executeCheckWithForEachItems2(checkId, forEachParent, forEachItem
|
|
|
52371
52598
|
};
|
|
52372
52599
|
{
|
|
52373
52600
|
const assumeExpr = checkConfig?.assume;
|
|
52374
|
-
if (assumeExpr) {
|
|
52601
|
+
if (assumeExpr !== void 0 && assumeExpr !== null) {
|
|
52375
52602
|
let ok = true;
|
|
52376
52603
|
try {
|
|
52377
52604
|
const evaluator = new FailureConditionEvaluator();
|
|
52378
|
-
const
|
|
52605
|
+
const rawExprs = Array.isArray(assumeExpr) ? assumeExpr : [assumeExpr];
|
|
52606
|
+
const exprs = rawExprs.map((e) => typeof e === "string" ? e : String(e));
|
|
52379
52607
|
const conversation = context2.executionContext?.conversation || providerConfig?.eventContext?.conversation;
|
|
52380
52608
|
for (const ex of exprs) {
|
|
52381
52609
|
const res = await evaluator.evaluateIfCondition(checkId, ex, {
|
|
@@ -53443,11 +53671,12 @@ async function executeSingleCheck2(checkId, context2, state, emitEvent, transiti
|
|
|
53443
53671
|
};
|
|
53444
53672
|
{
|
|
53445
53673
|
const assumeExpr = checkConfig2?.assume;
|
|
53446
|
-
if (assumeExpr) {
|
|
53674
|
+
if (assumeExpr !== void 0 && assumeExpr !== null) {
|
|
53447
53675
|
let ok = true;
|
|
53448
53676
|
try {
|
|
53449
53677
|
const evaluator = new FailureConditionEvaluator();
|
|
53450
|
-
const
|
|
53678
|
+
const rawExprs = Array.isArray(assumeExpr) ? assumeExpr : [assumeExpr];
|
|
53679
|
+
const exprs = rawExprs.map((e) => typeof e === "string" ? e : String(e));
|
|
53451
53680
|
const conversation = context2.executionContext?.conversation || providerConfig?.eventContext?.conversation;
|
|
53452
53681
|
for (const ex of exprs) {
|
|
53453
53682
|
const res = await evaluator.evaluateIfCondition(checkId, ex, {
|
|
@@ -54134,8 +54363,8 @@ function updateStats2(results, state, isForEachIteration = false) {
|
|
|
54134
54363
|
async function renderTemplateContent2(checkId, checkConfig, reviewSummary) {
|
|
54135
54364
|
try {
|
|
54136
54365
|
const { createExtendedLiquid: createExtendedLiquid2 } = await Promise.resolve().then(() => (init_liquid_extensions(), liquid_extensions_exports));
|
|
54137
|
-
const
|
|
54138
|
-
const
|
|
54366
|
+
const fs25 = await import("fs/promises");
|
|
54367
|
+
const path29 = await import("path");
|
|
54139
54368
|
const schemaRaw = checkConfig.schema || "plain";
|
|
54140
54369
|
const schema = typeof schemaRaw === "string" && !schemaRaw.includes("{{") && !schemaRaw.includes("{%") ? schemaRaw : typeof schemaRaw === "object" ? "code-review" : "plain";
|
|
54141
54370
|
let templateContent;
|
|
@@ -54144,27 +54373,27 @@ async function renderTemplateContent2(checkId, checkConfig, reviewSummary) {
|
|
|
54144
54373
|
logger.debug(`[LevelDispatch] Using inline template for ${checkId}`);
|
|
54145
54374
|
} else if (checkConfig.template && checkConfig.template.file) {
|
|
54146
54375
|
const file = String(checkConfig.template.file);
|
|
54147
|
-
const resolved =
|
|
54148
|
-
templateContent = await
|
|
54376
|
+
const resolved = path29.resolve(process.cwd(), file);
|
|
54377
|
+
templateContent = await fs25.readFile(resolved, "utf-8");
|
|
54149
54378
|
logger.debug(`[LevelDispatch] Using template file for ${checkId}: ${resolved}`);
|
|
54150
54379
|
} else if (schema && schema !== "plain") {
|
|
54151
54380
|
const sanitized = String(schema).replace(/[^a-zA-Z0-9-]/g, "");
|
|
54152
54381
|
if (sanitized) {
|
|
54153
54382
|
const candidatePaths = [
|
|
54154
|
-
|
|
54383
|
+
path29.join(__dirname, "output", sanitized, "template.liquid"),
|
|
54155
54384
|
// bundled: dist/output/
|
|
54156
|
-
|
|
54385
|
+
path29.join(__dirname, "..", "..", "output", sanitized, "template.liquid"),
|
|
54157
54386
|
// source (from state-machine/states)
|
|
54158
|
-
|
|
54387
|
+
path29.join(__dirname, "..", "..", "..", "output", sanitized, "template.liquid"),
|
|
54159
54388
|
// source (alternate)
|
|
54160
|
-
|
|
54389
|
+
path29.join(process.cwd(), "output", sanitized, "template.liquid"),
|
|
54161
54390
|
// fallback: cwd/output/
|
|
54162
|
-
|
|
54391
|
+
path29.join(process.cwd(), "dist", "output", sanitized, "template.liquid")
|
|
54163
54392
|
// fallback: cwd/dist/output/
|
|
54164
54393
|
];
|
|
54165
54394
|
for (const p of candidatePaths) {
|
|
54166
54395
|
try {
|
|
54167
|
-
templateContent = await
|
|
54396
|
+
templateContent = await fs25.readFile(p, "utf-8");
|
|
54168
54397
|
if (templateContent) {
|
|
54169
54398
|
logger.debug(`[LevelDispatch] Using schema template for ${checkId}: ${p}`);
|
|
54170
54399
|
break;
|
|
@@ -56304,8 +56533,8 @@ var init_workspace_manager = __esm({
|
|
|
56304
56533
|
);
|
|
56305
56534
|
if (this.cleanupRequested && this.activeOperations === 0) {
|
|
56306
56535
|
logger.debug(`[Workspace] All references released, proceeding with deferred cleanup`);
|
|
56307
|
-
for (const
|
|
56308
|
-
|
|
56536
|
+
for (const resolve15 of this.cleanupResolvers) {
|
|
56537
|
+
resolve15();
|
|
56309
56538
|
}
|
|
56310
56539
|
this.cleanupResolvers = [];
|
|
56311
56540
|
}
|
|
@@ -56484,19 +56713,19 @@ var init_workspace_manager = __esm({
|
|
|
56484
56713
|
);
|
|
56485
56714
|
this.cleanupRequested = true;
|
|
56486
56715
|
await Promise.race([
|
|
56487
|
-
new Promise((
|
|
56716
|
+
new Promise((resolve15) => {
|
|
56488
56717
|
if (this.activeOperations === 0) {
|
|
56489
|
-
|
|
56718
|
+
resolve15();
|
|
56490
56719
|
} else {
|
|
56491
|
-
this.cleanupResolvers.push(
|
|
56720
|
+
this.cleanupResolvers.push(resolve15);
|
|
56492
56721
|
}
|
|
56493
56722
|
}),
|
|
56494
|
-
new Promise((
|
|
56723
|
+
new Promise((resolve15) => {
|
|
56495
56724
|
setTimeout(() => {
|
|
56496
56725
|
logger.warn(
|
|
56497
56726
|
`[Workspace] Cleanup timeout after ${timeout}ms, proceeding anyway (${this.activeOperations} operations still active)`
|
|
56498
56727
|
);
|
|
56499
|
-
|
|
56728
|
+
resolve15();
|
|
56500
56729
|
}, timeout);
|
|
56501
56730
|
})
|
|
56502
56731
|
]);
|
|
@@ -56911,8 +57140,8 @@ var init_fair_concurrency_limiter = __esm({
|
|
|
56911
57140
|
);
|
|
56912
57141
|
const queuedAt = Date.now();
|
|
56913
57142
|
const effectiveTimeout = queueTimeout ?? 12e4;
|
|
56914
|
-
return new Promise((
|
|
56915
|
-
const entry = { resolve:
|
|
57143
|
+
return new Promise((resolve15, reject) => {
|
|
57144
|
+
const entry = { resolve: resolve15, reject, queuedAt };
|
|
56916
57145
|
entry.reminder = setInterval(() => {
|
|
56917
57146
|
const waited = Math.round((Date.now() - queuedAt) / 1e3);
|
|
56918
57147
|
const curQueued = this._totalQueued();
|
|
@@ -57126,7 +57355,8 @@ function buildEngineContextForRun(workingDirectory, config, prInfo, debug, maxPa
|
|
|
57126
57355
|
sharedConcurrencyLimiter = {
|
|
57127
57356
|
async acquire(parentSessionId, _dbg, queueTimeout) {
|
|
57128
57357
|
const sid = parentSessionId || sessionId;
|
|
57129
|
-
|
|
57358
|
+
const effectiveQueueTimeout = queueTimeout ?? 0;
|
|
57359
|
+
return fairLimiter.acquire(sid, _dbg, effectiveQueueTimeout);
|
|
57130
57360
|
},
|
|
57131
57361
|
release(parentSessionId, _dbg) {
|
|
57132
57362
|
const sid = parentSessionId || sessionId;
|
|
@@ -57219,1380 +57449,6 @@ var init_build_engine_context = __esm({
|
|
|
57219
57449
|
}
|
|
57220
57450
|
});
|
|
57221
57451
|
|
|
57222
|
-
// src/policy/default-engine.ts
|
|
57223
|
-
var DefaultPolicyEngine;
|
|
57224
|
-
var init_default_engine = __esm({
|
|
57225
|
-
"src/policy/default-engine.ts"() {
|
|
57226
|
-
"use strict";
|
|
57227
|
-
DefaultPolicyEngine = class {
|
|
57228
|
-
async initialize(_config) {
|
|
57229
|
-
}
|
|
57230
|
-
async evaluateCheckExecution(_checkId, _checkConfig) {
|
|
57231
|
-
return { allowed: true };
|
|
57232
|
-
}
|
|
57233
|
-
async evaluateToolInvocation(_serverName, _methodName, _transport) {
|
|
57234
|
-
return { allowed: true };
|
|
57235
|
-
}
|
|
57236
|
-
async evaluateCapabilities(_checkId, _capabilities) {
|
|
57237
|
-
return { allowed: true };
|
|
57238
|
-
}
|
|
57239
|
-
async shutdown() {
|
|
57240
|
-
}
|
|
57241
|
-
};
|
|
57242
|
-
}
|
|
57243
|
-
});
|
|
57244
|
-
|
|
57245
|
-
// src/enterprise/license/validator.ts
|
|
57246
|
-
var validator_exports = {};
|
|
57247
|
-
__export(validator_exports, {
|
|
57248
|
-
LicenseValidator: () => LicenseValidator
|
|
57249
|
-
});
|
|
57250
|
-
var crypto3, fs21, path26, LicenseValidator;
|
|
57251
|
-
var init_validator = __esm({
|
|
57252
|
-
"src/enterprise/license/validator.ts"() {
|
|
57253
|
-
"use strict";
|
|
57254
|
-
crypto3 = __toESM(require("crypto"));
|
|
57255
|
-
fs21 = __toESM(require("fs"));
|
|
57256
|
-
path26 = __toESM(require("path"));
|
|
57257
|
-
LicenseValidator = class _LicenseValidator {
|
|
57258
|
-
/** Ed25519 public key for license verification (PEM format). */
|
|
57259
|
-
static PUBLIC_KEY = "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAI/Zd08EFmgIdrDm/HXd0l3/5GBt7R1PrdvhdmEXhJlU=\n-----END PUBLIC KEY-----\n";
|
|
57260
|
-
cache = null;
|
|
57261
|
-
static CACHE_TTL = 5 * 60 * 1e3;
|
|
57262
|
-
// 5 minutes
|
|
57263
|
-
static GRACE_PERIOD = 72 * 3600 * 1e3;
|
|
57264
|
-
// 72 hours after expiry
|
|
57265
|
-
/**
|
|
57266
|
-
* Load and validate license from environment or file.
|
|
57267
|
-
*
|
|
57268
|
-
* Resolution order:
|
|
57269
|
-
* 1. VISOR_LICENSE env var (JWT string)
|
|
57270
|
-
* 2. VISOR_LICENSE_FILE env var (path to file)
|
|
57271
|
-
* 3. .visor-license in project root (cwd)
|
|
57272
|
-
* 4. .visor-license in ~/.config/visor/
|
|
57273
|
-
*/
|
|
57274
|
-
async loadAndValidate() {
|
|
57275
|
-
if (this.cache && Date.now() - this.cache.validatedAt < _LicenseValidator.CACHE_TTL) {
|
|
57276
|
-
return this.cache.payload;
|
|
57277
|
-
}
|
|
57278
|
-
const token = this.resolveToken();
|
|
57279
|
-
if (!token) return null;
|
|
57280
|
-
const payload = this.verifyAndDecode(token);
|
|
57281
|
-
if (!payload) return null;
|
|
57282
|
-
this.cache = { payload, validatedAt: Date.now() };
|
|
57283
|
-
return payload;
|
|
57284
|
-
}
|
|
57285
|
-
/** Check if a specific feature is licensed */
|
|
57286
|
-
hasFeature(feature) {
|
|
57287
|
-
if (!this.cache) return false;
|
|
57288
|
-
return this.cache.payload.features.includes(feature);
|
|
57289
|
-
}
|
|
57290
|
-
/** Check if license is valid (with grace period) */
|
|
57291
|
-
isValid() {
|
|
57292
|
-
if (!this.cache) return false;
|
|
57293
|
-
const now = Date.now();
|
|
57294
|
-
const expiryMs = this.cache.payload.exp * 1e3;
|
|
57295
|
-
return now < expiryMs + _LicenseValidator.GRACE_PERIOD;
|
|
57296
|
-
}
|
|
57297
|
-
/** Check if the license is within its grace period (expired but still valid) */
|
|
57298
|
-
isInGracePeriod() {
|
|
57299
|
-
if (!this.cache) return false;
|
|
57300
|
-
const now = Date.now();
|
|
57301
|
-
const expiryMs = this.cache.payload.exp * 1e3;
|
|
57302
|
-
return now >= expiryMs && now < expiryMs + _LicenseValidator.GRACE_PERIOD;
|
|
57303
|
-
}
|
|
57304
|
-
resolveToken() {
|
|
57305
|
-
if (process.env.VISOR_LICENSE) {
|
|
57306
|
-
return process.env.VISOR_LICENSE.trim();
|
|
57307
|
-
}
|
|
57308
|
-
if (process.env.VISOR_LICENSE_FILE) {
|
|
57309
|
-
const resolved = path26.resolve(process.env.VISOR_LICENSE_FILE);
|
|
57310
|
-
const home2 = process.env.HOME || process.env.USERPROFILE || "";
|
|
57311
|
-
const allowedPrefixes = [path26.normalize(process.cwd())];
|
|
57312
|
-
if (home2) allowedPrefixes.push(path26.normalize(path26.join(home2, ".config", "visor")));
|
|
57313
|
-
let realPath;
|
|
57314
|
-
try {
|
|
57315
|
-
realPath = fs21.realpathSync(resolved);
|
|
57316
|
-
} catch {
|
|
57317
|
-
return null;
|
|
57318
|
-
}
|
|
57319
|
-
const isSafe = allowedPrefixes.some(
|
|
57320
|
-
(prefix) => realPath === prefix || realPath.startsWith(prefix + path26.sep)
|
|
57321
|
-
);
|
|
57322
|
-
if (!isSafe) return null;
|
|
57323
|
-
return this.readFile(realPath);
|
|
57324
|
-
}
|
|
57325
|
-
const cwdPath = path26.join(process.cwd(), ".visor-license");
|
|
57326
|
-
const cwdToken = this.readFile(cwdPath);
|
|
57327
|
-
if (cwdToken) return cwdToken;
|
|
57328
|
-
const home = process.env.HOME || process.env.USERPROFILE || "";
|
|
57329
|
-
if (home) {
|
|
57330
|
-
const configPath = path26.join(home, ".config", "visor", ".visor-license");
|
|
57331
|
-
const configToken = this.readFile(configPath);
|
|
57332
|
-
if (configToken) return configToken;
|
|
57333
|
-
}
|
|
57334
|
-
return null;
|
|
57335
|
-
}
|
|
57336
|
-
readFile(filePath) {
|
|
57337
|
-
try {
|
|
57338
|
-
return fs21.readFileSync(filePath, "utf-8").trim();
|
|
57339
|
-
} catch {
|
|
57340
|
-
return null;
|
|
57341
|
-
}
|
|
57342
|
-
}
|
|
57343
|
-
verifyAndDecode(token) {
|
|
57344
|
-
try {
|
|
57345
|
-
const parts = token.split(".");
|
|
57346
|
-
if (parts.length !== 3) return null;
|
|
57347
|
-
const [headerB64, payloadB64, signatureB64] = parts;
|
|
57348
|
-
const header = JSON.parse(Buffer.from(headerB64, "base64url").toString());
|
|
57349
|
-
if (header.alg !== "EdDSA") return null;
|
|
57350
|
-
const data = `${headerB64}.${payloadB64}`;
|
|
57351
|
-
const signature = Buffer.from(signatureB64, "base64url");
|
|
57352
|
-
const publicKey = crypto3.createPublicKey(_LicenseValidator.PUBLIC_KEY);
|
|
57353
|
-
if (publicKey.asymmetricKeyType !== "ed25519") {
|
|
57354
|
-
return null;
|
|
57355
|
-
}
|
|
57356
|
-
const isValid = crypto3.verify(null, Buffer.from(data), publicKey, signature);
|
|
57357
|
-
if (!isValid) return null;
|
|
57358
|
-
const payload = JSON.parse(Buffer.from(payloadB64, "base64url").toString());
|
|
57359
|
-
if (!payload.org || !Array.isArray(payload.features) || typeof payload.exp !== "number" || typeof payload.iat !== "number" || !payload.sub) {
|
|
57360
|
-
return null;
|
|
57361
|
-
}
|
|
57362
|
-
const now = Date.now();
|
|
57363
|
-
const expiryMs = payload.exp * 1e3;
|
|
57364
|
-
if (now >= expiryMs + _LicenseValidator.GRACE_PERIOD) {
|
|
57365
|
-
return null;
|
|
57366
|
-
}
|
|
57367
|
-
return payload;
|
|
57368
|
-
} catch {
|
|
57369
|
-
return null;
|
|
57370
|
-
}
|
|
57371
|
-
}
|
|
57372
|
-
};
|
|
57373
|
-
}
|
|
57374
|
-
});
|
|
57375
|
-
|
|
57376
|
-
// src/enterprise/policy/opa-compiler.ts
|
|
57377
|
-
var fs22, path27, os2, crypto4, import_child_process8, OpaCompiler;
|
|
57378
|
-
var init_opa_compiler = __esm({
|
|
57379
|
-
"src/enterprise/policy/opa-compiler.ts"() {
|
|
57380
|
-
"use strict";
|
|
57381
|
-
fs22 = __toESM(require("fs"));
|
|
57382
|
-
path27 = __toESM(require("path"));
|
|
57383
|
-
os2 = __toESM(require("os"));
|
|
57384
|
-
crypto4 = __toESM(require("crypto"));
|
|
57385
|
-
import_child_process8 = require("child_process");
|
|
57386
|
-
OpaCompiler = class _OpaCompiler {
|
|
57387
|
-
static CACHE_DIR = path27.join(os2.tmpdir(), "visor-opa-cache");
|
|
57388
|
-
/**
|
|
57389
|
-
* Resolve the input paths to WASM bytes.
|
|
57390
|
-
*
|
|
57391
|
-
* Strategy:
|
|
57392
|
-
* 1. If any path is a .wasm file, read it directly
|
|
57393
|
-
* 2. If a directory contains policy.wasm, read it
|
|
57394
|
-
* 3. Otherwise, collect all .rego files and auto-compile via `opa build`
|
|
57395
|
-
*/
|
|
57396
|
-
async resolveWasmBytes(paths) {
|
|
57397
|
-
const regoFiles = [];
|
|
57398
|
-
for (const p of paths) {
|
|
57399
|
-
const resolved = path27.resolve(p);
|
|
57400
|
-
if (path27.normalize(resolved).includes("..")) {
|
|
57401
|
-
throw new Error(`Policy path contains traversal sequences: ${p}`);
|
|
57402
|
-
}
|
|
57403
|
-
if (resolved.endsWith(".wasm") && fs22.existsSync(resolved)) {
|
|
57404
|
-
return fs22.readFileSync(resolved);
|
|
57405
|
-
}
|
|
57406
|
-
if (!fs22.existsSync(resolved)) continue;
|
|
57407
|
-
const stat2 = fs22.statSync(resolved);
|
|
57408
|
-
if (stat2.isDirectory()) {
|
|
57409
|
-
const wasmCandidate = path27.join(resolved, "policy.wasm");
|
|
57410
|
-
if (fs22.existsSync(wasmCandidate)) {
|
|
57411
|
-
return fs22.readFileSync(wasmCandidate);
|
|
57412
|
-
}
|
|
57413
|
-
const files = fs22.readdirSync(resolved);
|
|
57414
|
-
for (const f of files) {
|
|
57415
|
-
if (f.endsWith(".rego")) {
|
|
57416
|
-
regoFiles.push(path27.join(resolved, f));
|
|
57417
|
-
}
|
|
57418
|
-
}
|
|
57419
|
-
} else if (resolved.endsWith(".rego")) {
|
|
57420
|
-
regoFiles.push(resolved);
|
|
57421
|
-
}
|
|
57422
|
-
}
|
|
57423
|
-
if (regoFiles.length === 0) {
|
|
57424
|
-
throw new Error(
|
|
57425
|
-
`OPA WASM evaluator: no .wasm bundle or .rego files found in: ${paths.join(", ")}`
|
|
57426
|
-
);
|
|
57427
|
-
}
|
|
57428
|
-
return this.compileRego(regoFiles);
|
|
57429
|
-
}
|
|
57430
|
-
/**
|
|
57431
|
-
* Auto-compile .rego files to a WASM bundle using the `opa` CLI.
|
|
57432
|
-
*
|
|
57433
|
-
* Caches the compiled bundle based on a content hash of all input .rego files
|
|
57434
|
-
* so subsequent runs skip compilation if policies haven't changed.
|
|
57435
|
-
*/
|
|
57436
|
-
compileRego(regoFiles) {
|
|
57437
|
-
try {
|
|
57438
|
-
(0, import_child_process8.execFileSync)("opa", ["version"], { stdio: "pipe" });
|
|
57439
|
-
} catch {
|
|
57440
|
-
throw new Error(
|
|
57441
|
-
"OPA CLI (`opa`) not found on PATH. Install it from https://www.openpolicyagent.org/docs/latest/#running-opa\nOr pre-compile your .rego files: opa build -t wasm -e visor -o bundle.tar.gz " + regoFiles.join(" ")
|
|
57442
|
-
);
|
|
57443
|
-
}
|
|
57444
|
-
const hash = crypto4.createHash("sha256");
|
|
57445
|
-
for (const f of regoFiles.sort()) {
|
|
57446
|
-
hash.update(fs22.readFileSync(f));
|
|
57447
|
-
hash.update(f);
|
|
57448
|
-
}
|
|
57449
|
-
const cacheKey = hash.digest("hex").slice(0, 16);
|
|
57450
|
-
const cacheDir = _OpaCompiler.CACHE_DIR;
|
|
57451
|
-
const cachedWasm = path27.join(cacheDir, `${cacheKey}.wasm`);
|
|
57452
|
-
if (fs22.existsSync(cachedWasm)) {
|
|
57453
|
-
return fs22.readFileSync(cachedWasm);
|
|
57454
|
-
}
|
|
57455
|
-
fs22.mkdirSync(cacheDir, { recursive: true });
|
|
57456
|
-
const bundleTar = path27.join(cacheDir, `${cacheKey}-bundle.tar.gz`);
|
|
57457
|
-
try {
|
|
57458
|
-
const args = [
|
|
57459
|
-
"build",
|
|
57460
|
-
"-t",
|
|
57461
|
-
"wasm",
|
|
57462
|
-
"-e",
|
|
57463
|
-
"visor",
|
|
57464
|
-
// entrypoint: the visor package tree
|
|
57465
|
-
"-o",
|
|
57466
|
-
bundleTar,
|
|
57467
|
-
...regoFiles
|
|
57468
|
-
];
|
|
57469
|
-
(0, import_child_process8.execFileSync)("opa", args, {
|
|
57470
|
-
stdio: "pipe",
|
|
57471
|
-
timeout: 3e4
|
|
57472
|
-
});
|
|
57473
|
-
} catch (err) {
|
|
57474
|
-
const stderr = err?.stderr?.toString() || "";
|
|
57475
|
-
throw new Error(
|
|
57476
|
-
`Failed to compile .rego files to WASM:
|
|
57477
|
-
${stderr}
|
|
57478
|
-
Ensure your .rego files are valid and the \`opa\` CLI is installed.`
|
|
57479
|
-
);
|
|
57480
|
-
}
|
|
57481
|
-
try {
|
|
57482
|
-
(0, import_child_process8.execFileSync)("tar", ["-xzf", bundleTar, "-C", cacheDir, "/policy.wasm"], {
|
|
57483
|
-
stdio: "pipe"
|
|
57484
|
-
});
|
|
57485
|
-
const extractedWasm = path27.join(cacheDir, "policy.wasm");
|
|
57486
|
-
if (fs22.existsSync(extractedWasm)) {
|
|
57487
|
-
fs22.renameSync(extractedWasm, cachedWasm);
|
|
57488
|
-
}
|
|
57489
|
-
} catch {
|
|
57490
|
-
try {
|
|
57491
|
-
(0, import_child_process8.execFileSync)("tar", ["-xzf", bundleTar, "-C", cacheDir, "policy.wasm"], {
|
|
57492
|
-
stdio: "pipe"
|
|
57493
|
-
});
|
|
57494
|
-
const extractedWasm = path27.join(cacheDir, "policy.wasm");
|
|
57495
|
-
if (fs22.existsSync(extractedWasm)) {
|
|
57496
|
-
fs22.renameSync(extractedWasm, cachedWasm);
|
|
57497
|
-
}
|
|
57498
|
-
} catch (err2) {
|
|
57499
|
-
throw new Error(`Failed to extract policy.wasm from OPA bundle: ${err2?.message || err2}`);
|
|
57500
|
-
}
|
|
57501
|
-
}
|
|
57502
|
-
try {
|
|
57503
|
-
fs22.unlinkSync(bundleTar);
|
|
57504
|
-
} catch {
|
|
57505
|
-
}
|
|
57506
|
-
if (!fs22.existsSync(cachedWasm)) {
|
|
57507
|
-
throw new Error("OPA build succeeded but policy.wasm was not found in the bundle");
|
|
57508
|
-
}
|
|
57509
|
-
return fs22.readFileSync(cachedWasm);
|
|
57510
|
-
}
|
|
57511
|
-
};
|
|
57512
|
-
}
|
|
57513
|
-
});
|
|
57514
|
-
|
|
57515
|
-
// src/enterprise/policy/opa-wasm-evaluator.ts
|
|
57516
|
-
var fs23, path28, OpaWasmEvaluator;
|
|
57517
|
-
var init_opa_wasm_evaluator = __esm({
|
|
57518
|
-
"src/enterprise/policy/opa-wasm-evaluator.ts"() {
|
|
57519
|
-
"use strict";
|
|
57520
|
-
fs23 = __toESM(require("fs"));
|
|
57521
|
-
path28 = __toESM(require("path"));
|
|
57522
|
-
init_opa_compiler();
|
|
57523
|
-
OpaWasmEvaluator = class {
|
|
57524
|
-
policy = null;
|
|
57525
|
-
dataDocument = {};
|
|
57526
|
-
compiler = new OpaCompiler();
|
|
57527
|
-
async initialize(rulesPath) {
|
|
57528
|
-
const paths = Array.isArray(rulesPath) ? rulesPath : [rulesPath];
|
|
57529
|
-
const wasmBytes = await this.compiler.resolveWasmBytes(paths);
|
|
57530
|
-
try {
|
|
57531
|
-
const { createRequire } = require("module");
|
|
57532
|
-
const runtimeRequire = createRequire(__filename);
|
|
57533
|
-
const opaWasm = runtimeRequire("@open-policy-agent/opa-wasm");
|
|
57534
|
-
const loadPolicy = opaWasm.loadPolicy || opaWasm.default?.loadPolicy;
|
|
57535
|
-
if (!loadPolicy) {
|
|
57536
|
-
throw new Error("loadPolicy not found in @open-policy-agent/opa-wasm");
|
|
57537
|
-
}
|
|
57538
|
-
this.policy = await loadPolicy(wasmBytes);
|
|
57539
|
-
} catch (err) {
|
|
57540
|
-
if (err?.code === "MODULE_NOT_FOUND" || err?.code === "ERR_MODULE_NOT_FOUND") {
|
|
57541
|
-
throw new Error(
|
|
57542
|
-
"OPA WASM evaluator requires @open-policy-agent/opa-wasm. Install it with: npm install @open-policy-agent/opa-wasm"
|
|
57543
|
-
);
|
|
57544
|
-
}
|
|
57545
|
-
throw err;
|
|
57546
|
-
}
|
|
57547
|
-
}
|
|
57548
|
-
/**
|
|
57549
|
-
* Load external data from a JSON file to use as the OPA data document.
|
|
57550
|
-
* The loaded data will be passed to `policy.setData()` during evaluation,
|
|
57551
|
-
* making it available in Rego via `data.<key>`.
|
|
57552
|
-
*/
|
|
57553
|
-
loadData(dataPath) {
|
|
57554
|
-
const resolved = path28.resolve(dataPath);
|
|
57555
|
-
if (path28.normalize(resolved).includes("..")) {
|
|
57556
|
-
throw new Error(`Data path contains traversal sequences: ${dataPath}`);
|
|
57557
|
-
}
|
|
57558
|
-
if (!fs23.existsSync(resolved)) {
|
|
57559
|
-
throw new Error(`OPA data file not found: ${resolved}`);
|
|
57560
|
-
}
|
|
57561
|
-
const stat2 = fs23.statSync(resolved);
|
|
57562
|
-
if (stat2.size > 10 * 1024 * 1024) {
|
|
57563
|
-
throw new Error(`OPA data file exceeds 10MB limit: ${resolved} (${stat2.size} bytes)`);
|
|
57564
|
-
}
|
|
57565
|
-
const raw = fs23.readFileSync(resolved, "utf-8");
|
|
57566
|
-
try {
|
|
57567
|
-
const parsed = JSON.parse(raw);
|
|
57568
|
-
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
57569
|
-
throw new Error("OPA data file must contain a JSON object (not an array or primitive)");
|
|
57570
|
-
}
|
|
57571
|
-
this.dataDocument = parsed;
|
|
57572
|
-
} catch (err) {
|
|
57573
|
-
if (err.message.startsWith("OPA data file must")) {
|
|
57574
|
-
throw err;
|
|
57575
|
-
}
|
|
57576
|
-
throw new Error(`Failed to parse OPA data file ${resolved}: ${err.message}`);
|
|
57577
|
-
}
|
|
57578
|
-
}
|
|
57579
|
-
async evaluate(input) {
|
|
57580
|
-
if (!this.policy) {
|
|
57581
|
-
throw new Error("OPA WASM evaluator not initialized");
|
|
57582
|
-
}
|
|
57583
|
-
this.policy.setData(this.dataDocument);
|
|
57584
|
-
const resultSet = this.policy.evaluate(input);
|
|
57585
|
-
if (Array.isArray(resultSet) && resultSet.length > 0) {
|
|
57586
|
-
return resultSet[0].result;
|
|
57587
|
-
}
|
|
57588
|
-
return void 0;
|
|
57589
|
-
}
|
|
57590
|
-
async shutdown() {
|
|
57591
|
-
if (this.policy) {
|
|
57592
|
-
if (typeof this.policy.close === "function") {
|
|
57593
|
-
try {
|
|
57594
|
-
this.policy.close();
|
|
57595
|
-
} catch {
|
|
57596
|
-
}
|
|
57597
|
-
} else if (typeof this.policy.free === "function") {
|
|
57598
|
-
try {
|
|
57599
|
-
this.policy.free();
|
|
57600
|
-
} catch {
|
|
57601
|
-
}
|
|
57602
|
-
}
|
|
57603
|
-
}
|
|
57604
|
-
this.policy = null;
|
|
57605
|
-
}
|
|
57606
|
-
};
|
|
57607
|
-
}
|
|
57608
|
-
});
|
|
57609
|
-
|
|
57610
|
-
// src/enterprise/policy/opa-http-evaluator.ts
|
|
57611
|
-
var OpaHttpEvaluator;
|
|
57612
|
-
var init_opa_http_evaluator = __esm({
|
|
57613
|
-
"src/enterprise/policy/opa-http-evaluator.ts"() {
|
|
57614
|
-
"use strict";
|
|
57615
|
-
OpaHttpEvaluator = class {
|
|
57616
|
-
baseUrl;
|
|
57617
|
-
timeout;
|
|
57618
|
-
constructor(baseUrl, timeout = 5e3) {
|
|
57619
|
-
let parsed;
|
|
57620
|
-
try {
|
|
57621
|
-
parsed = new URL(baseUrl);
|
|
57622
|
-
} catch {
|
|
57623
|
-
throw new Error(`OPA HTTP evaluator: invalid URL: ${baseUrl}`);
|
|
57624
|
-
}
|
|
57625
|
-
if (!["http:", "https:"].includes(parsed.protocol)) {
|
|
57626
|
-
throw new Error(
|
|
57627
|
-
`OPA HTTP evaluator: url must use http:// or https:// protocol, got: ${baseUrl}`
|
|
57628
|
-
);
|
|
57629
|
-
}
|
|
57630
|
-
const hostname = parsed.hostname;
|
|
57631
|
-
if (this.isBlockedHostname(hostname)) {
|
|
57632
|
-
throw new Error(
|
|
57633
|
-
`OPA HTTP evaluator: url must not point to internal, loopback, or private network addresses`
|
|
57634
|
-
);
|
|
57635
|
-
}
|
|
57636
|
-
this.baseUrl = baseUrl.replace(/\/+$/, "");
|
|
57637
|
-
this.timeout = timeout;
|
|
57638
|
-
}
|
|
57639
|
-
/**
|
|
57640
|
-
* Check if a hostname is blocked due to SSRF concerns.
|
|
57641
|
-
*
|
|
57642
|
-
* Blocks:
|
|
57643
|
-
* - Loopback addresses (127.x.x.x, localhost, 0.0.0.0, ::1)
|
|
57644
|
-
* - Link-local addresses (169.254.x.x)
|
|
57645
|
-
* - Private networks (10.x.x.x, 172.16-31.x.x, 192.168.x.x)
|
|
57646
|
-
* - IPv6 unique local addresses (fd00::/8)
|
|
57647
|
-
* - Cloud metadata services (*.internal)
|
|
57648
|
-
*/
|
|
57649
|
-
isBlockedHostname(hostname) {
|
|
57650
|
-
if (!hostname) return true;
|
|
57651
|
-
const normalized = hostname.toLowerCase().replace(/^\[|\]$/g, "");
|
|
57652
|
-
if (normalized === "metadata.google.internal" || normalized.endsWith(".internal")) {
|
|
57653
|
-
return true;
|
|
57654
|
-
}
|
|
57655
|
-
if (normalized === "localhost" || normalized === "localhost.localdomain") {
|
|
57656
|
-
return true;
|
|
57657
|
-
}
|
|
57658
|
-
if (normalized === "::1" || normalized === "0:0:0:0:0:0:0:1") {
|
|
57659
|
-
return true;
|
|
57660
|
-
}
|
|
57661
|
-
const ipv4Pattern = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/;
|
|
57662
|
-
const ipv4Match = normalized.match(ipv4Pattern);
|
|
57663
|
-
if (ipv4Match) {
|
|
57664
|
-
const octets = ipv4Match.slice(1, 5).map(Number);
|
|
57665
|
-
if (octets.some((octet) => octet > 255)) {
|
|
57666
|
-
return false;
|
|
57667
|
-
}
|
|
57668
|
-
const [a, b] = octets;
|
|
57669
|
-
if (a === 127) {
|
|
57670
|
-
return true;
|
|
57671
|
-
}
|
|
57672
|
-
if (a === 0) {
|
|
57673
|
-
return true;
|
|
57674
|
-
}
|
|
57675
|
-
if (a === 169 && b === 254) {
|
|
57676
|
-
return true;
|
|
57677
|
-
}
|
|
57678
|
-
if (a === 10) {
|
|
57679
|
-
return true;
|
|
57680
|
-
}
|
|
57681
|
-
if (a === 172 && b >= 16 && b <= 31) {
|
|
57682
|
-
return true;
|
|
57683
|
-
}
|
|
57684
|
-
if (a === 192 && b === 168) {
|
|
57685
|
-
return true;
|
|
57686
|
-
}
|
|
57687
|
-
}
|
|
57688
|
-
if (normalized.startsWith("fd") || normalized.startsWith("fc")) {
|
|
57689
|
-
return true;
|
|
57690
|
-
}
|
|
57691
|
-
if (normalized.startsWith("fe80:")) {
|
|
57692
|
-
return true;
|
|
57693
|
-
}
|
|
57694
|
-
return false;
|
|
57695
|
-
}
|
|
57696
|
-
/**
|
|
57697
|
-
* Evaluate a policy rule against an input document via OPA REST API.
|
|
57698
|
-
*
|
|
57699
|
-
* @param input - The input document to evaluate
|
|
57700
|
-
* @param rulePath - OPA rule path (e.g., 'visor/check/execute')
|
|
57701
|
-
* @returns The result object from OPA, or undefined on error
|
|
57702
|
-
*/
|
|
57703
|
-
async evaluate(input, rulePath) {
|
|
57704
|
-
const encodedPath = rulePath.split("/").map((s) => encodeURIComponent(s)).join("/");
|
|
57705
|
-
const url = `${this.baseUrl}/v1/data/${encodedPath}`;
|
|
57706
|
-
const controller = new AbortController();
|
|
57707
|
-
const timer = setTimeout(() => controller.abort(), this.timeout);
|
|
57708
|
-
try {
|
|
57709
|
-
const response = await fetch(url, {
|
|
57710
|
-
method: "POST",
|
|
57711
|
-
headers: { "Content-Type": "application/json" },
|
|
57712
|
-
body: JSON.stringify({ input }),
|
|
57713
|
-
signal: controller.signal
|
|
57714
|
-
});
|
|
57715
|
-
if (!response.ok) {
|
|
57716
|
-
throw new Error(`OPA HTTP ${response.status}: ${response.statusText}`);
|
|
57717
|
-
}
|
|
57718
|
-
let body;
|
|
57719
|
-
try {
|
|
57720
|
-
body = await response.json();
|
|
57721
|
-
} catch (jsonErr) {
|
|
57722
|
-
throw new Error(
|
|
57723
|
-
`OPA HTTP evaluator: failed to parse JSON response: ${jsonErr instanceof Error ? jsonErr.message : String(jsonErr)}`
|
|
57724
|
-
);
|
|
57725
|
-
}
|
|
57726
|
-
return body?.result;
|
|
57727
|
-
} finally {
|
|
57728
|
-
clearTimeout(timer);
|
|
57729
|
-
}
|
|
57730
|
-
}
|
|
57731
|
-
async shutdown() {
|
|
57732
|
-
}
|
|
57733
|
-
};
|
|
57734
|
-
}
|
|
57735
|
-
});
|
|
57736
|
-
|
|
57737
|
-
// src/enterprise/policy/policy-input-builder.ts
|
|
57738
|
-
var PolicyInputBuilder;
|
|
57739
|
-
var init_policy_input_builder = __esm({
|
|
57740
|
-
"src/enterprise/policy/policy-input-builder.ts"() {
|
|
57741
|
-
"use strict";
|
|
57742
|
-
PolicyInputBuilder = class {
|
|
57743
|
-
roles;
|
|
57744
|
-
actor;
|
|
57745
|
-
repository;
|
|
57746
|
-
pullRequest;
|
|
57747
|
-
constructor(policyConfig, actor, repository, pullRequest) {
|
|
57748
|
-
this.roles = policyConfig.roles || {};
|
|
57749
|
-
this.actor = actor;
|
|
57750
|
-
this.repository = repository;
|
|
57751
|
-
this.pullRequest = pullRequest;
|
|
57752
|
-
}
|
|
57753
|
-
/** Resolve which roles apply to the current actor. */
|
|
57754
|
-
resolveRoles() {
|
|
57755
|
-
const matched = [];
|
|
57756
|
-
for (const [roleName, roleConfig] of Object.entries(this.roles)) {
|
|
57757
|
-
let identityMatch = false;
|
|
57758
|
-
if (roleConfig.author_association && this.actor.authorAssociation && roleConfig.author_association.includes(this.actor.authorAssociation)) {
|
|
57759
|
-
identityMatch = true;
|
|
57760
|
-
}
|
|
57761
|
-
if (!identityMatch && roleConfig.users && this.actor.login && roleConfig.users.includes(this.actor.login)) {
|
|
57762
|
-
identityMatch = true;
|
|
57763
|
-
}
|
|
57764
|
-
if (!identityMatch && roleConfig.slack_users && this.actor.slack?.userId && roleConfig.slack_users.includes(this.actor.slack.userId)) {
|
|
57765
|
-
identityMatch = true;
|
|
57766
|
-
}
|
|
57767
|
-
if (!identityMatch && roleConfig.emails && this.actor.slack?.email) {
|
|
57768
|
-
const actorEmail = this.actor.slack.email.toLowerCase();
|
|
57769
|
-
if (roleConfig.emails.some((e) => e.toLowerCase() === actorEmail)) {
|
|
57770
|
-
identityMatch = true;
|
|
57771
|
-
}
|
|
57772
|
-
}
|
|
57773
|
-
if (!identityMatch) continue;
|
|
57774
|
-
if (roleConfig.slack_channels && roleConfig.slack_channels.length > 0) {
|
|
57775
|
-
if (!this.actor.slack?.channelId || !roleConfig.slack_channels.includes(this.actor.slack.channelId)) {
|
|
57776
|
-
continue;
|
|
57777
|
-
}
|
|
57778
|
-
}
|
|
57779
|
-
matched.push(roleName);
|
|
57780
|
-
}
|
|
57781
|
-
return matched;
|
|
57782
|
-
}
|
|
57783
|
-
buildActor() {
|
|
57784
|
-
return {
|
|
57785
|
-
authorAssociation: this.actor.authorAssociation,
|
|
57786
|
-
login: this.actor.login,
|
|
57787
|
-
roles: this.resolveRoles(),
|
|
57788
|
-
isLocalMode: this.actor.isLocalMode,
|
|
57789
|
-
...this.actor.slack && { slack: this.actor.slack }
|
|
57790
|
-
};
|
|
57791
|
-
}
|
|
57792
|
-
forCheckExecution(check) {
|
|
57793
|
-
return {
|
|
57794
|
-
scope: "check.execute",
|
|
57795
|
-
check: {
|
|
57796
|
-
id: check.id,
|
|
57797
|
-
type: check.type,
|
|
57798
|
-
group: check.group,
|
|
57799
|
-
tags: check.tags,
|
|
57800
|
-
criticality: check.criticality,
|
|
57801
|
-
sandbox: check.sandbox,
|
|
57802
|
-
policy: check.policy
|
|
57803
|
-
},
|
|
57804
|
-
actor: this.buildActor(),
|
|
57805
|
-
repository: this.repository,
|
|
57806
|
-
pullRequest: this.pullRequest
|
|
57807
|
-
};
|
|
57808
|
-
}
|
|
57809
|
-
forToolInvocation(serverName, methodName, transport) {
|
|
57810
|
-
return {
|
|
57811
|
-
scope: "tool.invoke",
|
|
57812
|
-
tool: { serverName, methodName, transport },
|
|
57813
|
-
actor: this.buildActor(),
|
|
57814
|
-
repository: this.repository,
|
|
57815
|
-
pullRequest: this.pullRequest
|
|
57816
|
-
};
|
|
57817
|
-
}
|
|
57818
|
-
forCapabilityResolve(checkId, capabilities) {
|
|
57819
|
-
return {
|
|
57820
|
-
scope: "capability.resolve",
|
|
57821
|
-
check: { id: checkId, type: "ai" },
|
|
57822
|
-
capability: capabilities,
|
|
57823
|
-
actor: this.buildActor(),
|
|
57824
|
-
repository: this.repository,
|
|
57825
|
-
pullRequest: this.pullRequest
|
|
57826
|
-
};
|
|
57827
|
-
}
|
|
57828
|
-
};
|
|
57829
|
-
}
|
|
57830
|
-
});
|
|
57831
|
-
|
|
57832
|
-
// src/enterprise/policy/opa-policy-engine.ts
|
|
57833
|
-
var opa_policy_engine_exports = {};
|
|
57834
|
-
__export(opa_policy_engine_exports, {
|
|
57835
|
-
OpaPolicyEngine: () => OpaPolicyEngine
|
|
57836
|
-
});
|
|
57837
|
-
var OpaPolicyEngine;
|
|
57838
|
-
var init_opa_policy_engine = __esm({
|
|
57839
|
-
"src/enterprise/policy/opa-policy-engine.ts"() {
|
|
57840
|
-
"use strict";
|
|
57841
|
-
init_opa_wasm_evaluator();
|
|
57842
|
-
init_opa_http_evaluator();
|
|
57843
|
-
init_policy_input_builder();
|
|
57844
|
-
OpaPolicyEngine = class {
|
|
57845
|
-
evaluator = null;
|
|
57846
|
-
fallback;
|
|
57847
|
-
timeout;
|
|
57848
|
-
config;
|
|
57849
|
-
inputBuilder = null;
|
|
57850
|
-
logger = null;
|
|
57851
|
-
constructor(config) {
|
|
57852
|
-
this.config = config;
|
|
57853
|
-
this.fallback = config.fallback || "deny";
|
|
57854
|
-
this.timeout = config.timeout || 5e3;
|
|
57855
|
-
}
|
|
57856
|
-
async initialize(config) {
|
|
57857
|
-
try {
|
|
57858
|
-
this.logger = (init_logger(), __toCommonJS(logger_exports)).logger;
|
|
57859
|
-
} catch {
|
|
57860
|
-
}
|
|
57861
|
-
const actor = {
|
|
57862
|
-
authorAssociation: process.env.VISOR_AUTHOR_ASSOCIATION,
|
|
57863
|
-
login: process.env.VISOR_AUTHOR_LOGIN || process.env.GITHUB_ACTOR,
|
|
57864
|
-
isLocalMode: !process.env.GITHUB_ACTIONS
|
|
57865
|
-
};
|
|
57866
|
-
const repo = {
|
|
57867
|
-
owner: process.env.GITHUB_REPOSITORY_OWNER,
|
|
57868
|
-
name: process.env.GITHUB_REPOSITORY?.split("/")[1],
|
|
57869
|
-
branch: process.env.GITHUB_HEAD_REF,
|
|
57870
|
-
baseBranch: process.env.GITHUB_BASE_REF,
|
|
57871
|
-
event: process.env.GITHUB_EVENT_NAME
|
|
57872
|
-
};
|
|
57873
|
-
const prNum = process.env.GITHUB_PR_NUMBER ? parseInt(process.env.GITHUB_PR_NUMBER, 10) : void 0;
|
|
57874
|
-
const pullRequest = {
|
|
57875
|
-
number: prNum !== void 0 && Number.isFinite(prNum) ? prNum : void 0
|
|
57876
|
-
};
|
|
57877
|
-
this.inputBuilder = new PolicyInputBuilder(config, actor, repo, pullRequest);
|
|
57878
|
-
if (config.engine === "local") {
|
|
57879
|
-
if (!config.rules) {
|
|
57880
|
-
throw new Error("OPA local mode requires `policy.rules` path to .wasm or .rego files");
|
|
57881
|
-
}
|
|
57882
|
-
const wasm = new OpaWasmEvaluator();
|
|
57883
|
-
await wasm.initialize(config.rules);
|
|
57884
|
-
if (config.data) {
|
|
57885
|
-
wasm.loadData(config.data);
|
|
57886
|
-
}
|
|
57887
|
-
this.evaluator = wasm;
|
|
57888
|
-
} else if (config.engine === "remote") {
|
|
57889
|
-
if (!config.url) {
|
|
57890
|
-
throw new Error("OPA remote mode requires `policy.url` pointing to OPA server");
|
|
57891
|
-
}
|
|
57892
|
-
this.evaluator = new OpaHttpEvaluator(config.url, this.timeout);
|
|
57893
|
-
} else {
|
|
57894
|
-
this.evaluator = null;
|
|
57895
|
-
}
|
|
57896
|
-
}
|
|
57897
|
-
/**
|
|
57898
|
-
* Update actor/repo/PR context (e.g., after PR info becomes available).
|
|
57899
|
-
* Called by the enterprise loader when engine context is enriched.
|
|
57900
|
-
*/
|
|
57901
|
-
setActorContext(actor, repo, pullRequest) {
|
|
57902
|
-
this.inputBuilder = new PolicyInputBuilder(this.config, actor, repo, pullRequest);
|
|
57903
|
-
}
|
|
57904
|
-
async evaluateCheckExecution(checkId, checkConfig) {
|
|
57905
|
-
if (!this.evaluator || !this.inputBuilder) return { allowed: true };
|
|
57906
|
-
const cfg = checkConfig && typeof checkConfig === "object" ? checkConfig : {};
|
|
57907
|
-
const policyOverride = cfg.policy;
|
|
57908
|
-
const input = this.inputBuilder.forCheckExecution({
|
|
57909
|
-
id: checkId,
|
|
57910
|
-
type: cfg.type || "ai",
|
|
57911
|
-
group: cfg.group,
|
|
57912
|
-
tags: cfg.tags,
|
|
57913
|
-
criticality: cfg.criticality,
|
|
57914
|
-
sandbox: cfg.sandbox,
|
|
57915
|
-
policy: policyOverride
|
|
57916
|
-
});
|
|
57917
|
-
return this.doEvaluate(input, this.resolveRulePath("check.execute", policyOverride?.rule));
|
|
57918
|
-
}
|
|
57919
|
-
async evaluateToolInvocation(serverName, methodName, transport) {
|
|
57920
|
-
if (!this.evaluator || !this.inputBuilder) return { allowed: true };
|
|
57921
|
-
const input = this.inputBuilder.forToolInvocation(serverName, methodName, transport);
|
|
57922
|
-
return this.doEvaluate(input, "visor/tool/invoke");
|
|
57923
|
-
}
|
|
57924
|
-
async evaluateCapabilities(checkId, capabilities) {
|
|
57925
|
-
if (!this.evaluator || !this.inputBuilder) return { allowed: true };
|
|
57926
|
-
const input = this.inputBuilder.forCapabilityResolve(checkId, capabilities);
|
|
57927
|
-
return this.doEvaluate(input, "visor/capability/resolve");
|
|
57928
|
-
}
|
|
57929
|
-
async shutdown() {
|
|
57930
|
-
if (this.evaluator && "shutdown" in this.evaluator) {
|
|
57931
|
-
await this.evaluator.shutdown();
|
|
57932
|
-
}
|
|
57933
|
-
this.evaluator = null;
|
|
57934
|
-
this.inputBuilder = null;
|
|
57935
|
-
}
|
|
57936
|
-
resolveRulePath(defaultScope, override) {
|
|
57937
|
-
if (override) {
|
|
57938
|
-
return override.startsWith("visor/") ? override : `visor/${override}`;
|
|
57939
|
-
}
|
|
57940
|
-
return `visor/${defaultScope.replace(/\./g, "/")}`;
|
|
57941
|
-
}
|
|
57942
|
-
async doEvaluate(input, rulePath) {
|
|
57943
|
-
try {
|
|
57944
|
-
this.logger?.debug(`[PolicyEngine] Evaluating ${rulePath}`, JSON.stringify(input));
|
|
57945
|
-
let timer;
|
|
57946
|
-
const timeoutPromise = new Promise((_resolve, reject) => {
|
|
57947
|
-
timer = setTimeout(() => reject(new Error("policy evaluation timeout")), this.timeout);
|
|
57948
|
-
});
|
|
57949
|
-
try {
|
|
57950
|
-
const result = await Promise.race([this.rawEvaluate(input, rulePath), timeoutPromise]);
|
|
57951
|
-
const decision = this.parseDecision(result);
|
|
57952
|
-
if (!decision.allowed && this.fallback === "warn") {
|
|
57953
|
-
decision.allowed = true;
|
|
57954
|
-
decision.warn = true;
|
|
57955
|
-
decision.reason = `audit: ${decision.reason || "policy denied"}`;
|
|
57956
|
-
}
|
|
57957
|
-
this.logger?.debug(
|
|
57958
|
-
`[PolicyEngine] Decision for ${rulePath}: allowed=${decision.allowed}, warn=${decision.warn || false}, reason=${decision.reason || "none"}`
|
|
57959
|
-
);
|
|
57960
|
-
return decision;
|
|
57961
|
-
} finally {
|
|
57962
|
-
if (timer) clearTimeout(timer);
|
|
57963
|
-
}
|
|
57964
|
-
} catch (err) {
|
|
57965
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
57966
|
-
this.logger?.warn(`[PolicyEngine] Evaluation failed for ${rulePath}: ${msg}`);
|
|
57967
|
-
return {
|
|
57968
|
-
allowed: this.fallback === "allow" || this.fallback === "warn",
|
|
57969
|
-
warn: this.fallback === "warn" ? true : void 0,
|
|
57970
|
-
reason: `policy evaluation failed, fallback=${this.fallback}`
|
|
57971
|
-
};
|
|
57972
|
-
}
|
|
57973
|
-
}
|
|
57974
|
-
async rawEvaluate(input, rulePath) {
|
|
57975
|
-
if (this.evaluator instanceof OpaWasmEvaluator) {
|
|
57976
|
-
const result = await this.evaluator.evaluate(input);
|
|
57977
|
-
return this.navigateWasmResult(result, rulePath);
|
|
57978
|
-
}
|
|
57979
|
-
return this.evaluator.evaluate(input, rulePath);
|
|
57980
|
-
}
|
|
57981
|
-
/**
|
|
57982
|
-
* Navigate nested OPA WASM result tree to reach the specific rule's output.
|
|
57983
|
-
* The WASM entrypoint `-e visor` means the result root IS the visor package,
|
|
57984
|
-
* so we strip the `visor/` prefix and walk the remaining segments.
|
|
57985
|
-
*/
|
|
57986
|
-
navigateWasmResult(result, rulePath) {
|
|
57987
|
-
if (!result || typeof result !== "object") return result;
|
|
57988
|
-
const segments = rulePath.replace(/^visor\//, "").split("/");
|
|
57989
|
-
let current = result;
|
|
57990
|
-
for (const seg of segments) {
|
|
57991
|
-
if (current && typeof current === "object" && seg in current) {
|
|
57992
|
-
current = current[seg];
|
|
57993
|
-
} else {
|
|
57994
|
-
return void 0;
|
|
57995
|
-
}
|
|
57996
|
-
}
|
|
57997
|
-
return current;
|
|
57998
|
-
}
|
|
57999
|
-
parseDecision(result) {
|
|
58000
|
-
if (result === void 0 || result === null) {
|
|
58001
|
-
return {
|
|
58002
|
-
allowed: this.fallback === "allow" || this.fallback === "warn",
|
|
58003
|
-
warn: this.fallback === "warn" ? true : void 0,
|
|
58004
|
-
reason: this.fallback === "warn" ? "audit: no policy result" : "no policy result"
|
|
58005
|
-
};
|
|
58006
|
-
}
|
|
58007
|
-
const allowed = result.allowed !== false;
|
|
58008
|
-
const decision = {
|
|
58009
|
-
allowed,
|
|
58010
|
-
reason: result.reason
|
|
58011
|
-
};
|
|
58012
|
-
if (result.capabilities) {
|
|
58013
|
-
decision.capabilities = result.capabilities;
|
|
58014
|
-
}
|
|
58015
|
-
return decision;
|
|
58016
|
-
}
|
|
58017
|
-
};
|
|
58018
|
-
}
|
|
58019
|
-
});
|
|
58020
|
-
|
|
58021
|
-
// src/enterprise/scheduler/knex-store.ts
|
|
58022
|
-
var knex_store_exports = {};
|
|
58023
|
-
__export(knex_store_exports, {
|
|
58024
|
-
KnexStoreBackend: () => KnexStoreBackend
|
|
58025
|
-
});
|
|
58026
|
-
function toNum(val) {
|
|
58027
|
-
if (val === null || val === void 0) return void 0;
|
|
58028
|
-
return typeof val === "string" ? parseInt(val, 10) : val;
|
|
58029
|
-
}
|
|
58030
|
-
function safeJsonParse2(value) {
|
|
58031
|
-
if (!value) return void 0;
|
|
58032
|
-
try {
|
|
58033
|
-
return JSON.parse(value);
|
|
58034
|
-
} catch {
|
|
58035
|
-
return void 0;
|
|
58036
|
-
}
|
|
58037
|
-
}
|
|
58038
|
-
function fromTriggerRow2(row) {
|
|
58039
|
-
return {
|
|
58040
|
-
id: row.id,
|
|
58041
|
-
creatorId: row.creator_id,
|
|
58042
|
-
creatorContext: row.creator_context ?? void 0,
|
|
58043
|
-
creatorName: row.creator_name ?? void 0,
|
|
58044
|
-
description: row.description ?? void 0,
|
|
58045
|
-
channels: safeJsonParse2(row.channels),
|
|
58046
|
-
fromUsers: safeJsonParse2(row.from_users),
|
|
58047
|
-
fromBots: row.from_bots === true || row.from_bots === 1,
|
|
58048
|
-
contains: safeJsonParse2(row.contains),
|
|
58049
|
-
matchPattern: row.match_pattern ?? void 0,
|
|
58050
|
-
threads: row.threads,
|
|
58051
|
-
workflow: row.workflow,
|
|
58052
|
-
inputs: safeJsonParse2(row.inputs),
|
|
58053
|
-
outputContext: safeJsonParse2(row.output_context),
|
|
58054
|
-
status: row.status,
|
|
58055
|
-
enabled: row.enabled === true || row.enabled === 1,
|
|
58056
|
-
createdAt: toNum(row.created_at)
|
|
58057
|
-
};
|
|
58058
|
-
}
|
|
58059
|
-
function toTriggerInsertRow(trigger) {
|
|
58060
|
-
return {
|
|
58061
|
-
id: trigger.id,
|
|
58062
|
-
creator_id: trigger.creatorId,
|
|
58063
|
-
creator_context: trigger.creatorContext ?? null,
|
|
58064
|
-
creator_name: trigger.creatorName ?? null,
|
|
58065
|
-
description: trigger.description ?? null,
|
|
58066
|
-
channels: trigger.channels ? JSON.stringify(trigger.channels) : null,
|
|
58067
|
-
from_users: trigger.fromUsers ? JSON.stringify(trigger.fromUsers) : null,
|
|
58068
|
-
from_bots: trigger.fromBots,
|
|
58069
|
-
contains: trigger.contains ? JSON.stringify(trigger.contains) : null,
|
|
58070
|
-
match_pattern: trigger.matchPattern ?? null,
|
|
58071
|
-
threads: trigger.threads,
|
|
58072
|
-
workflow: trigger.workflow,
|
|
58073
|
-
inputs: trigger.inputs ? JSON.stringify(trigger.inputs) : null,
|
|
58074
|
-
output_context: trigger.outputContext ? JSON.stringify(trigger.outputContext) : null,
|
|
58075
|
-
status: trigger.status,
|
|
58076
|
-
enabled: trigger.enabled,
|
|
58077
|
-
created_at: trigger.createdAt
|
|
58078
|
-
};
|
|
58079
|
-
}
|
|
58080
|
-
function fromDbRow2(row) {
|
|
58081
|
-
return {
|
|
58082
|
-
id: row.id,
|
|
58083
|
-
creatorId: row.creator_id,
|
|
58084
|
-
creatorContext: row.creator_context ?? void 0,
|
|
58085
|
-
creatorName: row.creator_name ?? void 0,
|
|
58086
|
-
timezone: row.timezone,
|
|
58087
|
-
schedule: row.schedule_expr,
|
|
58088
|
-
runAt: toNum(row.run_at),
|
|
58089
|
-
isRecurring: row.is_recurring === true || row.is_recurring === 1,
|
|
58090
|
-
originalExpression: row.original_expression,
|
|
58091
|
-
workflow: row.workflow ?? void 0,
|
|
58092
|
-
workflowInputs: safeJsonParse2(row.workflow_inputs),
|
|
58093
|
-
outputContext: safeJsonParse2(row.output_context),
|
|
58094
|
-
status: row.status,
|
|
58095
|
-
createdAt: toNum(row.created_at),
|
|
58096
|
-
lastRunAt: toNum(row.last_run_at),
|
|
58097
|
-
nextRunAt: toNum(row.next_run_at),
|
|
58098
|
-
runCount: row.run_count,
|
|
58099
|
-
failureCount: row.failure_count,
|
|
58100
|
-
lastError: row.last_error ?? void 0,
|
|
58101
|
-
previousResponse: row.previous_response ?? void 0
|
|
58102
|
-
};
|
|
58103
|
-
}
|
|
58104
|
-
function toInsertRow(schedule) {
|
|
58105
|
-
return {
|
|
58106
|
-
id: schedule.id,
|
|
58107
|
-
creator_id: schedule.creatorId,
|
|
58108
|
-
creator_context: schedule.creatorContext ?? null,
|
|
58109
|
-
creator_name: schedule.creatorName ?? null,
|
|
58110
|
-
timezone: schedule.timezone,
|
|
58111
|
-
schedule_expr: schedule.schedule,
|
|
58112
|
-
run_at: schedule.runAt ?? null,
|
|
58113
|
-
is_recurring: schedule.isRecurring,
|
|
58114
|
-
original_expression: schedule.originalExpression,
|
|
58115
|
-
workflow: schedule.workflow ?? null,
|
|
58116
|
-
workflow_inputs: schedule.workflowInputs ? JSON.stringify(schedule.workflowInputs) : null,
|
|
58117
|
-
output_context: schedule.outputContext ? JSON.stringify(schedule.outputContext) : null,
|
|
58118
|
-
status: schedule.status,
|
|
58119
|
-
created_at: schedule.createdAt,
|
|
58120
|
-
last_run_at: schedule.lastRunAt ?? null,
|
|
58121
|
-
next_run_at: schedule.nextRunAt ?? null,
|
|
58122
|
-
run_count: schedule.runCount,
|
|
58123
|
-
failure_count: schedule.failureCount,
|
|
58124
|
-
last_error: schedule.lastError ?? null,
|
|
58125
|
-
previous_response: schedule.previousResponse ?? null
|
|
58126
|
-
};
|
|
58127
|
-
}
|
|
58128
|
-
var fs24, path29, import_uuid2, KnexStoreBackend;
|
|
58129
|
-
var init_knex_store = __esm({
|
|
58130
|
-
"src/enterprise/scheduler/knex-store.ts"() {
|
|
58131
|
-
"use strict";
|
|
58132
|
-
fs24 = __toESM(require("fs"));
|
|
58133
|
-
path29 = __toESM(require("path"));
|
|
58134
|
-
import_uuid2 = require("uuid");
|
|
58135
|
-
init_logger();
|
|
58136
|
-
KnexStoreBackend = class {
|
|
58137
|
-
knex = null;
|
|
58138
|
-
driver;
|
|
58139
|
-
connection;
|
|
58140
|
-
constructor(driver, storageConfig, _haConfig) {
|
|
58141
|
-
this.driver = driver;
|
|
58142
|
-
this.connection = storageConfig.connection || {};
|
|
58143
|
-
}
|
|
58144
|
-
async initialize() {
|
|
58145
|
-
const { createRequire } = require("module");
|
|
58146
|
-
const runtimeRequire = createRequire(__filename);
|
|
58147
|
-
let knexFactory;
|
|
58148
|
-
try {
|
|
58149
|
-
knexFactory = runtimeRequire("knex");
|
|
58150
|
-
} catch (err) {
|
|
58151
|
-
const code = err?.code;
|
|
58152
|
-
if (code === "MODULE_NOT_FOUND" || code === "ERR_MODULE_NOT_FOUND") {
|
|
58153
|
-
throw new Error(
|
|
58154
|
-
"knex is required for PostgreSQL/MySQL/MSSQL schedule storage. Install it with: npm install knex"
|
|
58155
|
-
);
|
|
58156
|
-
}
|
|
58157
|
-
throw err;
|
|
58158
|
-
}
|
|
58159
|
-
const clientMap = {
|
|
58160
|
-
postgresql: "pg",
|
|
58161
|
-
mysql: "mysql2",
|
|
58162
|
-
mssql: "tedious"
|
|
58163
|
-
};
|
|
58164
|
-
const client = clientMap[this.driver];
|
|
58165
|
-
let connection;
|
|
58166
|
-
if (this.connection.connection_string) {
|
|
58167
|
-
connection = this.connection.connection_string;
|
|
58168
|
-
} else if (this.driver === "mssql") {
|
|
58169
|
-
connection = this.buildMssqlConnection();
|
|
58170
|
-
} else {
|
|
58171
|
-
connection = this.buildStandardConnection();
|
|
58172
|
-
}
|
|
58173
|
-
this.knex = knexFactory({
|
|
58174
|
-
client,
|
|
58175
|
-
connection,
|
|
58176
|
-
pool: {
|
|
58177
|
-
min: this.connection.pool?.min ?? 0,
|
|
58178
|
-
max: this.connection.pool?.max ?? 10
|
|
58179
|
-
}
|
|
58180
|
-
});
|
|
58181
|
-
await this.migrateSchema();
|
|
58182
|
-
logger.info(`[KnexStore] Initialized (${this.driver})`);
|
|
58183
|
-
}
|
|
58184
|
-
buildStandardConnection() {
|
|
58185
|
-
return {
|
|
58186
|
-
host: this.connection.host || "localhost",
|
|
58187
|
-
port: this.connection.port,
|
|
58188
|
-
database: this.connection.database || "visor",
|
|
58189
|
-
user: this.connection.user,
|
|
58190
|
-
password: this.connection.password,
|
|
58191
|
-
ssl: this.resolveSslConfig()
|
|
58192
|
-
};
|
|
58193
|
-
}
|
|
58194
|
-
buildMssqlConnection() {
|
|
58195
|
-
const ssl = this.connection.ssl;
|
|
58196
|
-
const sslEnabled = ssl === true || typeof ssl === "object" && ssl.enabled !== false;
|
|
58197
|
-
return {
|
|
58198
|
-
server: this.connection.host || "localhost",
|
|
58199
|
-
port: this.connection.port,
|
|
58200
|
-
database: this.connection.database || "visor",
|
|
58201
|
-
user: this.connection.user,
|
|
58202
|
-
password: this.connection.password,
|
|
58203
|
-
options: {
|
|
58204
|
-
encrypt: sslEnabled,
|
|
58205
|
-
trustServerCertificate: typeof ssl === "object" ? ssl.reject_unauthorized === false : !sslEnabled
|
|
58206
|
-
}
|
|
58207
|
-
};
|
|
58208
|
-
}
|
|
58209
|
-
resolveSslConfig() {
|
|
58210
|
-
const ssl = this.connection.ssl;
|
|
58211
|
-
if (ssl === false || ssl === void 0) return false;
|
|
58212
|
-
if (ssl === true) return { rejectUnauthorized: true };
|
|
58213
|
-
if (ssl.enabled === false) return false;
|
|
58214
|
-
const result = {
|
|
58215
|
-
rejectUnauthorized: ssl.reject_unauthorized !== false
|
|
58216
|
-
};
|
|
58217
|
-
if (ssl.ca) {
|
|
58218
|
-
const caPath = this.validateSslPath(ssl.ca, "CA certificate");
|
|
58219
|
-
result.ca = fs24.readFileSync(caPath, "utf8");
|
|
58220
|
-
}
|
|
58221
|
-
if (ssl.cert) {
|
|
58222
|
-
const certPath = this.validateSslPath(ssl.cert, "client certificate");
|
|
58223
|
-
result.cert = fs24.readFileSync(certPath, "utf8");
|
|
58224
|
-
}
|
|
58225
|
-
if (ssl.key) {
|
|
58226
|
-
const keyPath = this.validateSslPath(ssl.key, "client key");
|
|
58227
|
-
result.key = fs24.readFileSync(keyPath, "utf8");
|
|
58228
|
-
}
|
|
58229
|
-
return result;
|
|
58230
|
-
}
|
|
58231
|
-
validateSslPath(filePath, label) {
|
|
58232
|
-
const resolved = path29.resolve(filePath);
|
|
58233
|
-
if (resolved !== path29.normalize(resolved)) {
|
|
58234
|
-
throw new Error(`SSL ${label} path contains invalid sequences: ${filePath}`);
|
|
58235
|
-
}
|
|
58236
|
-
if (!fs24.existsSync(resolved)) {
|
|
58237
|
-
throw new Error(`SSL ${label} not found: ${filePath}`);
|
|
58238
|
-
}
|
|
58239
|
-
return resolved;
|
|
58240
|
-
}
|
|
58241
|
-
async shutdown() {
|
|
58242
|
-
if (this.knex) {
|
|
58243
|
-
await this.knex.destroy();
|
|
58244
|
-
this.knex = null;
|
|
58245
|
-
}
|
|
58246
|
-
}
|
|
58247
|
-
async migrateSchema() {
|
|
58248
|
-
const knex = this.getKnex();
|
|
58249
|
-
const exists = await knex.schema.hasTable("schedules");
|
|
58250
|
-
if (!exists) {
|
|
58251
|
-
await knex.schema.createTable("schedules", (table) => {
|
|
58252
|
-
table.string("id", 36).primary();
|
|
58253
|
-
table.string("creator_id", 255).notNullable().index();
|
|
58254
|
-
table.string("creator_context", 255);
|
|
58255
|
-
table.string("creator_name", 255);
|
|
58256
|
-
table.string("timezone", 64).notNullable().defaultTo("UTC");
|
|
58257
|
-
table.string("schedule_expr", 255);
|
|
58258
|
-
table.bigInteger("run_at");
|
|
58259
|
-
table.boolean("is_recurring").notNullable();
|
|
58260
|
-
table.text("original_expression");
|
|
58261
|
-
table.string("workflow", 255);
|
|
58262
|
-
table.text("workflow_inputs");
|
|
58263
|
-
table.text("output_context");
|
|
58264
|
-
table.string("status", 20).notNullable().index();
|
|
58265
|
-
table.bigInteger("created_at").notNullable();
|
|
58266
|
-
table.bigInteger("last_run_at");
|
|
58267
|
-
table.bigInteger("next_run_at");
|
|
58268
|
-
table.integer("run_count").notNullable().defaultTo(0);
|
|
58269
|
-
table.integer("failure_count").notNullable().defaultTo(0);
|
|
58270
|
-
table.text("last_error");
|
|
58271
|
-
table.text("previous_response");
|
|
58272
|
-
table.index(["status", "next_run_at"]);
|
|
58273
|
-
});
|
|
58274
|
-
}
|
|
58275
|
-
const triggersExist = await knex.schema.hasTable("message_triggers");
|
|
58276
|
-
if (!triggersExist) {
|
|
58277
|
-
await knex.schema.createTable("message_triggers", (table) => {
|
|
58278
|
-
table.string("id", 36).primary();
|
|
58279
|
-
table.string("creator_id", 255).notNullable().index();
|
|
58280
|
-
table.string("creator_context", 255);
|
|
58281
|
-
table.string("creator_name", 255);
|
|
58282
|
-
table.text("description");
|
|
58283
|
-
table.text("channels");
|
|
58284
|
-
table.text("from_users");
|
|
58285
|
-
table.boolean("from_bots").notNullable().defaultTo(false);
|
|
58286
|
-
table.text("contains");
|
|
58287
|
-
table.text("match_pattern");
|
|
58288
|
-
table.string("threads", 20).notNullable().defaultTo("any");
|
|
58289
|
-
table.string("workflow", 255).notNullable();
|
|
58290
|
-
table.text("inputs");
|
|
58291
|
-
table.text("output_context");
|
|
58292
|
-
table.string("status", 20).notNullable().defaultTo("active").index();
|
|
58293
|
-
table.boolean("enabled").notNullable().defaultTo(true);
|
|
58294
|
-
table.bigInteger("created_at").notNullable();
|
|
58295
|
-
});
|
|
58296
|
-
}
|
|
58297
|
-
const locksExist = await knex.schema.hasTable("scheduler_locks");
|
|
58298
|
-
if (!locksExist) {
|
|
58299
|
-
await knex.schema.createTable("scheduler_locks", (table) => {
|
|
58300
|
-
table.string("lock_id", 255).primary();
|
|
58301
|
-
table.string("node_id", 255).notNullable();
|
|
58302
|
-
table.string("lock_token", 36).notNullable();
|
|
58303
|
-
table.bigInteger("acquired_at").notNullable();
|
|
58304
|
-
table.bigInteger("expires_at").notNullable();
|
|
58305
|
-
});
|
|
58306
|
-
}
|
|
58307
|
-
}
|
|
58308
|
-
getKnex() {
|
|
58309
|
-
if (!this.knex) {
|
|
58310
|
-
throw new Error("[KnexStore] Not initialized. Call initialize() first.");
|
|
58311
|
-
}
|
|
58312
|
-
return this.knex;
|
|
58313
|
-
}
|
|
58314
|
-
// --- CRUD ---
|
|
58315
|
-
async create(schedule) {
|
|
58316
|
-
const knex = this.getKnex();
|
|
58317
|
-
const newSchedule = {
|
|
58318
|
-
...schedule,
|
|
58319
|
-
id: (0, import_uuid2.v4)(),
|
|
58320
|
-
createdAt: Date.now(),
|
|
58321
|
-
runCount: 0,
|
|
58322
|
-
failureCount: 0,
|
|
58323
|
-
status: "active"
|
|
58324
|
-
};
|
|
58325
|
-
await knex("schedules").insert(toInsertRow(newSchedule));
|
|
58326
|
-
logger.info(`[KnexStore] Created schedule ${newSchedule.id} for user ${newSchedule.creatorId}`);
|
|
58327
|
-
return newSchedule;
|
|
58328
|
-
}
|
|
58329
|
-
async importSchedule(schedule) {
|
|
58330
|
-
const knex = this.getKnex();
|
|
58331
|
-
const existing = await knex("schedules").where("id", schedule.id).first();
|
|
58332
|
-
if (existing) return;
|
|
58333
|
-
await knex("schedules").insert(toInsertRow(schedule));
|
|
58334
|
-
}
|
|
58335
|
-
async get(id) {
|
|
58336
|
-
const knex = this.getKnex();
|
|
58337
|
-
const row = await knex("schedules").where("id", id).first();
|
|
58338
|
-
return row ? fromDbRow2(row) : void 0;
|
|
58339
|
-
}
|
|
58340
|
-
async update(id, patch) {
|
|
58341
|
-
const knex = this.getKnex();
|
|
58342
|
-
const existing = await knex("schedules").where("id", id).first();
|
|
58343
|
-
if (!existing) return void 0;
|
|
58344
|
-
const current = fromDbRow2(existing);
|
|
58345
|
-
const updated = { ...current, ...patch, id: current.id };
|
|
58346
|
-
const row = toInsertRow(updated);
|
|
58347
|
-
delete row.id;
|
|
58348
|
-
await knex("schedules").where("id", id).update(row);
|
|
58349
|
-
return updated;
|
|
58350
|
-
}
|
|
58351
|
-
async delete(id) {
|
|
58352
|
-
const knex = this.getKnex();
|
|
58353
|
-
const deleted = await knex("schedules").where("id", id).del();
|
|
58354
|
-
if (deleted > 0) {
|
|
58355
|
-
logger.info(`[KnexStore] Deleted schedule ${id}`);
|
|
58356
|
-
return true;
|
|
58357
|
-
}
|
|
58358
|
-
return false;
|
|
58359
|
-
}
|
|
58360
|
-
// --- Queries ---
|
|
58361
|
-
async getByCreator(creatorId) {
|
|
58362
|
-
const knex = this.getKnex();
|
|
58363
|
-
const rows = await knex("schedules").where("creator_id", creatorId);
|
|
58364
|
-
return rows.map((r) => fromDbRow2(r));
|
|
58365
|
-
}
|
|
58366
|
-
async getActiveSchedules() {
|
|
58367
|
-
const knex = this.getKnex();
|
|
58368
|
-
const rows = await knex("schedules").where("status", "active");
|
|
58369
|
-
return rows.map((r) => fromDbRow2(r));
|
|
58370
|
-
}
|
|
58371
|
-
async getDueSchedules(now) {
|
|
58372
|
-
const ts = now ?? Date.now();
|
|
58373
|
-
const knex = this.getKnex();
|
|
58374
|
-
const bFalse = this.driver === "mssql" ? 0 : false;
|
|
58375
|
-
const bTrue = this.driver === "mssql" ? 1 : true;
|
|
58376
|
-
const rows = await knex("schedules").where("status", "active").andWhere(function() {
|
|
58377
|
-
this.where(function() {
|
|
58378
|
-
this.where("is_recurring", bFalse).whereNotNull("run_at").where("run_at", "<=", ts);
|
|
58379
|
-
}).orWhere(function() {
|
|
58380
|
-
this.where("is_recurring", bTrue).whereNotNull("next_run_at").where("next_run_at", "<=", ts);
|
|
58381
|
-
});
|
|
58382
|
-
});
|
|
58383
|
-
return rows.map((r) => fromDbRow2(r));
|
|
58384
|
-
}
|
|
58385
|
-
async findByWorkflow(creatorId, workflowName) {
|
|
58386
|
-
const knex = this.getKnex();
|
|
58387
|
-
const escaped = workflowName.toLowerCase().replace(/[%_\\]/g, "\\$&");
|
|
58388
|
-
const pattern = `%${escaped}%`;
|
|
58389
|
-
const rows = await knex("schedules").where("creator_id", creatorId).where("status", "active").whereRaw("LOWER(workflow) LIKE ? ESCAPE '\\'", [pattern]);
|
|
58390
|
-
return rows.map((r) => fromDbRow2(r));
|
|
58391
|
-
}
|
|
58392
|
-
async getAll() {
|
|
58393
|
-
const knex = this.getKnex();
|
|
58394
|
-
const rows = await knex("schedules");
|
|
58395
|
-
return rows.map((r) => fromDbRow2(r));
|
|
58396
|
-
}
|
|
58397
|
-
async getStats() {
|
|
58398
|
-
const knex = this.getKnex();
|
|
58399
|
-
const boolTrue = this.driver === "mssql" ? "1" : "true";
|
|
58400
|
-
const boolFalse = this.driver === "mssql" ? "0" : "false";
|
|
58401
|
-
const result = await knex("schedules").select(
|
|
58402
|
-
knex.raw("COUNT(*) as total"),
|
|
58403
|
-
knex.raw("SUM(CASE WHEN status = 'active' THEN 1 ELSE 0 END) as active"),
|
|
58404
|
-
knex.raw("SUM(CASE WHEN status = 'paused' THEN 1 ELSE 0 END) as paused"),
|
|
58405
|
-
knex.raw("SUM(CASE WHEN status = 'completed' THEN 1 ELSE 0 END) as completed"),
|
|
58406
|
-
knex.raw("SUM(CASE WHEN status = 'failed' THEN 1 ELSE 0 END) as failed"),
|
|
58407
|
-
knex.raw(`SUM(CASE WHEN is_recurring = ${boolTrue} THEN 1 ELSE 0 END) as recurring`),
|
|
58408
|
-
knex.raw(`SUM(CASE WHEN is_recurring = ${boolFalse} THEN 1 ELSE 0 END) as one_time`)
|
|
58409
|
-
).first();
|
|
58410
|
-
return {
|
|
58411
|
-
total: Number(result.total) || 0,
|
|
58412
|
-
active: Number(result.active) || 0,
|
|
58413
|
-
paused: Number(result.paused) || 0,
|
|
58414
|
-
completed: Number(result.completed) || 0,
|
|
58415
|
-
failed: Number(result.failed) || 0,
|
|
58416
|
-
recurring: Number(result.recurring) || 0,
|
|
58417
|
-
oneTime: Number(result.one_time) || 0
|
|
58418
|
-
};
|
|
58419
|
-
}
|
|
58420
|
-
async validateLimits(creatorId, isRecurring, limits) {
|
|
58421
|
-
const knex = this.getKnex();
|
|
58422
|
-
if (limits.maxGlobal) {
|
|
58423
|
-
const result = await knex("schedules").count("* as cnt").first();
|
|
58424
|
-
if (Number(result?.cnt) >= limits.maxGlobal) {
|
|
58425
|
-
throw new Error(`Global schedule limit reached (${limits.maxGlobal})`);
|
|
58426
|
-
}
|
|
58427
|
-
}
|
|
58428
|
-
if (limits.maxPerUser) {
|
|
58429
|
-
const result = await knex("schedules").where("creator_id", creatorId).count("* as cnt").first();
|
|
58430
|
-
if (Number(result?.cnt) >= limits.maxPerUser) {
|
|
58431
|
-
throw new Error(`You have reached the maximum number of schedules (${limits.maxPerUser})`);
|
|
58432
|
-
}
|
|
58433
|
-
}
|
|
58434
|
-
if (isRecurring && limits.maxRecurringPerUser) {
|
|
58435
|
-
const bTrue = this.driver === "mssql" ? 1 : true;
|
|
58436
|
-
const result = await knex("schedules").where("creator_id", creatorId).where("is_recurring", bTrue).count("* as cnt").first();
|
|
58437
|
-
if (Number(result?.cnt) >= limits.maxRecurringPerUser) {
|
|
58438
|
-
throw new Error(
|
|
58439
|
-
`You have reached the maximum number of recurring schedules (${limits.maxRecurringPerUser})`
|
|
58440
|
-
);
|
|
58441
|
-
}
|
|
58442
|
-
}
|
|
58443
|
-
}
|
|
58444
|
-
// --- HA Distributed Locking (via scheduler_locks table) ---
|
|
58445
|
-
async tryAcquireLock(lockId, nodeId, ttlSeconds) {
|
|
58446
|
-
const knex = this.getKnex();
|
|
58447
|
-
const now = Date.now();
|
|
58448
|
-
const expiresAt = now + ttlSeconds * 1e3;
|
|
58449
|
-
const token = (0, import_uuid2.v4)();
|
|
58450
|
-
const updated = await knex("scheduler_locks").where("lock_id", lockId).where("expires_at", "<", now).update({
|
|
58451
|
-
node_id: nodeId,
|
|
58452
|
-
lock_token: token,
|
|
58453
|
-
acquired_at: now,
|
|
58454
|
-
expires_at: expiresAt
|
|
58455
|
-
});
|
|
58456
|
-
if (updated > 0) return token;
|
|
58457
|
-
try {
|
|
58458
|
-
await knex("scheduler_locks").insert({
|
|
58459
|
-
lock_id: lockId,
|
|
58460
|
-
node_id: nodeId,
|
|
58461
|
-
lock_token: token,
|
|
58462
|
-
acquired_at: now,
|
|
58463
|
-
expires_at: expiresAt
|
|
58464
|
-
});
|
|
58465
|
-
return token;
|
|
58466
|
-
} catch {
|
|
58467
|
-
return null;
|
|
58468
|
-
}
|
|
58469
|
-
}
|
|
58470
|
-
async releaseLock(lockId, lockToken) {
|
|
58471
|
-
const knex = this.getKnex();
|
|
58472
|
-
await knex("scheduler_locks").where("lock_id", lockId).where("lock_token", lockToken).del();
|
|
58473
|
-
}
|
|
58474
|
-
async renewLock(lockId, lockToken, ttlSeconds) {
|
|
58475
|
-
const knex = this.getKnex();
|
|
58476
|
-
const now = Date.now();
|
|
58477
|
-
const expiresAt = now + ttlSeconds * 1e3;
|
|
58478
|
-
const updated = await knex("scheduler_locks").where("lock_id", lockId).where("lock_token", lockToken).update({ acquired_at: now, expires_at: expiresAt });
|
|
58479
|
-
return updated > 0;
|
|
58480
|
-
}
|
|
58481
|
-
async flush() {
|
|
58482
|
-
}
|
|
58483
|
-
// --- Message Trigger CRUD ---
|
|
58484
|
-
async createTrigger(trigger) {
|
|
58485
|
-
const knex = this.getKnex();
|
|
58486
|
-
const newTrigger = {
|
|
58487
|
-
...trigger,
|
|
58488
|
-
id: (0, import_uuid2.v4)(),
|
|
58489
|
-
createdAt: Date.now()
|
|
58490
|
-
};
|
|
58491
|
-
await knex("message_triggers").insert(toTriggerInsertRow(newTrigger));
|
|
58492
|
-
logger.info(`[KnexStore] Created trigger ${newTrigger.id} for user ${newTrigger.creatorId}`);
|
|
58493
|
-
return newTrigger;
|
|
58494
|
-
}
|
|
58495
|
-
async getTrigger(id) {
|
|
58496
|
-
const knex = this.getKnex();
|
|
58497
|
-
const row = await knex("message_triggers").where("id", id).first();
|
|
58498
|
-
return row ? fromTriggerRow2(row) : void 0;
|
|
58499
|
-
}
|
|
58500
|
-
async updateTrigger(id, patch) {
|
|
58501
|
-
const knex = this.getKnex();
|
|
58502
|
-
const existing = await knex("message_triggers").where("id", id).first();
|
|
58503
|
-
if (!existing) return void 0;
|
|
58504
|
-
const current = fromTriggerRow2(existing);
|
|
58505
|
-
const updated = {
|
|
58506
|
-
...current,
|
|
58507
|
-
...patch,
|
|
58508
|
-
id: current.id,
|
|
58509
|
-
createdAt: current.createdAt
|
|
58510
|
-
};
|
|
58511
|
-
const row = toTriggerInsertRow(updated);
|
|
58512
|
-
delete row.id;
|
|
58513
|
-
await knex("message_triggers").where("id", id).update(row);
|
|
58514
|
-
return updated;
|
|
58515
|
-
}
|
|
58516
|
-
async deleteTrigger(id) {
|
|
58517
|
-
const knex = this.getKnex();
|
|
58518
|
-
const deleted = await knex("message_triggers").where("id", id).del();
|
|
58519
|
-
if (deleted > 0) {
|
|
58520
|
-
logger.info(`[KnexStore] Deleted trigger ${id}`);
|
|
58521
|
-
return true;
|
|
58522
|
-
}
|
|
58523
|
-
return false;
|
|
58524
|
-
}
|
|
58525
|
-
async getTriggersByCreator(creatorId) {
|
|
58526
|
-
const knex = this.getKnex();
|
|
58527
|
-
const rows = await knex("message_triggers").where("creator_id", creatorId);
|
|
58528
|
-
return rows.map((r) => fromTriggerRow2(r));
|
|
58529
|
-
}
|
|
58530
|
-
async getActiveTriggers() {
|
|
58531
|
-
const knex = this.getKnex();
|
|
58532
|
-
const rows = await knex("message_triggers").where("status", "active").where("enabled", this.driver === "mssql" ? 1 : true);
|
|
58533
|
-
return rows.map((r) => fromTriggerRow2(r));
|
|
58534
|
-
}
|
|
58535
|
-
};
|
|
58536
|
-
}
|
|
58537
|
-
});
|
|
58538
|
-
|
|
58539
|
-
// src/enterprise/loader.ts
|
|
58540
|
-
var loader_exports = {};
|
|
58541
|
-
__export(loader_exports, {
|
|
58542
|
-
loadEnterprisePolicyEngine: () => loadEnterprisePolicyEngine,
|
|
58543
|
-
loadEnterpriseStoreBackend: () => loadEnterpriseStoreBackend
|
|
58544
|
-
});
|
|
58545
|
-
async function loadEnterprisePolicyEngine(config) {
|
|
58546
|
-
try {
|
|
58547
|
-
const { LicenseValidator: LicenseValidator2 } = await Promise.resolve().then(() => (init_validator(), validator_exports));
|
|
58548
|
-
const validator = new LicenseValidator2();
|
|
58549
|
-
const license = await validator.loadAndValidate();
|
|
58550
|
-
if (!license || !validator.hasFeature("policy")) {
|
|
58551
|
-
return new DefaultPolicyEngine();
|
|
58552
|
-
}
|
|
58553
|
-
if (validator.isInGracePeriod()) {
|
|
58554
|
-
console.warn(
|
|
58555
|
-
"[visor:enterprise] License has expired but is within the 72-hour grace period. Please renew your license."
|
|
58556
|
-
);
|
|
58557
|
-
}
|
|
58558
|
-
const { OpaPolicyEngine: OpaPolicyEngine2 } = await Promise.resolve().then(() => (init_opa_policy_engine(), opa_policy_engine_exports));
|
|
58559
|
-
const engine = new OpaPolicyEngine2(config);
|
|
58560
|
-
await engine.initialize(config);
|
|
58561
|
-
return engine;
|
|
58562
|
-
} catch (err) {
|
|
58563
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
58564
|
-
try {
|
|
58565
|
-
const { logger: logger2 } = (init_logger(), __toCommonJS(logger_exports));
|
|
58566
|
-
logger2.warn(`[PolicyEngine] Enterprise policy init failed, falling back to default: ${msg}`);
|
|
58567
|
-
} catch {
|
|
58568
|
-
}
|
|
58569
|
-
return new DefaultPolicyEngine();
|
|
58570
|
-
}
|
|
58571
|
-
}
|
|
58572
|
-
async function loadEnterpriseStoreBackend(driver, storageConfig, haConfig) {
|
|
58573
|
-
const { LicenseValidator: LicenseValidator2 } = await Promise.resolve().then(() => (init_validator(), validator_exports));
|
|
58574
|
-
const validator = new LicenseValidator2();
|
|
58575
|
-
const license = await validator.loadAndValidate();
|
|
58576
|
-
if (!license || !validator.hasFeature("scheduler-sql")) {
|
|
58577
|
-
throw new Error(
|
|
58578
|
-
`The ${driver} schedule storage driver requires a Visor Enterprise license with the 'scheduler-sql' feature. Please upgrade or use driver: 'sqlite' (default).`
|
|
58579
|
-
);
|
|
58580
|
-
}
|
|
58581
|
-
if (validator.isInGracePeriod()) {
|
|
58582
|
-
console.warn(
|
|
58583
|
-
"[visor:enterprise] License has expired but is within the 72-hour grace period. Please renew your license."
|
|
58584
|
-
);
|
|
58585
|
-
}
|
|
58586
|
-
const { KnexStoreBackend: KnexStoreBackend2 } = await Promise.resolve().then(() => (init_knex_store(), knex_store_exports));
|
|
58587
|
-
return new KnexStoreBackend2(driver, storageConfig, haConfig);
|
|
58588
|
-
}
|
|
58589
|
-
var init_loader = __esm({
|
|
58590
|
-
"src/enterprise/loader.ts"() {
|
|
58591
|
-
"use strict";
|
|
58592
|
-
init_default_engine();
|
|
58593
|
-
}
|
|
58594
|
-
});
|
|
58595
|
-
|
|
58596
57452
|
// src/event-bus/event-bus.ts
|
|
58597
57453
|
var event_bus_exports = {};
|
|
58598
57454
|
__export(event_bus_exports, {
|
|
@@ -59250,6 +58106,9 @@ var init_github_comments = __esm({
|
|
|
59250
58106
|
CommentManager = class {
|
|
59251
58107
|
octokit;
|
|
59252
58108
|
retryConfig;
|
|
58109
|
+
// Serial write queue: chains all updateOrCreateComment calls so only one
|
|
58110
|
+
// GitHub comment write is in-flight at a time within a job.
|
|
58111
|
+
_writeQueue = Promise.resolve();
|
|
59253
58112
|
constructor(octokit, retryConfig) {
|
|
59254
58113
|
this.octokit = octokit;
|
|
59255
58114
|
this.retryConfig = {
|
|
@@ -59292,6 +58151,11 @@ var init_github_comments = __esm({
|
|
|
59292
58151
|
* Update existing comment or create new one with collision detection
|
|
59293
58152
|
*/
|
|
59294
58153
|
async updateOrCreateComment(owner, repo, prNumber, content, options = {}) {
|
|
58154
|
+
return new Promise((resolve15, reject) => {
|
|
58155
|
+
this._writeQueue = this._writeQueue.then(() => this._doUpdateOrCreate(owner, repo, prNumber, content, options)).then(resolve15, reject);
|
|
58156
|
+
});
|
|
58157
|
+
}
|
|
58158
|
+
async _doUpdateOrCreate(owner, repo, prNumber, content, options = {}) {
|
|
59295
58159
|
const {
|
|
59296
58160
|
commentId = this.generateCommentId(),
|
|
59297
58161
|
triggeredBy = "unknown",
|
|
@@ -59499,8 +58363,8 @@ ${content}
|
|
|
59499
58363
|
* Sleep utility
|
|
59500
58364
|
*/
|
|
59501
58365
|
sleep(ms) {
|
|
59502
|
-
return new Promise((
|
|
59503
|
-
const t = setTimeout(
|
|
58366
|
+
return new Promise((resolve15) => {
|
|
58367
|
+
const t = setTimeout(resolve15, ms);
|
|
59504
58368
|
if (typeof t.unref === "function") {
|
|
59505
58369
|
try {
|
|
59506
58370
|
t.unref();
|
|
@@ -59785,8 +58649,8 @@ ${end}`);
|
|
|
59785
58649
|
async updateGroupedComment(ctx, comments, group, changedIds) {
|
|
59786
58650
|
const existingLock = this.updateLocks.get(group);
|
|
59787
58651
|
let resolveLock;
|
|
59788
|
-
const ourLock = new Promise((
|
|
59789
|
-
resolveLock =
|
|
58652
|
+
const ourLock = new Promise((resolve15) => {
|
|
58653
|
+
resolveLock = resolve15;
|
|
59790
58654
|
});
|
|
59791
58655
|
this.updateLocks.set(group, ourLock);
|
|
59792
58656
|
try {
|
|
@@ -60117,7 +58981,7 @@ ${blocks}
|
|
|
60117
58981
|
* Sleep utility for enforcing delays
|
|
60118
58982
|
*/
|
|
60119
58983
|
sleep(ms) {
|
|
60120
|
-
return new Promise((
|
|
58984
|
+
return new Promise((resolve15) => setTimeout(resolve15, ms));
|
|
60121
58985
|
}
|
|
60122
58986
|
};
|
|
60123
58987
|
}
|
|
@@ -61979,11 +60843,11 @@ var require_request3 = __commonJS({
|
|
|
61979
60843
|
"use strict";
|
|
61980
60844
|
var __awaiter = exports2 && exports2.__awaiter || function(thisArg, _arguments, P, generator) {
|
|
61981
60845
|
function adopt(value) {
|
|
61982
|
-
return value instanceof P ? value : new P(function(
|
|
61983
|
-
|
|
60846
|
+
return value instanceof P ? value : new P(function(resolve15) {
|
|
60847
|
+
resolve15(value);
|
|
61984
60848
|
});
|
|
61985
60849
|
}
|
|
61986
|
-
return new (P || (P = Promise))(function(
|
|
60850
|
+
return new (P || (P = Promise))(function(resolve15, reject) {
|
|
61987
60851
|
function fulfilled(value) {
|
|
61988
60852
|
try {
|
|
61989
60853
|
step(generator.next(value));
|
|
@@ -61999,7 +60863,7 @@ var require_request3 = __commonJS({
|
|
|
61999
60863
|
}
|
|
62000
60864
|
}
|
|
62001
60865
|
function step(result) {
|
|
62002
|
-
result.done ?
|
|
60866
|
+
result.done ? resolve15(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
62003
60867
|
}
|
|
62004
60868
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
62005
60869
|
});
|
|
@@ -62023,9 +60887,9 @@ var require_request3 = __commonJS({
|
|
|
62023
60887
|
HttpMethod2["PATCH"] = "PATCH";
|
|
62024
60888
|
})(HttpMethod = exports2.HttpMethod || (exports2.HttpMethod = {}));
|
|
62025
60889
|
var SvixRequest = class {
|
|
62026
|
-
constructor(method,
|
|
60890
|
+
constructor(method, path29) {
|
|
62027
60891
|
this.method = method;
|
|
62028
|
-
this.path =
|
|
60892
|
+
this.path = path29;
|
|
62029
60893
|
this.queryParams = {};
|
|
62030
60894
|
this.headerParams = {};
|
|
62031
60895
|
}
|
|
@@ -62128,7 +60992,7 @@ var require_request3 = __commonJS({
|
|
|
62128
60992
|
}
|
|
62129
60993
|
function sendWithRetry(url, init, retryScheduleInMs, nextInterval = 50, triesLeft = 2, fetchImpl = fetch, retryCount = 1) {
|
|
62130
60994
|
return __awaiter(this, void 0, void 0, function* () {
|
|
62131
|
-
const sleep = (interval) => new Promise((
|
|
60995
|
+
const sleep = (interval) => new Promise((resolve15) => setTimeout(resolve15, interval));
|
|
62132
60996
|
try {
|
|
62133
60997
|
const response = yield fetchImpl(url, init);
|
|
62134
60998
|
if (triesLeft <= 0 || response.status < 500) {
|
|
@@ -71202,7 +70066,7 @@ ${message}`;
|
|
|
71202
70066
|
});
|
|
71203
70067
|
|
|
71204
70068
|
// src/agent-protocol/task-store.ts
|
|
71205
|
-
function
|
|
70069
|
+
function safeJsonParse2(value) {
|
|
71206
70070
|
if (!value) return void 0;
|
|
71207
70071
|
try {
|
|
71208
70072
|
return JSON.parse(value);
|
|
@@ -71219,12 +70083,12 @@ function taskRowToAgentTask(row) {
|
|
|
71219
70083
|
context_id: row.context_id,
|
|
71220
70084
|
status: {
|
|
71221
70085
|
state: row.state,
|
|
71222
|
-
message:
|
|
70086
|
+
message: safeJsonParse2(row.status_message),
|
|
71223
70087
|
timestamp: row.updated_at
|
|
71224
70088
|
},
|
|
71225
|
-
artifacts:
|
|
71226
|
-
history:
|
|
71227
|
-
metadata:
|
|
70089
|
+
artifacts: safeJsonParse2(row.artifacts) ?? [],
|
|
70090
|
+
history: safeJsonParse2(row.history) ?? [],
|
|
70091
|
+
metadata: safeJsonParse2(row.request_metadata),
|
|
71228
70092
|
workflow_id: row.workflow_id ?? void 0
|
|
71229
70093
|
};
|
|
71230
70094
|
}
|
|
@@ -71461,7 +70325,7 @@ var init_task_store = __esm({
|
|
|
71461
70325
|
const db = this.getDb();
|
|
71462
70326
|
const row = db.prepare("SELECT artifacts FROM agent_tasks WHERE id = ?").get(taskId);
|
|
71463
70327
|
if (!row) throw new TaskNotFoundError(taskId);
|
|
71464
|
-
const artifacts =
|
|
70328
|
+
const artifacts = safeJsonParse2(row.artifacts) ?? [];
|
|
71465
70329
|
artifacts.push(artifact);
|
|
71466
70330
|
db.prepare("UPDATE agent_tasks SET artifacts = ?, updated_at = ? WHERE id = ?").run(
|
|
71467
70331
|
JSON.stringify(artifacts),
|
|
@@ -71473,7 +70337,7 @@ var init_task_store = __esm({
|
|
|
71473
70337
|
const db = this.getDb();
|
|
71474
70338
|
const row = db.prepare("SELECT history FROM agent_tasks WHERE id = ?").get(taskId);
|
|
71475
70339
|
if (!row) throw new TaskNotFoundError(taskId);
|
|
71476
|
-
const history =
|
|
70340
|
+
const history = safeJsonParse2(row.history) ?? [];
|
|
71477
70341
|
history.push(message);
|
|
71478
70342
|
db.prepare("UPDATE agent_tasks SET history = ?, updated_at = ? WHERE id = ?").run(
|
|
71479
70343
|
JSON.stringify(history),
|
|
@@ -71985,13 +70849,13 @@ __export(a2a_frontend_exports, {
|
|
|
71985
70849
|
resultToArtifacts: () => resultToArtifacts
|
|
71986
70850
|
});
|
|
71987
70851
|
function readJsonBody(req) {
|
|
71988
|
-
return new Promise((
|
|
70852
|
+
return new Promise((resolve15, reject) => {
|
|
71989
70853
|
const chunks = [];
|
|
71990
70854
|
req.on("data", (chunk) => chunks.push(chunk));
|
|
71991
70855
|
req.on("end", () => {
|
|
71992
70856
|
try {
|
|
71993
70857
|
const body = Buffer.concat(chunks).toString("utf8");
|
|
71994
|
-
|
|
70858
|
+
resolve15(body ? JSON.parse(body) : {});
|
|
71995
70859
|
} catch {
|
|
71996
70860
|
reject(new ParseError("Malformed JSON body"));
|
|
71997
70861
|
}
|
|
@@ -72234,12 +71098,12 @@ var init_a2a_frontend = __esm({
|
|
|
72234
71098
|
}
|
|
72235
71099
|
const port = this.config.port ?? 9e3;
|
|
72236
71100
|
const host = this.config.host ?? "0.0.0.0";
|
|
72237
|
-
await new Promise((
|
|
71101
|
+
await new Promise((resolve15) => {
|
|
72238
71102
|
this.server.listen(port, host, () => {
|
|
72239
71103
|
const addr = this.server.address();
|
|
72240
71104
|
this._boundPort = typeof addr === "object" && addr ? addr.port : port;
|
|
72241
71105
|
logger.info(`A2A server listening on ${host}:${this._boundPort}`);
|
|
72242
|
-
|
|
71106
|
+
resolve15();
|
|
72243
71107
|
});
|
|
72244
71108
|
});
|
|
72245
71109
|
if (this.agentCard) {
|
|
@@ -72263,8 +71127,8 @@ var init_a2a_frontend = __esm({
|
|
|
72263
71127
|
}
|
|
72264
71128
|
this.streamManager.shutdown();
|
|
72265
71129
|
if (this.server) {
|
|
72266
|
-
await new Promise((
|
|
72267
|
-
this.server.close((err) => err ? reject(err) :
|
|
71130
|
+
await new Promise((resolve15, reject) => {
|
|
71131
|
+
this.server.close((err) => err ? reject(err) : resolve15());
|
|
72268
71132
|
});
|
|
72269
71133
|
this.server = null;
|
|
72270
71134
|
}
|
|
@@ -72981,15 +71845,15 @@ function serializeRunState(state) {
|
|
|
72981
71845
|
])
|
|
72982
71846
|
};
|
|
72983
71847
|
}
|
|
72984
|
-
var
|
|
71848
|
+
var path28, fs24, StateMachineExecutionEngine;
|
|
72985
71849
|
var init_state_machine_execution_engine = __esm({
|
|
72986
71850
|
"src/state-machine-execution-engine.ts"() {
|
|
72987
71851
|
"use strict";
|
|
72988
71852
|
init_runner();
|
|
72989
71853
|
init_logger();
|
|
72990
71854
|
init_sandbox_manager();
|
|
72991
|
-
|
|
72992
|
-
|
|
71855
|
+
path28 = __toESM(require("path"));
|
|
71856
|
+
fs24 = __toESM(require("fs"));
|
|
72993
71857
|
StateMachineExecutionEngine = class _StateMachineExecutionEngine {
|
|
72994
71858
|
workingDirectory;
|
|
72995
71859
|
executionContext;
|
|
@@ -73221,8 +72085,8 @@ var init_state_machine_execution_engine = __esm({
|
|
|
73221
72085
|
logger.debug(
|
|
73222
72086
|
`[PolicyEngine] Loading enterprise policy engine (engine=${configWithTagFilter.policy.engine})`
|
|
73223
72087
|
);
|
|
73224
|
-
const { loadEnterprisePolicyEngine
|
|
73225
|
-
context2.policyEngine = await
|
|
72088
|
+
const { loadEnterprisePolicyEngine } = await import("./enterprise/loader");
|
|
72089
|
+
context2.policyEngine = await loadEnterprisePolicyEngine(configWithTagFilter.policy);
|
|
73226
72090
|
logger.debug(
|
|
73227
72091
|
`[PolicyEngine] Initialized: ${context2.policyEngine?.constructor?.name || "unknown"}`
|
|
73228
72092
|
);
|
|
@@ -73376,9 +72240,9 @@ var init_state_machine_execution_engine = __esm({
|
|
|
73376
72240
|
}
|
|
73377
72241
|
const checkId = String(ev?.checkId || "unknown");
|
|
73378
72242
|
const threadKey = ev?.threadKey || (channel && threadTs ? `${channel}:${threadTs}` : "session");
|
|
73379
|
-
const baseDir = process.env.VISOR_SNAPSHOT_DIR ||
|
|
73380
|
-
|
|
73381
|
-
const filePath =
|
|
72243
|
+
const baseDir = process.env.VISOR_SNAPSHOT_DIR || path28.resolve(process.cwd(), ".visor", "snapshots");
|
|
72244
|
+
fs24.mkdirSync(baseDir, { recursive: true });
|
|
72245
|
+
const filePath = path28.join(baseDir, `${threadKey}-${checkId}.json`);
|
|
73382
72246
|
await this.saveSnapshotToFile(filePath);
|
|
73383
72247
|
logger.info(`[Snapshot] Saved run snapshot: ${filePath}`);
|
|
73384
72248
|
try {
|
|
@@ -73519,7 +72383,7 @@ var init_state_machine_execution_engine = __esm({
|
|
|
73519
72383
|
* Does not include secrets. Intended for debugging and future resume support.
|
|
73520
72384
|
*/
|
|
73521
72385
|
async saveSnapshotToFile(filePath) {
|
|
73522
|
-
const
|
|
72386
|
+
const fs25 = await import("fs/promises");
|
|
73523
72387
|
const ctx = this._lastContext;
|
|
73524
72388
|
const runner = this._lastRunner;
|
|
73525
72389
|
if (!ctx || !runner) {
|
|
@@ -73539,14 +72403,14 @@ var init_state_machine_execution_engine = __esm({
|
|
|
73539
72403
|
journal: entries,
|
|
73540
72404
|
requestedChecks: ctx.requestedChecks || []
|
|
73541
72405
|
};
|
|
73542
|
-
await
|
|
72406
|
+
await fs25.writeFile(filePath, JSON.stringify(payload, null, 2), "utf8");
|
|
73543
72407
|
}
|
|
73544
72408
|
/**
|
|
73545
72409
|
* Load a snapshot JSON from file and return it. Resume support can build on this.
|
|
73546
72410
|
*/
|
|
73547
72411
|
async loadSnapshotFromFile(filePath) {
|
|
73548
|
-
const
|
|
73549
|
-
const raw = await
|
|
72412
|
+
const fs25 = await import("fs/promises");
|
|
72413
|
+
const raw = await fs25.readFile(filePath, "utf8");
|
|
73550
72414
|
return JSON.parse(raw);
|
|
73551
72415
|
}
|
|
73552
72416
|
/**
|