@probelabs/visor 0.1.166 → 0.1.167-ee

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/dist/config.d.ts.map +1 -1
  2. package/dist/frontends/github-frontend.d.ts.map +1 -1
  3. package/dist/index.js +2182 -50
  4. package/dist/sdk/{check-provider-registry-V6C4LUYJ.mjs → check-provider-registry-6WR2SG66.mjs} +3 -3
  5. package/dist/sdk/{check-provider-registry-TGPICTHD.mjs → check-provider-registry-CWLPAM5U.mjs} +3 -3
  6. package/dist/sdk/{chunk-WSYVK6ML.mjs → chunk-2G2PJKHM.mjs} +297 -31
  7. package/dist/sdk/chunk-2G2PJKHM.mjs.map +1 -0
  8. package/dist/sdk/{chunk-KKGMGB4X.mjs → chunk-3LXYZ2OQ.mjs} +298 -32
  9. package/dist/sdk/chunk-3LXYZ2OQ.mjs.map +1 -0
  10. package/dist/sdk/{chunk-DEAPFYNX.mjs → chunk-KYBKVKBS.mjs} +7 -1
  11. package/dist/sdk/{chunk-DEAPFYNX.mjs.map → chunk-KYBKVKBS.mjs.map} +1 -1
  12. package/dist/sdk/{config-D6WF2U4B.mjs → config-DP5QU3XC.mjs} +2 -2
  13. package/dist/sdk/{github-frontend-P274ISBJ.mjs → github-frontend-VM52NX7N.mjs} +19 -1
  14. package/dist/sdk/{github-frontend-BPRRUIGB.mjs.map → github-frontend-VM52NX7N.mjs.map} +1 -1
  15. package/dist/sdk/{host-753E6PKF.mjs → host-7MGCKSHM.mjs} +2 -2
  16. package/dist/sdk/{host-AIMRV5YL.mjs → host-BTHRY6NS.mjs} +2 -2
  17. package/dist/sdk/knex-store-CRORFJE6.mjs +527 -0
  18. package/dist/sdk/knex-store-CRORFJE6.mjs.map +1 -0
  19. package/dist/sdk/loader-NJCF7DUS.mjs +89 -0
  20. package/dist/sdk/loader-NJCF7DUS.mjs.map +1 -0
  21. package/dist/sdk/opa-policy-engine-S2S2ULEI.mjs +655 -0
  22. package/dist/sdk/opa-policy-engine-S2S2ULEI.mjs.map +1 -0
  23. package/dist/sdk/{schedule-tool-OCZGLKMJ.mjs → schedule-tool-KKQ4W7KU.mjs} +3 -3
  24. package/dist/sdk/{schedule-tool-MQHISNJ6.mjs → schedule-tool-MPHHE2IM.mjs} +3 -3
  25. package/dist/sdk/{schedule-tool-handler-BGOL2TOP.mjs → schedule-tool-handler-6NUB2IHV.mjs} +3 -3
  26. package/dist/sdk/{schedule-tool-handler-TZYXM664.mjs → schedule-tool-handler-V7A4AQGS.mjs} +3 -3
  27. package/dist/sdk/sdk.js +1940 -276
  28. package/dist/sdk/sdk.js.map +1 -1
  29. package/dist/sdk/sdk.mjs +5 -5
  30. package/dist/sdk/validator-XTZJZZJH.mjs +134 -0
  31. package/dist/sdk/validator-XTZJZZJH.mjs.map +1 -0
  32. package/dist/sdk/{workflow-check-provider-3M5LXLLX.mjs → workflow-check-provider-N4ZTFOH6.mjs} +3 -3
  33. package/dist/sdk/{workflow-check-provider-QKHL6AFT.mjs → workflow-check-provider-PI7VJT25.mjs} +3 -3
  34. package/dist/state-machine/context/build-engine-context.d.ts.map +1 -1
  35. package/dist/utils/fair-concurrency-limiter.d.ts +56 -0
  36. package/dist/utils/fair-concurrency-limiter.d.ts.map +1 -0
  37. package/dist/utils/interactive-prompt.d.ts.map +1 -1
  38. package/package.json +1 -1
  39. package/dist/output/traces/run-2026-03-06T13-08-34-152Z.ndjson +0 -138
  40. package/dist/output/traces/run-2026-03-06T13-09-10-593Z.ndjson +0 -2235
  41. package/dist/sdk/check-provider-registry-WXEBJWXY.mjs +0 -29
  42. package/dist/sdk/chunk-HFCOZPAS.mjs +0 -443
  43. package/dist/sdk/chunk-HFCOZPAS.mjs.map +0 -1
  44. package/dist/sdk/chunk-KBTFMYZQ.mjs +0 -739
  45. package/dist/sdk/chunk-KBTFMYZQ.mjs.map +0 -1
  46. package/dist/sdk/chunk-KKGMGB4X.mjs.map +0 -1
  47. package/dist/sdk/chunk-OQ3CML4F.mjs +0 -1502
  48. package/dist/sdk/chunk-OQ3CML4F.mjs.map +0 -1
  49. package/dist/sdk/chunk-WSYVK6ML.mjs.map +0 -1
  50. package/dist/sdk/chunk-ZQR4AGS3.mjs +0 -44057
  51. package/dist/sdk/chunk-ZQR4AGS3.mjs.map +0 -1
  52. package/dist/sdk/failure-condition-evaluator-5EAESM44.mjs +0 -17
  53. package/dist/sdk/github-frontend-BPRRUIGB.mjs +0 -1368
  54. package/dist/sdk/github-frontend-P274ISBJ.mjs.map +0 -1
  55. package/dist/sdk/routing-QHWSMAIH.mjs +0 -25
  56. package/dist/sdk/schedule-tool-ZVOSSFN2.mjs +0 -35
  57. package/dist/sdk/schedule-tool-handler-4NCS4ARE.mjs +0 -39
  58. package/dist/sdk/schedule-tool-handler-4NCS4ARE.mjs.map +0 -1
  59. package/dist/sdk/schedule-tool-handler-BGOL2TOP.mjs.map +0 -1
  60. package/dist/sdk/schedule-tool-handler-TZYXM664.mjs.map +0 -1
  61. package/dist/sdk/trace-helpers-CTHTK6V5.mjs +0 -25
  62. package/dist/sdk/trace-helpers-CTHTK6V5.mjs.map +0 -1
  63. package/dist/sdk/workflow-check-provider-3M5LXLLX.mjs.map +0 -1
  64. package/dist/sdk/workflow-check-provider-QKHL6AFT.mjs.map +0 -1
  65. package/dist/sdk/workflow-check-provider-UTNO6XN6.mjs +0 -29
  66. package/dist/sdk/workflow-check-provider-UTNO6XN6.mjs.map +0 -1
  67. package/dist/traces/run-2026-03-06T13-08-34-152Z.ndjson +0 -138
  68. package/dist/traces/run-2026-03-06T13-09-10-593Z.ndjson +0 -2235
  69. /package/dist/sdk/{check-provider-registry-TGPICTHD.mjs.map → check-provider-registry-6WR2SG66.mjs.map} +0 -0
  70. /package/dist/sdk/{check-provider-registry-V6C4LUYJ.mjs.map → check-provider-registry-CWLPAM5U.mjs.map} +0 -0
  71. /package/dist/sdk/{check-provider-registry-WXEBJWXY.mjs.map → config-DP5QU3XC.mjs.map} +0 -0
  72. /package/dist/sdk/{host-753E6PKF.mjs.map → host-7MGCKSHM.mjs.map} +0 -0
  73. /package/dist/sdk/{host-AIMRV5YL.mjs.map → host-BTHRY6NS.mjs.map} +0 -0
  74. /package/dist/sdk/{config-D6WF2U4B.mjs.map → schedule-tool-KKQ4W7KU.mjs.map} +0 -0
  75. /package/dist/sdk/{failure-condition-evaluator-5EAESM44.mjs.map → schedule-tool-MPHHE2IM.mjs.map} +0 -0
  76. /package/dist/sdk/{routing-QHWSMAIH.mjs.map → schedule-tool-handler-6NUB2IHV.mjs.map} +0 -0
  77. /package/dist/sdk/{schedule-tool-MQHISNJ6.mjs.map → schedule-tool-handler-V7A4AQGS.mjs.map} +0 -0
  78. /package/dist/sdk/{schedule-tool-OCZGLKMJ.mjs.map → workflow-check-provider-N4ZTFOH6.mjs.map} +0 -0
  79. /package/dist/sdk/{schedule-tool-ZVOSSFN2.mjs.map → workflow-check-provider-PI7VJT25.mjs.map} +0 -0
package/dist/sdk/sdk.js CHANGED
@@ -646,7 +646,7 @@ var require_package = __commonJS({
646
646
  "package.json"(exports2, module2) {
647
647
  module2.exports = {
648
648
  name: "@probelabs/visor",
649
- version: "0.1.166",
649
+ version: "0.1.42",
650
650
  main: "dist/index.js",
651
651
  bin: {
652
652
  visor: "./dist/index.js"
@@ -864,11 +864,11 @@ function getTracer() {
864
864
  }
865
865
  async function withActiveSpan(name, attrs, fn) {
866
866
  const tracer = getTracer();
867
- return await new Promise((resolve15, reject) => {
867
+ return await new Promise((resolve19, reject) => {
868
868
  const callback = async (span) => {
869
869
  try {
870
870
  const res = await fn(span);
871
- resolve15(res);
871
+ resolve19(res);
872
872
  } catch (err) {
873
873
  try {
874
874
  if (err instanceof Error) span.recordException(err);
@@ -945,19 +945,19 @@ function __getOrCreateNdjsonPath() {
945
945
  try {
946
946
  if (process.env.VISOR_TELEMETRY_SINK && process.env.VISOR_TELEMETRY_SINK !== "file")
947
947
  return null;
948
- const path27 = require("path");
949
- const fs23 = require("fs");
948
+ const path31 = require("path");
949
+ const fs27 = require("fs");
950
950
  if (process.env.VISOR_FALLBACK_TRACE_FILE) {
951
951
  __ndjsonPath = process.env.VISOR_FALLBACK_TRACE_FILE;
952
- const dir = path27.dirname(__ndjsonPath);
953
- if (!fs23.existsSync(dir)) fs23.mkdirSync(dir, { recursive: true });
952
+ const dir = path31.dirname(__ndjsonPath);
953
+ if (!fs27.existsSync(dir)) fs27.mkdirSync(dir, { recursive: true });
954
954
  return __ndjsonPath;
955
955
  }
956
- const outDir = process.env.VISOR_TRACE_DIR || path27.join(process.cwd(), "output", "traces");
957
- if (!fs23.existsSync(outDir)) fs23.mkdirSync(outDir, { recursive: true });
956
+ const outDir = process.env.VISOR_TRACE_DIR || path31.join(process.cwd(), "output", "traces");
957
+ if (!fs27.existsSync(outDir)) fs27.mkdirSync(outDir, { recursive: true });
958
958
  if (!__ndjsonPath) {
959
959
  const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
960
- __ndjsonPath = path27.join(outDir, `${ts}.ndjson`);
960
+ __ndjsonPath = path31.join(outDir, `${ts}.ndjson`);
961
961
  }
962
962
  return __ndjsonPath;
963
963
  } catch {
@@ -966,11 +966,11 @@ function __getOrCreateNdjsonPath() {
966
966
  }
967
967
  function _appendRunMarker() {
968
968
  try {
969
- const fs23 = require("fs");
969
+ const fs27 = require("fs");
970
970
  const p = __getOrCreateNdjsonPath();
971
971
  if (!p) return;
972
972
  const line = { name: "visor.run", attributes: { started: true } };
973
- fs23.appendFileSync(p, JSON.stringify(line) + "\n", "utf8");
973
+ fs27.appendFileSync(p, JSON.stringify(line) + "\n", "utf8");
974
974
  } catch {
975
975
  }
976
976
  }
@@ -3193,7 +3193,7 @@ var init_failure_condition_evaluator = __esm({
3193
3193
  */
3194
3194
  evaluateExpression(condition, context2) {
3195
3195
  try {
3196
- const normalize4 = (expr) => {
3196
+ const normalize8 = (expr) => {
3197
3197
  const trimmed = expr.trim();
3198
3198
  if (!/[\n;]/.test(trimmed)) return trimmed;
3199
3199
  const parts = trimmed.split(/[\n;]+/).map((s) => s.trim()).filter((s) => s.length > 0 && !s.startsWith("//"));
@@ -3351,7 +3351,7 @@ var init_failure_condition_evaluator = __esm({
3351
3351
  try {
3352
3352
  exec2 = this.sandbox.compile(`return (${raw});`);
3353
3353
  } catch {
3354
- const normalizedExpr = normalize4(condition);
3354
+ const normalizedExpr = normalize8(condition);
3355
3355
  exec2 = this.sandbox.compile(`return (${normalizedExpr});`);
3356
3356
  }
3357
3357
  const result = exec2(scope).run();
@@ -3734,9 +3734,9 @@ function configureLiquidWithExtensions(liquid) {
3734
3734
  });
3735
3735
  liquid.registerFilter("get", (obj, pathExpr) => {
3736
3736
  if (obj == null) return void 0;
3737
- const path27 = typeof pathExpr === "string" ? pathExpr : String(pathExpr || "");
3738
- if (!path27) return obj;
3739
- const parts = path27.split(".");
3737
+ const path31 = typeof pathExpr === "string" ? pathExpr : String(pathExpr || "");
3738
+ if (!path31) return obj;
3739
+ const parts = path31.split(".");
3740
3740
  let cur = obj;
3741
3741
  for (const p of parts) {
3742
3742
  if (cur == null) return void 0;
@@ -3855,9 +3855,9 @@ function configureLiquidWithExtensions(liquid) {
3855
3855
  }
3856
3856
  }
3857
3857
  const defaultRole = typeof rolesCfg.default === "string" && rolesCfg.default.trim() ? rolesCfg.default.trim() : void 0;
3858
- const getNested = (obj, path27) => {
3859
- if (!obj || !path27) return void 0;
3860
- const parts = path27.split(".");
3858
+ const getNested = (obj, path31) => {
3859
+ if (!obj || !path31) return void 0;
3860
+ const parts = path31.split(".");
3861
3861
  let cur = obj;
3862
3862
  for (const p of parts) {
3863
3863
  if (cur == null) return void 0;
@@ -6409,8 +6409,8 @@ var init_dependency_gating = __esm({
6409
6409
  async function renderTemplateContent(checkId, checkConfig, reviewSummary) {
6410
6410
  try {
6411
6411
  const { createExtendedLiquid: createExtendedLiquid2 } = await Promise.resolve().then(() => (init_liquid_extensions(), liquid_extensions_exports));
6412
- const fs23 = await import("fs/promises");
6413
- const path27 = await import("path");
6412
+ const fs27 = await import("fs/promises");
6413
+ const path31 = await import("path");
6414
6414
  const schemaRaw = checkConfig.schema || "plain";
6415
6415
  const schema = typeof schemaRaw === "string" ? schemaRaw : "code-review";
6416
6416
  let templateContent;
@@ -6418,24 +6418,24 @@ async function renderTemplateContent(checkId, checkConfig, reviewSummary) {
6418
6418
  templateContent = String(checkConfig.template.content);
6419
6419
  } else if (checkConfig.template && checkConfig.template.file) {
6420
6420
  const file = String(checkConfig.template.file);
6421
- const resolved = path27.resolve(process.cwd(), file);
6422
- templateContent = await fs23.readFile(resolved, "utf-8");
6421
+ const resolved = path31.resolve(process.cwd(), file);
6422
+ templateContent = await fs27.readFile(resolved, "utf-8");
6423
6423
  } else if (schema && schema !== "plain") {
6424
6424
  const sanitized = String(schema).replace(/[^a-zA-Z0-9-]/g, "");
6425
6425
  if (sanitized) {
6426
6426
  const candidatePaths = [
6427
- path27.join(__dirname, "output", sanitized, "template.liquid"),
6427
+ path31.join(__dirname, "output", sanitized, "template.liquid"),
6428
6428
  // bundled: dist/output/
6429
- path27.join(__dirname, "..", "..", "output", sanitized, "template.liquid"),
6429
+ path31.join(__dirname, "..", "..", "output", sanitized, "template.liquid"),
6430
6430
  // source: output/
6431
- path27.join(process.cwd(), "output", sanitized, "template.liquid"),
6431
+ path31.join(process.cwd(), "output", sanitized, "template.liquid"),
6432
6432
  // fallback: cwd/output/
6433
- path27.join(process.cwd(), "dist", "output", sanitized, "template.liquid")
6433
+ path31.join(process.cwd(), "dist", "output", sanitized, "template.liquid")
6434
6434
  // fallback: cwd/dist/output/
6435
6435
  ];
6436
6436
  for (const p of candidatePaths) {
6437
6437
  try {
6438
- templateContent = await fs23.readFile(p, "utf-8");
6438
+ templateContent = await fs27.readFile(p, "utf-8");
6439
6439
  if (templateContent) break;
6440
6440
  } catch {
6441
6441
  }
@@ -6840,7 +6840,7 @@ async function processDiffWithOutline(diffContent) {
6840
6840
  }
6841
6841
  try {
6842
6842
  const originalProbePath = process.env.PROBE_PATH;
6843
- const fs23 = require("fs");
6843
+ const fs27 = require("fs");
6844
6844
  const possiblePaths = [
6845
6845
  // Relative to current working directory (most common in production)
6846
6846
  path6.join(process.cwd(), "node_modules/@probelabs/probe/bin/probe-binary"),
@@ -6851,7 +6851,7 @@ async function processDiffWithOutline(diffContent) {
6851
6851
  ];
6852
6852
  let probeBinaryPath;
6853
6853
  for (const candidatePath of possiblePaths) {
6854
- if (fs23.existsSync(candidatePath)) {
6854
+ if (fs27.existsSync(candidatePath)) {
6855
6855
  probeBinaryPath = candidatePath;
6856
6856
  break;
6857
6857
  }
@@ -6958,7 +6958,7 @@ async function renderMermaidToPng(mermaidCode) {
6958
6958
  if (chromiumPath) {
6959
6959
  env.PUPPETEER_EXECUTABLE_PATH = chromiumPath;
6960
6960
  }
6961
- const result = await new Promise((resolve15) => {
6961
+ const result = await new Promise((resolve19) => {
6962
6962
  const proc = (0, import_child_process.spawn)(
6963
6963
  "npx",
6964
6964
  [
@@ -6988,13 +6988,13 @@ async function renderMermaidToPng(mermaidCode) {
6988
6988
  });
6989
6989
  proc.on("close", (code) => {
6990
6990
  if (code === 0) {
6991
- resolve15({ success: true });
6991
+ resolve19({ success: true });
6992
6992
  } else {
6993
- resolve15({ success: false, error: stderr || `Exit code ${code}` });
6993
+ resolve19({ success: false, error: stderr || `Exit code ${code}` });
6994
6994
  }
6995
6995
  });
6996
6996
  proc.on("error", (err) => {
6997
- resolve15({ success: false, error: err.message });
6997
+ resolve19({ success: false, error: err.message });
6998
6998
  });
6999
6999
  });
7000
7000
  if (!result.success) {
@@ -8156,8 +8156,8 @@ ${schemaString}`);
8156
8156
  }
8157
8157
  if (process.env.VISOR_DEBUG_AI_SESSIONS === "true") {
8158
8158
  try {
8159
- const fs23 = require("fs");
8160
- const path27 = require("path");
8159
+ const fs27 = require("fs");
8160
+ const path31 = require("path");
8161
8161
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
8162
8162
  const provider = this.config.provider || "auto";
8163
8163
  const model = this.config.model || "default";
@@ -8271,20 +8271,20 @@ ${"=".repeat(60)}
8271
8271
  `;
8272
8272
  readableVersion += `${"=".repeat(60)}
8273
8273
  `;
8274
- const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS || path27.join(process.cwd(), "debug-artifacts");
8275
- if (!fs23.existsSync(debugArtifactsDir)) {
8276
- fs23.mkdirSync(debugArtifactsDir, { recursive: true });
8274
+ const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS || path31.join(process.cwd(), "debug-artifacts");
8275
+ if (!fs27.existsSync(debugArtifactsDir)) {
8276
+ fs27.mkdirSync(debugArtifactsDir, { recursive: true });
8277
8277
  }
8278
- const debugFile = path27.join(
8278
+ const debugFile = path31.join(
8279
8279
  debugArtifactsDir,
8280
8280
  `prompt-${_checkName || "unknown"}-${timestamp}.json`
8281
8281
  );
8282
- fs23.writeFileSync(debugFile, debugJson, "utf-8");
8283
- const readableFile = path27.join(
8282
+ fs27.writeFileSync(debugFile, debugJson, "utf-8");
8283
+ const readableFile = path31.join(
8284
8284
  debugArtifactsDir,
8285
8285
  `prompt-${_checkName || "unknown"}-${timestamp}.txt`
8286
8286
  );
8287
- fs23.writeFileSync(readableFile, readableVersion, "utf-8");
8287
+ fs27.writeFileSync(readableFile, readableVersion, "utf-8");
8288
8288
  log(`
8289
8289
  \u{1F4BE} Full debug info saved to:`);
8290
8290
  log(` JSON: ${debugFile}`);
@@ -8317,8 +8317,8 @@ ${"=".repeat(60)}
8317
8317
  log(`\u{1F4E4} Response length: ${response.length} characters`);
8318
8318
  if (process.env.VISOR_DEBUG_AI_SESSIONS === "true") {
8319
8319
  try {
8320
- const fs23 = require("fs");
8321
- const path27 = require("path");
8320
+ const fs27 = require("fs");
8321
+ const path31 = require("path");
8322
8322
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
8323
8323
  const agentAny2 = agent;
8324
8324
  let fullHistory = [];
@@ -8329,8 +8329,8 @@ ${"=".repeat(60)}
8329
8329
  } else if (agentAny2._messages) {
8330
8330
  fullHistory = agentAny2._messages;
8331
8331
  }
8332
- const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS || path27.join(process.cwd(), "debug-artifacts");
8333
- const sessionBase = path27.join(
8332
+ const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS || path31.join(process.cwd(), "debug-artifacts");
8333
+ const sessionBase = path31.join(
8334
8334
  debugArtifactsDir,
8335
8335
  `session-${_checkName || "unknown"}-${timestamp}`
8336
8336
  );
@@ -8342,7 +8342,7 @@ ${"=".repeat(60)}
8342
8342
  schema: effectiveSchema,
8343
8343
  totalMessages: fullHistory.length
8344
8344
  };
8345
- fs23.writeFileSync(sessionBase + ".json", JSON.stringify(sessionData, null, 2), "utf-8");
8345
+ fs27.writeFileSync(sessionBase + ".json", JSON.stringify(sessionData, null, 2), "utf-8");
8346
8346
  let readable = `=============================================================
8347
8347
  `;
8348
8348
  readable += `COMPLETE AI SESSION HISTORY (AFTER RESPONSE)
@@ -8369,7 +8369,7 @@ ${"=".repeat(60)}
8369
8369
  `;
8370
8370
  readable += content + "\n";
8371
8371
  });
8372
- fs23.writeFileSync(sessionBase + ".summary.txt", readable, "utf-8");
8372
+ fs27.writeFileSync(sessionBase + ".summary.txt", readable, "utf-8");
8373
8373
  log(`\u{1F4BE} Complete session history saved:`);
8374
8374
  log(` - Contains ALL ${fullHistory.length} messages (prompts + responses)`);
8375
8375
  } catch (error) {
@@ -8378,11 +8378,11 @@ ${"=".repeat(60)}
8378
8378
  }
8379
8379
  if (process.env.VISOR_DEBUG_AI_SESSIONS === "true") {
8380
8380
  try {
8381
- const fs23 = require("fs");
8382
- const path27 = require("path");
8381
+ const fs27 = require("fs");
8382
+ const path31 = require("path");
8383
8383
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
8384
- const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS || path27.join(process.cwd(), "debug-artifacts");
8385
- const responseFile = path27.join(
8384
+ const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS || path31.join(process.cwd(), "debug-artifacts");
8385
+ const responseFile = path31.join(
8386
8386
  debugArtifactsDir,
8387
8387
  `response-${_checkName || "unknown"}-${timestamp}.txt`
8388
8388
  );
@@ -8415,7 +8415,7 @@ ${"=".repeat(60)}
8415
8415
  `;
8416
8416
  responseContent += `${"=".repeat(60)}
8417
8417
  `;
8418
- fs23.writeFileSync(responseFile, responseContent, "utf-8");
8418
+ fs27.writeFileSync(responseFile, responseContent, "utf-8");
8419
8419
  log(`\u{1F4BE} Response saved to: ${responseFile}`);
8420
8420
  } catch (error) {
8421
8421
  log(`\u26A0\uFE0F Could not save response file: ${error}`);
@@ -8431,9 +8431,9 @@ ${"=".repeat(60)}
8431
8431
  await agentAny._telemetryConfig.shutdown();
8432
8432
  log(`\u{1F4CA} OpenTelemetry trace saved to: ${agentAny._traceFilePath}`);
8433
8433
  if (process.env.GITHUB_ACTIONS) {
8434
- const fs23 = require("fs");
8435
- if (fs23.existsSync(agentAny._traceFilePath)) {
8436
- const stats = fs23.statSync(agentAny._traceFilePath);
8434
+ const fs27 = require("fs");
8435
+ if (fs27.existsSync(agentAny._traceFilePath)) {
8436
+ const stats = fs27.statSync(agentAny._traceFilePath);
8437
8437
  console.log(
8438
8438
  `::notice title=AI Trace Saved::${agentAny._traceFilePath} (${stats.size} bytes)`
8439
8439
  );
@@ -8646,9 +8646,9 @@ ${schemaString}`);
8646
8646
  const model = this.config.model || "default";
8647
8647
  if (process.env.VISOR_DEBUG_AI_SESSIONS === "true") {
8648
8648
  try {
8649
- const fs23 = require("fs");
8650
- const path27 = require("path");
8651
- const os2 = require("os");
8649
+ const fs27 = require("fs");
8650
+ const path31 = require("path");
8651
+ const os3 = require("os");
8652
8652
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
8653
8653
  const debugData = {
8654
8654
  timestamp,
@@ -8720,19 +8720,19 @@ ${"=".repeat(60)}
8720
8720
  `;
8721
8721
  readableVersion += `${"=".repeat(60)}
8722
8722
  `;
8723
- const tempDir = os2.tmpdir();
8724
- const promptFile = path27.join(tempDir, `visor-prompt-${timestamp}.txt`);
8725
- fs23.writeFileSync(promptFile, prompt, "utf-8");
8723
+ const tempDir = os3.tmpdir();
8724
+ const promptFile = path31.join(tempDir, `visor-prompt-${timestamp}.txt`);
8725
+ fs27.writeFileSync(promptFile, prompt, "utf-8");
8726
8726
  log(`
8727
8727
  \u{1F4BE} Prompt saved to: ${promptFile}`);
8728
- const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS || path27.join(process.cwd(), "debug-artifacts");
8728
+ const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS || path31.join(process.cwd(), "debug-artifacts");
8729
8729
  try {
8730
- const base = path27.join(
8730
+ const base = path31.join(
8731
8731
  debugArtifactsDir,
8732
8732
  `prompt-${_checkName || "unknown"}-${timestamp}`
8733
8733
  );
8734
- fs23.writeFileSync(base + ".json", debugJson, "utf-8");
8735
- fs23.writeFileSync(base + ".summary.txt", readableVersion, "utf-8");
8734
+ fs27.writeFileSync(base + ".json", debugJson, "utf-8");
8735
+ fs27.writeFileSync(base + ".summary.txt", readableVersion, "utf-8");
8736
8736
  log(`
8737
8737
  \u{1F4BE} Full debug info saved to directory: ${debugArtifactsDir}`);
8738
8738
  } catch {
@@ -8777,8 +8777,8 @@ $ ${cliCommand}
8777
8777
  log(`\u{1F4E4} Response length: ${response.length} characters`);
8778
8778
  if (process.env.VISOR_DEBUG_AI_SESSIONS === "true") {
8779
8779
  try {
8780
- const fs23 = require("fs");
8781
- const path27 = require("path");
8780
+ const fs27 = require("fs");
8781
+ const path31 = require("path");
8782
8782
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
8783
8783
  const agentAny = agent;
8784
8784
  let fullHistory = [];
@@ -8789,8 +8789,8 @@ $ ${cliCommand}
8789
8789
  } else if (agentAny._messages) {
8790
8790
  fullHistory = agentAny._messages;
8791
8791
  }
8792
- const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS || path27.join(process.cwd(), "debug-artifacts");
8793
- const sessionBase = path27.join(
8792
+ const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS || path31.join(process.cwd(), "debug-artifacts");
8793
+ const sessionBase = path31.join(
8794
8794
  debugArtifactsDir,
8795
8795
  `session-${_checkName || "unknown"}-${timestamp}`
8796
8796
  );
@@ -8802,7 +8802,7 @@ $ ${cliCommand}
8802
8802
  schema: effectiveSchema,
8803
8803
  totalMessages: fullHistory.length
8804
8804
  };
8805
- fs23.writeFileSync(sessionBase + ".json", JSON.stringify(sessionData, null, 2), "utf-8");
8805
+ fs27.writeFileSync(sessionBase + ".json", JSON.stringify(sessionData, null, 2), "utf-8");
8806
8806
  let readable = `=============================================================
8807
8807
  `;
8808
8808
  readable += `COMPLETE AI SESSION HISTORY (AFTER RESPONSE)
@@ -8829,7 +8829,7 @@ ${"=".repeat(60)}
8829
8829
  `;
8830
8830
  readable += content + "\n";
8831
8831
  });
8832
- fs23.writeFileSync(sessionBase + ".summary.txt", readable, "utf-8");
8832
+ fs27.writeFileSync(sessionBase + ".summary.txt", readable, "utf-8");
8833
8833
  log(`\u{1F4BE} Complete session history saved:`);
8834
8834
  log(` - Contains ALL ${fullHistory.length} messages (prompts + responses)`);
8835
8835
  } catch (error) {
@@ -8838,11 +8838,11 @@ ${"=".repeat(60)}
8838
8838
  }
8839
8839
  if (process.env.VISOR_DEBUG_AI_SESSIONS === "true") {
8840
8840
  try {
8841
- const fs23 = require("fs");
8842
- const path27 = require("path");
8841
+ const fs27 = require("fs");
8842
+ const path31 = require("path");
8843
8843
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
8844
- const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS || path27.join(process.cwd(), "debug-artifacts");
8845
- const responseFile = path27.join(
8844
+ const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS || path31.join(process.cwd(), "debug-artifacts");
8845
+ const responseFile = path31.join(
8846
8846
  debugArtifactsDir,
8847
8847
  `response-${_checkName || "unknown"}-${timestamp}.txt`
8848
8848
  );
@@ -8875,7 +8875,7 @@ ${"=".repeat(60)}
8875
8875
  `;
8876
8876
  responseContent += `${"=".repeat(60)}
8877
8877
  `;
8878
- fs23.writeFileSync(responseFile, responseContent, "utf-8");
8878
+ fs27.writeFileSync(responseFile, responseContent, "utf-8");
8879
8879
  log(`\u{1F4BE} Response saved to: ${responseFile}`);
8880
8880
  } catch (error) {
8881
8881
  log(`\u26A0\uFE0F Could not save response file: ${error}`);
@@ -8893,9 +8893,9 @@ ${"=".repeat(60)}
8893
8893
  await telemetry.shutdown();
8894
8894
  log(`\u{1F4CA} OpenTelemetry trace saved to: ${traceFilePath}`);
8895
8895
  if (process.env.GITHUB_ACTIONS) {
8896
- const fs23 = require("fs");
8897
- if (fs23.existsSync(traceFilePath)) {
8898
- const stats = fs23.statSync(traceFilePath);
8896
+ const fs27 = require("fs");
8897
+ if (fs27.existsSync(traceFilePath)) {
8898
+ const stats = fs27.statSync(traceFilePath);
8899
8899
  console.log(
8900
8900
  `::notice title=AI Trace Saved::OpenTelemetry trace file size: ${stats.size} bytes`
8901
8901
  );
@@ -8933,8 +8933,8 @@ ${"=".repeat(60)}
8933
8933
  * Load schema content from schema files or inline definitions
8934
8934
  */
8935
8935
  async loadSchemaContent(schema) {
8936
- const fs23 = require("fs").promises;
8937
- const path27 = require("path");
8936
+ const fs27 = require("fs").promises;
8937
+ const path31 = require("path");
8938
8938
  if (typeof schema === "object" && schema !== null) {
8939
8939
  log("\u{1F4CB} Using inline schema object from configuration");
8940
8940
  return JSON.stringify(schema);
@@ -8947,14 +8947,14 @@ ${"=".repeat(60)}
8947
8947
  }
8948
8948
  } catch {
8949
8949
  }
8950
- if ((schema.startsWith("./") || schema.includes(".json")) && !path27.isAbsolute(schema)) {
8950
+ if ((schema.startsWith("./") || schema.includes(".json")) && !path31.isAbsolute(schema)) {
8951
8951
  if (schema.includes("..") || schema.includes("\0")) {
8952
8952
  throw new Error("Invalid schema path: path traversal not allowed");
8953
8953
  }
8954
8954
  try {
8955
- const schemaPath = path27.resolve(process.cwd(), schema);
8955
+ const schemaPath = path31.resolve(process.cwd(), schema);
8956
8956
  log(`\u{1F4CB} Loading custom schema from file: ${schemaPath}`);
8957
- const schemaContent = await fs23.readFile(schemaPath, "utf-8");
8957
+ const schemaContent = await fs27.readFile(schemaPath, "utf-8");
8958
8958
  return schemaContent.trim();
8959
8959
  } catch (error) {
8960
8960
  throw new Error(
@@ -8968,22 +8968,22 @@ ${"=".repeat(60)}
8968
8968
  }
8969
8969
  const candidatePaths = [
8970
8970
  // GitHub Action bundle location
8971
- path27.join(__dirname, "output", sanitizedSchemaName, "schema.json"),
8971
+ path31.join(__dirname, "output", sanitizedSchemaName, "schema.json"),
8972
8972
  // Historical fallback when src/output was inadvertently bundled as output1/
8973
- path27.join(__dirname, "output1", sanitizedSchemaName, "schema.json"),
8973
+ path31.join(__dirname, "output1", sanitizedSchemaName, "schema.json"),
8974
8974
  // Local dev (repo root)
8975
- path27.join(process.cwd(), "output", sanitizedSchemaName, "schema.json")
8975
+ path31.join(process.cwd(), "output", sanitizedSchemaName, "schema.json")
8976
8976
  ];
8977
8977
  for (const schemaPath of candidatePaths) {
8978
8978
  try {
8979
- const schemaContent = await fs23.readFile(schemaPath, "utf-8");
8979
+ const schemaContent = await fs27.readFile(schemaPath, "utf-8");
8980
8980
  return schemaContent.trim();
8981
8981
  } catch {
8982
8982
  }
8983
8983
  }
8984
- const distPath = path27.join(__dirname, "output", sanitizedSchemaName, "schema.json");
8985
- const distAltPath = path27.join(__dirname, "output1", sanitizedSchemaName, "schema.json");
8986
- const cwdPath = path27.join(process.cwd(), "output", sanitizedSchemaName, "schema.json");
8984
+ const distPath = path31.join(__dirname, "output", sanitizedSchemaName, "schema.json");
8985
+ const distAltPath = path31.join(__dirname, "output1", sanitizedSchemaName, "schema.json");
8986
+ const cwdPath = path31.join(process.cwd(), "output", sanitizedSchemaName, "schema.json");
8987
8987
  throw new Error(
8988
8988
  `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.`
8989
8989
  );
@@ -9228,7 +9228,7 @@ ${"=".repeat(60)}
9228
9228
  * Generate mock response for testing
9229
9229
  */
9230
9230
  async generateMockResponse(_prompt, _checkName, _schema) {
9231
- await new Promise((resolve15) => setTimeout(resolve15, 500));
9231
+ await new Promise((resolve19) => setTimeout(resolve19, 500));
9232
9232
  const name = (_checkName || "").toLowerCase();
9233
9233
  if (name.includes("extract-facts")) {
9234
9234
  const arr = Array.from({ length: 6 }, (_, i) => ({
@@ -9589,7 +9589,7 @@ var init_command_executor = __esm({
9589
9589
  * Execute command with stdin input
9590
9590
  */
9591
9591
  executeWithStdin(command, options) {
9592
- return new Promise((resolve15, reject) => {
9592
+ return new Promise((resolve19, reject) => {
9593
9593
  const childProcess = (0, import_child_process2.exec)(
9594
9594
  command,
9595
9595
  {
@@ -9601,7 +9601,7 @@ var init_command_executor = __esm({
9601
9601
  if (error && error.killed && (error.code === "ETIMEDOUT" || error.signal === "SIGTERM")) {
9602
9602
  reject(new Error(`Command timed out after ${options.timeout || 3e4}ms`));
9603
9603
  } else {
9604
- resolve15({
9604
+ resolve19({
9605
9605
  stdout: stdout || "",
9606
9606
  stderr: stderr || "",
9607
9607
  exitCode: error ? error.code || 1 : 0
@@ -15695,6 +15695,12 @@ ${errors}`);
15695
15695
  if (workflowData.on) {
15696
15696
  visorConfig.on = workflowData.on;
15697
15697
  }
15698
+ if (workflowData.sandboxes) {
15699
+ visorConfig.sandboxes = workflowData.sandboxes;
15700
+ }
15701
+ if (workflowData.sandbox) {
15702
+ visorConfig.sandbox = workflowData.sandbox;
15703
+ }
15698
15704
  logger.debug(
15699
15705
  `Standalone workflow config has ${Object.keys(workflowSteps).length} workflow steps as checks`
15700
15706
  );
@@ -17704,17 +17710,17 @@ var init_workflow_check_provider = __esm({
17704
17710
  * so it can be executed by the state machine as a nested workflow.
17705
17711
  */
17706
17712
  async loadWorkflowFromConfigPath(sourcePath, baseDir) {
17707
- const path27 = require("path");
17708
- const fs23 = require("fs");
17713
+ const path31 = require("path");
17714
+ const fs27 = require("fs");
17709
17715
  const yaml5 = require("js-yaml");
17710
- const resolved = path27.isAbsolute(sourcePath) ? sourcePath : path27.resolve(baseDir, sourcePath);
17711
- if (!fs23.existsSync(resolved)) {
17716
+ const resolved = path31.isAbsolute(sourcePath) ? sourcePath : path31.resolve(baseDir, sourcePath);
17717
+ if (!fs27.existsSync(resolved)) {
17712
17718
  throw new Error(`Workflow config not found at: ${resolved}`);
17713
17719
  }
17714
- const rawContent = fs23.readFileSync(resolved, "utf8");
17720
+ const rawContent = fs27.readFileSync(resolved, "utf8");
17715
17721
  const rawData = yaml5.load(rawContent);
17716
17722
  if (rawData.imports && Array.isArray(rawData.imports)) {
17717
- const configDir = path27.dirname(resolved);
17723
+ const configDir = path31.dirname(resolved);
17718
17724
  for (const source of rawData.imports) {
17719
17725
  const results = await this.registry.import(source, {
17720
17726
  basePath: configDir,
@@ -17744,8 +17750,8 @@ ${errors}`);
17744
17750
  if (!steps || Object.keys(steps).length === 0) {
17745
17751
  throw new Error(`Config '${resolved}' does not contain any steps to execute as a workflow`);
17746
17752
  }
17747
- const id = path27.basename(resolved).replace(/\.(ya?ml)$/i, "");
17748
- const name = loaded.name || `Workflow from ${path27.basename(resolved)}`;
17753
+ const id = path31.basename(resolved).replace(/\.(ya?ml)$/i, "");
17754
+ const name = loaded.name || `Workflow from ${path31.basename(resolved)}`;
17749
17755
  const workflowDef = {
17750
17756
  id,
17751
17757
  name,
@@ -18551,8 +18557,8 @@ async function createStoreBackend(storageConfig, haConfig) {
18551
18557
  case "mssql": {
18552
18558
  try {
18553
18559
  const loaderPath = "../../enterprise/loader";
18554
- const { loadEnterpriseStoreBackend } = await import(loaderPath);
18555
- return await loadEnterpriseStoreBackend(driver, storageConfig, haConfig);
18560
+ const { loadEnterpriseStoreBackend: loadEnterpriseStoreBackend2 } = await import(loaderPath);
18561
+ return await loadEnterpriseStoreBackend2(driver, storageConfig, haConfig);
18556
18562
  } catch (err) {
18557
18563
  const msg = err instanceof Error ? err.message : String(err);
18558
18564
  logger.error(`[StoreFactory] Failed to load enterprise ${driver} backend: ${msg}`);
@@ -21123,7 +21129,7 @@ var init_mcp_custom_sse_server = __esm({
21123
21129
  * Returns the actual bound port number
21124
21130
  */
21125
21131
  async start() {
21126
- return new Promise((resolve15, reject) => {
21132
+ return new Promise((resolve19, reject) => {
21127
21133
  try {
21128
21134
  this.server = import_http.default.createServer((req, res) => {
21129
21135
  this.handleRequest(req, res).catch((error) => {
@@ -21157,7 +21163,7 @@ var init_mcp_custom_sse_server = __esm({
21157
21163
  );
21158
21164
  }
21159
21165
  this.startKeepalive();
21160
- resolve15(this.port);
21166
+ resolve19(this.port);
21161
21167
  });
21162
21168
  } catch (error) {
21163
21169
  reject(error);
@@ -21220,7 +21226,7 @@ var init_mcp_custom_sse_server = __esm({
21220
21226
  logger.debug(
21221
21227
  `[CustomToolsSSEServer:${this.sessionId}] Grace period before stop: ${waitMs}ms (activeToolCalls=${this.activeToolCalls})`
21222
21228
  );
21223
- await new Promise((resolve15) => setTimeout(resolve15, waitMs));
21229
+ await new Promise((resolve19) => setTimeout(resolve19, waitMs));
21224
21230
  }
21225
21231
  }
21226
21232
  if (this.activeToolCalls > 0) {
@@ -21229,7 +21235,7 @@ var init_mcp_custom_sse_server = __esm({
21229
21235
  `[CustomToolsSSEServer:${this.sessionId}] Waiting for ${this.activeToolCalls} active tool call(s) before stop`
21230
21236
  );
21231
21237
  while (this.activeToolCalls > 0 && Date.now() - startedAt < effectiveDrainTimeoutMs) {
21232
- await new Promise((resolve15) => setTimeout(resolve15, 250));
21238
+ await new Promise((resolve19) => setTimeout(resolve19, 250));
21233
21239
  }
21234
21240
  if (this.activeToolCalls > 0) {
21235
21241
  logger.warn(
@@ -21254,21 +21260,21 @@ var init_mcp_custom_sse_server = __esm({
21254
21260
  }
21255
21261
  this.connections.clear();
21256
21262
  if (this.server) {
21257
- await new Promise((resolve15, reject) => {
21263
+ await new Promise((resolve19, reject) => {
21258
21264
  const timeout = setTimeout(() => {
21259
21265
  if (this.debug) {
21260
21266
  logger.debug(
21261
21267
  `[CustomToolsSSEServer:${this.sessionId}] Force closing server after timeout`
21262
21268
  );
21263
21269
  }
21264
- this.server?.close(() => resolve15());
21270
+ this.server?.close(() => resolve19());
21265
21271
  }, 5e3);
21266
21272
  this.server.close((error) => {
21267
21273
  clearTimeout(timeout);
21268
21274
  if (error) {
21269
21275
  reject(error);
21270
21276
  } else {
21271
- resolve15();
21277
+ resolve19();
21272
21278
  }
21273
21279
  });
21274
21280
  });
@@ -21703,7 +21709,7 @@ var init_mcp_custom_sse_server = __esm({
21703
21709
  logger.warn(
21704
21710
  `[CustomToolsSSEServer:${this.sessionId}] Tool ${toolName} failed (attempt ${attempt + 1}/${retryCount + 1}): ${errorMsg}. Retrying in ${delay}ms`
21705
21711
  );
21706
- await new Promise((resolve15) => setTimeout(resolve15, delay));
21712
+ await new Promise((resolve19) => setTimeout(resolve19, delay));
21707
21713
  attempt++;
21708
21714
  }
21709
21715
  }
@@ -22016,9 +22022,9 @@ var init_ai_check_provider = __esm({
22016
22022
  } else {
22017
22023
  resolvedPath = import_path7.default.resolve(process.cwd(), str);
22018
22024
  }
22019
- const fs23 = require("fs").promises;
22025
+ const fs27 = require("fs").promises;
22020
22026
  try {
22021
- const stat2 = await fs23.stat(resolvedPath);
22027
+ const stat2 = await fs27.stat(resolvedPath);
22022
22028
  return stat2.isFile();
22023
22029
  } catch {
22024
22030
  return hasFileExtension && (isRelativePath || isAbsolutePath || hasPathSeparators);
@@ -28120,14 +28126,14 @@ var require_util = __commonJS({
28120
28126
  }
28121
28127
  const port = url.port != null ? url.port : url.protocol === "https:" ? 443 : 80;
28122
28128
  let origin = url.origin != null ? url.origin : `${url.protocol}//${url.hostname}:${port}`;
28123
- let path27 = url.path != null ? url.path : `${url.pathname || ""}${url.search || ""}`;
28129
+ let path31 = url.path != null ? url.path : `${url.pathname || ""}${url.search || ""}`;
28124
28130
  if (origin.endsWith("/")) {
28125
28131
  origin = origin.substring(0, origin.length - 1);
28126
28132
  }
28127
- if (path27 && !path27.startsWith("/")) {
28128
- path27 = `/${path27}`;
28133
+ if (path31 && !path31.startsWith("/")) {
28134
+ path31 = `/${path31}`;
28129
28135
  }
28130
- url = new URL(origin + path27);
28136
+ url = new URL(origin + path31);
28131
28137
  }
28132
28138
  return url;
28133
28139
  }
@@ -29741,20 +29747,20 @@ var require_parseParams = __commonJS({
29741
29747
  var require_basename = __commonJS({
29742
29748
  "node_modules/@fastify/busboy/lib/utils/basename.js"(exports2, module2) {
29743
29749
  "use strict";
29744
- module2.exports = function basename4(path27) {
29745
- if (typeof path27 !== "string") {
29750
+ module2.exports = function basename4(path31) {
29751
+ if (typeof path31 !== "string") {
29746
29752
  return "";
29747
29753
  }
29748
- for (var i = path27.length - 1; i >= 0; --i) {
29749
- switch (path27.charCodeAt(i)) {
29754
+ for (var i = path31.length - 1; i >= 0; --i) {
29755
+ switch (path31.charCodeAt(i)) {
29750
29756
  case 47:
29751
29757
  // '/'
29752
29758
  case 92:
29753
- path27 = path27.slice(i + 1);
29754
- return path27 === ".." || path27 === "." ? "" : path27;
29759
+ path31 = path31.slice(i + 1);
29760
+ return path31 === ".." || path31 === "." ? "" : path31;
29755
29761
  }
29756
29762
  }
29757
- return path27 === ".." || path27 === "." ? "" : path27;
29763
+ return path31 === ".." || path31 === "." ? "" : path31;
29758
29764
  };
29759
29765
  }
29760
29766
  });
@@ -30758,11 +30764,11 @@ var require_util2 = __commonJS({
30758
30764
  var assert = require("assert");
30759
30765
  var { isUint8Array } = require("util/types");
30760
30766
  var supportedHashes = [];
30761
- var crypto2;
30767
+ var crypto4;
30762
30768
  try {
30763
- crypto2 = require("crypto");
30769
+ crypto4 = require("crypto");
30764
30770
  const possibleRelevantHashes = ["sha256", "sha384", "sha512"];
30765
- supportedHashes = crypto2.getHashes().filter((hash) => possibleRelevantHashes.includes(hash));
30771
+ supportedHashes = crypto4.getHashes().filter((hash) => possibleRelevantHashes.includes(hash));
30766
30772
  } catch {
30767
30773
  }
30768
30774
  function responseURL(response) {
@@ -31039,7 +31045,7 @@ var require_util2 = __commonJS({
31039
31045
  }
31040
31046
  }
31041
31047
  function bytesMatch(bytes, metadataList) {
31042
- if (crypto2 === void 0) {
31048
+ if (crypto4 === void 0) {
31043
31049
  return true;
31044
31050
  }
31045
31051
  const parsedMetadata = parseMetadata(metadataList);
@@ -31054,7 +31060,7 @@ var require_util2 = __commonJS({
31054
31060
  for (const item of metadata) {
31055
31061
  const algorithm = item.algo;
31056
31062
  const expectedValue = item.hash;
31057
- let actualValue = crypto2.createHash(algorithm).update(bytes).digest("base64");
31063
+ let actualValue = crypto4.createHash(algorithm).update(bytes).digest("base64");
31058
31064
  if (actualValue[actualValue.length - 1] === "=") {
31059
31065
  if (actualValue[actualValue.length - 2] === "=") {
31060
31066
  actualValue = actualValue.slice(0, -2);
@@ -31147,8 +31153,8 @@ var require_util2 = __commonJS({
31147
31153
  function createDeferredPromise() {
31148
31154
  let res;
31149
31155
  let rej;
31150
- const promise = new Promise((resolve15, reject) => {
31151
- res = resolve15;
31156
+ const promise = new Promise((resolve19, reject) => {
31157
+ res = resolve19;
31152
31158
  rej = reject;
31153
31159
  });
31154
31160
  return { promise, resolve: res, reject: rej };
@@ -32401,8 +32407,8 @@ var require_body = __commonJS({
32401
32407
  var { parseMIMEType, serializeAMimeType } = require_dataURL();
32402
32408
  var random;
32403
32409
  try {
32404
- const crypto2 = require("crypto");
32405
- random = (max) => crypto2.randomInt(0, max);
32410
+ const crypto4 = require("crypto");
32411
+ random = (max) => crypto4.randomInt(0, max);
32406
32412
  } catch {
32407
32413
  random = (max) => Math.floor(Math.random(max));
32408
32414
  }
@@ -32653,8 +32659,8 @@ Content-Type: ${value.type || "application/octet-stream"}\r
32653
32659
  });
32654
32660
  }
32655
32661
  });
32656
- const busboyResolve = new Promise((resolve15, reject) => {
32657
- busboy.on("finish", resolve15);
32662
+ const busboyResolve = new Promise((resolve19, reject) => {
32663
+ busboy.on("finish", resolve19);
32658
32664
  busboy.on("error", (err) => reject(new TypeError(err)));
32659
32665
  });
32660
32666
  if (this.body !== null) for await (const chunk of consumeBody(this[kState].body)) busboy.write(chunk);
@@ -32785,7 +32791,7 @@ var require_request = __commonJS({
32785
32791
  }
32786
32792
  var Request = class _Request {
32787
32793
  constructor(origin, {
32788
- path: path27,
32794
+ path: path31,
32789
32795
  method,
32790
32796
  body,
32791
32797
  headers,
@@ -32799,11 +32805,11 @@ var require_request = __commonJS({
32799
32805
  throwOnError,
32800
32806
  expectContinue
32801
32807
  }, handler) {
32802
- if (typeof path27 !== "string") {
32808
+ if (typeof path31 !== "string") {
32803
32809
  throw new InvalidArgumentError("path must be a string");
32804
- } else if (path27[0] !== "/" && !(path27.startsWith("http://") || path27.startsWith("https://")) && method !== "CONNECT") {
32810
+ } else if (path31[0] !== "/" && !(path31.startsWith("http://") || path31.startsWith("https://")) && method !== "CONNECT") {
32805
32811
  throw new InvalidArgumentError("path must be an absolute URL or start with a slash");
32806
- } else if (invalidPathRegex.exec(path27) !== null) {
32812
+ } else if (invalidPathRegex.exec(path31) !== null) {
32807
32813
  throw new InvalidArgumentError("invalid request path");
32808
32814
  }
32809
32815
  if (typeof method !== "string") {
@@ -32866,7 +32872,7 @@ var require_request = __commonJS({
32866
32872
  this.completed = false;
32867
32873
  this.aborted = false;
32868
32874
  this.upgrade = upgrade || null;
32869
- this.path = query ? util.buildURL(path27, query) : path27;
32875
+ this.path = query ? util.buildURL(path31, query) : path31;
32870
32876
  this.origin = origin;
32871
32877
  this.idempotent = idempotent == null ? method === "HEAD" || method === "GET" : idempotent;
32872
32878
  this.blocking = blocking == null ? false : blocking;
@@ -33188,9 +33194,9 @@ var require_dispatcher_base = __commonJS({
33188
33194
  }
33189
33195
  close(callback) {
33190
33196
  if (callback === void 0) {
33191
- return new Promise((resolve15, reject) => {
33197
+ return new Promise((resolve19, reject) => {
33192
33198
  this.close((err, data) => {
33193
- return err ? reject(err) : resolve15(data);
33199
+ return err ? reject(err) : resolve19(data);
33194
33200
  });
33195
33201
  });
33196
33202
  }
@@ -33228,12 +33234,12 @@ var require_dispatcher_base = __commonJS({
33228
33234
  err = null;
33229
33235
  }
33230
33236
  if (callback === void 0) {
33231
- return new Promise((resolve15, reject) => {
33237
+ return new Promise((resolve19, reject) => {
33232
33238
  this.destroy(err, (err2, data) => {
33233
33239
  return err2 ? (
33234
33240
  /* istanbul ignore next: should never error */
33235
33241
  reject(err2)
33236
- ) : resolve15(data);
33242
+ ) : resolve19(data);
33237
33243
  });
33238
33244
  });
33239
33245
  }
@@ -33874,9 +33880,9 @@ var require_RedirectHandler = __commonJS({
33874
33880
  return this.handler.onHeaders(statusCode, headers, resume, statusText);
33875
33881
  }
33876
33882
  const { origin, pathname, search } = util.parseURL(new URL(this.location, this.opts.origin && new URL(this.opts.path, this.opts.origin)));
33877
- const path27 = search ? `${pathname}${search}` : pathname;
33883
+ const path31 = search ? `${pathname}${search}` : pathname;
33878
33884
  this.opts.headers = cleanRequestHeaders(this.opts.headers, statusCode === 303, this.opts.origin !== origin);
33879
- this.opts.path = path27;
33885
+ this.opts.path = path31;
33880
33886
  this.opts.origin = origin;
33881
33887
  this.opts.maxRedirections = 0;
33882
33888
  this.opts.query = null;
@@ -34295,16 +34301,16 @@ var require_client = __commonJS({
34295
34301
  return this[kNeedDrain] < 2;
34296
34302
  }
34297
34303
  async [kClose]() {
34298
- return new Promise((resolve15) => {
34304
+ return new Promise((resolve19) => {
34299
34305
  if (!this[kSize]) {
34300
- resolve15(null);
34306
+ resolve19(null);
34301
34307
  } else {
34302
- this[kClosedResolve] = resolve15;
34308
+ this[kClosedResolve] = resolve19;
34303
34309
  }
34304
34310
  });
34305
34311
  }
34306
34312
  async [kDestroy](err) {
34307
- return new Promise((resolve15) => {
34313
+ return new Promise((resolve19) => {
34308
34314
  const requests = this[kQueue].splice(this[kPendingIdx]);
34309
34315
  for (let i = 0; i < requests.length; i++) {
34310
34316
  const request = requests[i];
@@ -34315,7 +34321,7 @@ var require_client = __commonJS({
34315
34321
  this[kClosedResolve]();
34316
34322
  this[kClosedResolve] = null;
34317
34323
  }
34318
- resolve15();
34324
+ resolve19();
34319
34325
  };
34320
34326
  if (this[kHTTP2Session] != null) {
34321
34327
  util.destroy(this[kHTTP2Session], err);
@@ -34895,7 +34901,7 @@ var require_client = __commonJS({
34895
34901
  });
34896
34902
  }
34897
34903
  try {
34898
- const socket = await new Promise((resolve15, reject) => {
34904
+ const socket = await new Promise((resolve19, reject) => {
34899
34905
  client[kConnector]({
34900
34906
  host,
34901
34907
  hostname,
@@ -34907,7 +34913,7 @@ var require_client = __commonJS({
34907
34913
  if (err) {
34908
34914
  reject(err);
34909
34915
  } else {
34910
- resolve15(socket2);
34916
+ resolve19(socket2);
34911
34917
  }
34912
34918
  });
34913
34919
  });
@@ -35118,7 +35124,7 @@ var require_client = __commonJS({
35118
35124
  writeH2(client, client[kHTTP2Session], request);
35119
35125
  return;
35120
35126
  }
35121
- const { body, method, path: path27, host, upgrade, headers, blocking, reset } = request;
35127
+ const { body, method, path: path31, host, upgrade, headers, blocking, reset } = request;
35122
35128
  const expectsPayload = method === "PUT" || method === "POST" || method === "PATCH";
35123
35129
  if (body && typeof body.read === "function") {
35124
35130
  body.read(0);
@@ -35168,7 +35174,7 @@ var require_client = __commonJS({
35168
35174
  if (blocking) {
35169
35175
  socket[kBlocking] = true;
35170
35176
  }
35171
- let header = `${method} ${path27} HTTP/1.1\r
35177
+ let header = `${method} ${path31} HTTP/1.1\r
35172
35178
  `;
35173
35179
  if (typeof host === "string") {
35174
35180
  header += `host: ${host}\r
@@ -35231,7 +35237,7 @@ upgrade: ${upgrade}\r
35231
35237
  return true;
35232
35238
  }
35233
35239
  function writeH2(client, session, request) {
35234
- const { body, method, path: path27, host, upgrade, expectContinue, signal, headers: reqHeaders } = request;
35240
+ const { body, method, path: path31, host, upgrade, expectContinue, signal, headers: reqHeaders } = request;
35235
35241
  let headers;
35236
35242
  if (typeof reqHeaders === "string") headers = Request[kHTTP2CopyHeaders](reqHeaders.trim());
35237
35243
  else headers = reqHeaders;
@@ -35274,7 +35280,7 @@ upgrade: ${upgrade}\r
35274
35280
  });
35275
35281
  return true;
35276
35282
  }
35277
- headers[HTTP2_HEADER_PATH] = path27;
35283
+ headers[HTTP2_HEADER_PATH] = path31;
35278
35284
  headers[HTTP2_HEADER_SCHEME] = "https";
35279
35285
  const expectsPayload = method === "PUT" || method === "POST" || method === "PATCH";
35280
35286
  if (body && typeof body.read === "function") {
@@ -35531,12 +35537,12 @@ upgrade: ${upgrade}\r
35531
35537
  cb();
35532
35538
  }
35533
35539
  }
35534
- const waitForDrain = () => new Promise((resolve15, reject) => {
35540
+ const waitForDrain = () => new Promise((resolve19, reject) => {
35535
35541
  assert(callback === null);
35536
35542
  if (socket[kError]) {
35537
35543
  reject(socket[kError]);
35538
35544
  } else {
35539
- callback = resolve15;
35545
+ callback = resolve19;
35540
35546
  }
35541
35547
  });
35542
35548
  if (client[kHTTPConnVersion] === "h2") {
@@ -35882,8 +35888,8 @@ var require_pool_base = __commonJS({
35882
35888
  if (this[kQueue].isEmpty()) {
35883
35889
  return Promise.all(this[kClients].map((c) => c.close()));
35884
35890
  } else {
35885
- return new Promise((resolve15) => {
35886
- this[kClosedResolve] = resolve15;
35891
+ return new Promise((resolve19) => {
35892
+ this[kClosedResolve] = resolve19;
35887
35893
  });
35888
35894
  }
35889
35895
  }
@@ -36461,7 +36467,7 @@ var require_readable = __commonJS({
36461
36467
  if (this.closed) {
36462
36468
  return Promise.resolve(null);
36463
36469
  }
36464
- return new Promise((resolve15, reject) => {
36470
+ return new Promise((resolve19, reject) => {
36465
36471
  const signalListenerCleanup = signal ? util.addAbortListener(signal, () => {
36466
36472
  this.destroy();
36467
36473
  }) : noop;
@@ -36470,7 +36476,7 @@ var require_readable = __commonJS({
36470
36476
  if (signal && signal.aborted) {
36471
36477
  reject(signal.reason || Object.assign(new Error("The operation was aborted"), { name: "AbortError" }));
36472
36478
  } else {
36473
- resolve15(null);
36479
+ resolve19(null);
36474
36480
  }
36475
36481
  }).on("error", noop).on("data", function(chunk) {
36476
36482
  limit -= chunk.length;
@@ -36492,11 +36498,11 @@ var require_readable = __commonJS({
36492
36498
  throw new TypeError("unusable");
36493
36499
  }
36494
36500
  assert(!stream[kConsume]);
36495
- return new Promise((resolve15, reject) => {
36501
+ return new Promise((resolve19, reject) => {
36496
36502
  stream[kConsume] = {
36497
36503
  type,
36498
36504
  stream,
36499
- resolve: resolve15,
36505
+ resolve: resolve19,
36500
36506
  reject,
36501
36507
  length: 0,
36502
36508
  body: []
@@ -36531,12 +36537,12 @@ var require_readable = __commonJS({
36531
36537
  }
36532
36538
  }
36533
36539
  function consumeEnd(consume2) {
36534
- const { type, body, resolve: resolve15, stream, length } = consume2;
36540
+ const { type, body, resolve: resolve19, stream, length } = consume2;
36535
36541
  try {
36536
36542
  if (type === "text") {
36537
- resolve15(toUSVString(Buffer.concat(body)));
36543
+ resolve19(toUSVString(Buffer.concat(body)));
36538
36544
  } else if (type === "json") {
36539
- resolve15(JSON.parse(Buffer.concat(body)));
36545
+ resolve19(JSON.parse(Buffer.concat(body)));
36540
36546
  } else if (type === "arrayBuffer") {
36541
36547
  const dst = new Uint8Array(length);
36542
36548
  let pos = 0;
@@ -36544,12 +36550,12 @@ var require_readable = __commonJS({
36544
36550
  dst.set(buf, pos);
36545
36551
  pos += buf.byteLength;
36546
36552
  }
36547
- resolve15(dst.buffer);
36553
+ resolve19(dst.buffer);
36548
36554
  } else if (type === "blob") {
36549
36555
  if (!Blob2) {
36550
36556
  Blob2 = require("buffer").Blob;
36551
36557
  }
36552
- resolve15(new Blob2(body, { type: stream[kContentType] }));
36558
+ resolve19(new Blob2(body, { type: stream[kContentType] }));
36553
36559
  }
36554
36560
  consumeFinish(consume2);
36555
36561
  } catch (err) {
@@ -36806,9 +36812,9 @@ var require_api_request = __commonJS({
36806
36812
  };
36807
36813
  function request(opts, callback) {
36808
36814
  if (callback === void 0) {
36809
- return new Promise((resolve15, reject) => {
36815
+ return new Promise((resolve19, reject) => {
36810
36816
  request.call(this, opts, (err, data) => {
36811
- return err ? reject(err) : resolve15(data);
36817
+ return err ? reject(err) : resolve19(data);
36812
36818
  });
36813
36819
  });
36814
36820
  }
@@ -36981,9 +36987,9 @@ var require_api_stream = __commonJS({
36981
36987
  };
36982
36988
  function stream(opts, factory, callback) {
36983
36989
  if (callback === void 0) {
36984
- return new Promise((resolve15, reject) => {
36990
+ return new Promise((resolve19, reject) => {
36985
36991
  stream.call(this, opts, factory, (err, data) => {
36986
- return err ? reject(err) : resolve15(data);
36992
+ return err ? reject(err) : resolve19(data);
36987
36993
  });
36988
36994
  });
36989
36995
  }
@@ -37264,9 +37270,9 @@ var require_api_upgrade = __commonJS({
37264
37270
  };
37265
37271
  function upgrade(opts, callback) {
37266
37272
  if (callback === void 0) {
37267
- return new Promise((resolve15, reject) => {
37273
+ return new Promise((resolve19, reject) => {
37268
37274
  upgrade.call(this, opts, (err, data) => {
37269
- return err ? reject(err) : resolve15(data);
37275
+ return err ? reject(err) : resolve19(data);
37270
37276
  });
37271
37277
  });
37272
37278
  }
@@ -37355,9 +37361,9 @@ var require_api_connect = __commonJS({
37355
37361
  };
37356
37362
  function connect(opts, callback) {
37357
37363
  if (callback === void 0) {
37358
- return new Promise((resolve15, reject) => {
37364
+ return new Promise((resolve19, reject) => {
37359
37365
  connect.call(this, opts, (err, data) => {
37360
- return err ? reject(err) : resolve15(data);
37366
+ return err ? reject(err) : resolve19(data);
37361
37367
  });
37362
37368
  });
37363
37369
  }
@@ -37517,20 +37523,20 @@ var require_mock_utils = __commonJS({
37517
37523
  }
37518
37524
  return true;
37519
37525
  }
37520
- function safeUrl(path27) {
37521
- if (typeof path27 !== "string") {
37522
- return path27;
37526
+ function safeUrl(path31) {
37527
+ if (typeof path31 !== "string") {
37528
+ return path31;
37523
37529
  }
37524
- const pathSegments = path27.split("?");
37530
+ const pathSegments = path31.split("?");
37525
37531
  if (pathSegments.length !== 2) {
37526
- return path27;
37532
+ return path31;
37527
37533
  }
37528
37534
  const qp = new URLSearchParams(pathSegments.pop());
37529
37535
  qp.sort();
37530
37536
  return [...pathSegments, qp.toString()].join("?");
37531
37537
  }
37532
- function matchKey(mockDispatch2, { path: path27, method, body, headers }) {
37533
- const pathMatch = matchValue(mockDispatch2.path, path27);
37538
+ function matchKey(mockDispatch2, { path: path31, method, body, headers }) {
37539
+ const pathMatch = matchValue(mockDispatch2.path, path31);
37534
37540
  const methodMatch = matchValue(mockDispatch2.method, method);
37535
37541
  const bodyMatch = typeof mockDispatch2.body !== "undefined" ? matchValue(mockDispatch2.body, body) : true;
37536
37542
  const headersMatch = matchHeaders(mockDispatch2, headers);
@@ -37548,7 +37554,7 @@ var require_mock_utils = __commonJS({
37548
37554
  function getMockDispatch(mockDispatches, key) {
37549
37555
  const basePath = key.query ? buildURL(key.path, key.query) : key.path;
37550
37556
  const resolvedPath = typeof basePath === "string" ? safeUrl(basePath) : basePath;
37551
- let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path: path27 }) => matchValue(safeUrl(path27), resolvedPath));
37557
+ let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path: path31 }) => matchValue(safeUrl(path31), resolvedPath));
37552
37558
  if (matchedMockDispatches.length === 0) {
37553
37559
  throw new MockNotMatchedError(`Mock dispatch not matched for path '${resolvedPath}'`);
37554
37560
  }
@@ -37585,9 +37591,9 @@ var require_mock_utils = __commonJS({
37585
37591
  }
37586
37592
  }
37587
37593
  function buildKey(opts) {
37588
- const { path: path27, method, body, headers, query } = opts;
37594
+ const { path: path31, method, body, headers, query } = opts;
37589
37595
  return {
37590
- path: path27,
37596
+ path: path31,
37591
37597
  method,
37592
37598
  body,
37593
37599
  headers,
@@ -38036,10 +38042,10 @@ var require_pending_interceptors_formatter = __commonJS({
38036
38042
  }
38037
38043
  format(pendingInterceptors) {
38038
38044
  const withPrettyHeaders = pendingInterceptors.map(
38039
- ({ method, path: path27, data: { statusCode }, persist, times, timesInvoked, origin }) => ({
38045
+ ({ method, path: path31, data: { statusCode }, persist, times, timesInvoked, origin }) => ({
38040
38046
  Method: method,
38041
38047
  Origin: origin,
38042
- Path: path27,
38048
+ Path: path31,
38043
38049
  "Status code": statusCode,
38044
38050
  Persistent: persist ? "\u2705" : "\u274C",
38045
38051
  Invocations: timesInvoked,
@@ -40980,7 +40986,7 @@ var require_fetch = __commonJS({
40980
40986
  async function dispatch({ body }) {
40981
40987
  const url = requestCurrentURL(request);
40982
40988
  const agent = fetchParams.controller.dispatcher;
40983
- return new Promise((resolve15, reject) => agent.dispatch(
40989
+ return new Promise((resolve19, reject) => agent.dispatch(
40984
40990
  {
40985
40991
  path: url.pathname + url.search,
40986
40992
  origin: url.origin,
@@ -41056,7 +41062,7 @@ var require_fetch = __commonJS({
41056
41062
  }
41057
41063
  }
41058
41064
  }
41059
- resolve15({
41065
+ resolve19({
41060
41066
  status,
41061
41067
  statusText,
41062
41068
  headersList: headers[kHeadersList],
@@ -41099,7 +41105,7 @@ var require_fetch = __commonJS({
41099
41105
  const val = headersList[n + 1].toString("latin1");
41100
41106
  headers[kHeadersList].append(key, val);
41101
41107
  }
41102
- resolve15({
41108
+ resolve19({
41103
41109
  status,
41104
41110
  statusText: STATUS_CODES[status],
41105
41111
  headersList: headers[kHeadersList],
@@ -42660,8 +42666,8 @@ var require_util6 = __commonJS({
42660
42666
  }
42661
42667
  }
42662
42668
  }
42663
- function validateCookiePath(path27) {
42664
- for (const char of path27) {
42669
+ function validateCookiePath(path31) {
42670
+ for (const char of path31) {
42665
42671
  const code = char.charCodeAt(0);
42666
42672
  if (code < 33 || char === ";") {
42667
42673
  throw new Error("Invalid cookie path");
@@ -43458,9 +43464,9 @@ var require_connection = __commonJS({
43458
43464
  channels.open = diagnosticsChannel.channel("undici:websocket:open");
43459
43465
  channels.close = diagnosticsChannel.channel("undici:websocket:close");
43460
43466
  channels.socketError = diagnosticsChannel.channel("undici:websocket:socket_error");
43461
- var crypto2;
43467
+ var crypto4;
43462
43468
  try {
43463
- crypto2 = require("crypto");
43469
+ crypto4 = require("crypto");
43464
43470
  } catch {
43465
43471
  }
43466
43472
  function establishWebSocketConnection(url, protocols, ws, onEstablish, options) {
@@ -43479,7 +43485,7 @@ var require_connection = __commonJS({
43479
43485
  const headersList = new Headers(options.headers)[kHeadersList];
43480
43486
  request.headersList = headersList;
43481
43487
  }
43482
- const keyValue = crypto2.randomBytes(16).toString("base64");
43488
+ const keyValue = crypto4.randomBytes(16).toString("base64");
43483
43489
  request.headersList.append("sec-websocket-key", keyValue);
43484
43490
  request.headersList.append("sec-websocket-version", "13");
43485
43491
  for (const protocol of protocols) {
@@ -43508,7 +43514,7 @@ var require_connection = __commonJS({
43508
43514
  return;
43509
43515
  }
43510
43516
  const secWSAccept = response.headersList.get("Sec-WebSocket-Accept");
43511
- const digest = crypto2.createHash("sha1").update(keyValue + uid).digest("base64");
43517
+ const digest = crypto4.createHash("sha1").update(keyValue + uid).digest("base64");
43512
43518
  if (secWSAccept !== digest) {
43513
43519
  failWebsocketConnection(ws, "Incorrect hash received in Sec-WebSocket-Accept header.");
43514
43520
  return;
@@ -43588,9 +43594,9 @@ var require_frame = __commonJS({
43588
43594
  "node_modules/undici/lib/websocket/frame.js"(exports2, module2) {
43589
43595
  "use strict";
43590
43596
  var { maxUnsigned16Bit } = require_constants5();
43591
- var crypto2;
43597
+ var crypto4;
43592
43598
  try {
43593
- crypto2 = require("crypto");
43599
+ crypto4 = require("crypto");
43594
43600
  } catch {
43595
43601
  }
43596
43602
  var WebsocketFrameSend = class {
@@ -43599,7 +43605,7 @@ var require_frame = __commonJS({
43599
43605
  */
43600
43606
  constructor(data) {
43601
43607
  this.frameData = data;
43602
- this.maskKey = crypto2.randomBytes(4);
43608
+ this.maskKey = crypto4.randomBytes(4);
43603
43609
  }
43604
43610
  createFrame(opcode) {
43605
43611
  const bodyLength = this.frameData?.byteLength ?? 0;
@@ -44341,11 +44347,11 @@ var require_undici = __commonJS({
44341
44347
  if (typeof opts.path !== "string") {
44342
44348
  throw new InvalidArgumentError("invalid opts.path");
44343
44349
  }
44344
- let path27 = opts.path;
44350
+ let path31 = opts.path;
44345
44351
  if (!opts.path.startsWith("/")) {
44346
- path27 = `/${path27}`;
44352
+ path31 = `/${path31}`;
44347
44353
  }
44348
- url = new URL(util.parseOrigin(url).origin + path27);
44354
+ url = new URL(util.parseOrigin(url).origin + path31);
44349
44355
  } else {
44350
44356
  if (!opts) {
44351
44357
  opts = typeof url === "object" ? url : {};
@@ -44894,7 +44900,7 @@ var init_mcp_check_provider = __esm({
44894
44900
  logger.warn(
44895
44901
  `MCP ${transportName} failed (attempt ${attempt + 1}/${maxRetries + 1}), retrying in ${delay}ms: ${error instanceof Error ? error.message : String(error)}`
44896
44902
  );
44897
- await new Promise((resolve15) => setTimeout(resolve15, delay));
44903
+ await new Promise((resolve19) => setTimeout(resolve19, delay));
44898
44904
  attempt += 1;
44899
44905
  } finally {
44900
44906
  try {
@@ -45176,7 +45182,27 @@ async function acquirePromptLock() {
45176
45182
  activePrompt = true;
45177
45183
  return;
45178
45184
  }
45179
- await new Promise((resolve15) => waiters.push(resolve15));
45185
+ console.error(
45186
+ `[human-input] Prompt queued, waiting for active prompt to finish (${waiters.length} already waiting).`
45187
+ );
45188
+ const queuedAt = Date.now();
45189
+ const reminder = setInterval(() => {
45190
+ const waited = Math.round((Date.now() - queuedAt) / 1e3);
45191
+ console.error(
45192
+ `[human-input] Still waiting for prompt lock (${waited}s, ${waiters.length} in queue).`
45193
+ );
45194
+ }, 1e4);
45195
+ try {
45196
+ await new Promise((resolve19) => waiters.push(resolve19));
45197
+ } finally {
45198
+ clearInterval(reminder);
45199
+ const waitedMs = Date.now() - queuedAt;
45200
+ if (waitedMs > 100) {
45201
+ console.error(
45202
+ `[human-input] Prompt lock acquired after ${Math.round(waitedMs / 1e3)}s wait.`
45203
+ );
45204
+ }
45205
+ }
45180
45206
  activePrompt = true;
45181
45207
  }
45182
45208
  function releasePromptLock() {
@@ -45186,7 +45212,7 @@ function releasePromptLock() {
45186
45212
  }
45187
45213
  async function interactivePrompt(options) {
45188
45214
  await acquirePromptLock();
45189
- return new Promise((resolve15, reject) => {
45215
+ return new Promise((resolve19, reject) => {
45190
45216
  const dbg = process.env.VISOR_DEBUG === "true";
45191
45217
  try {
45192
45218
  if (dbg) {
@@ -45273,12 +45299,12 @@ async function interactivePrompt(options) {
45273
45299
  };
45274
45300
  const finish = (value) => {
45275
45301
  cleanup();
45276
- resolve15(value);
45302
+ resolve19(value);
45277
45303
  };
45278
45304
  if (options.timeout && options.timeout > 0) {
45279
45305
  timeoutId = setTimeout(() => {
45280
45306
  cleanup();
45281
- if (defaultValue !== void 0) return resolve15(defaultValue);
45307
+ if (defaultValue !== void 0) return resolve19(defaultValue);
45282
45308
  return reject(new Error("Input timeout"));
45283
45309
  }, options.timeout);
45284
45310
  }
@@ -45410,7 +45436,7 @@ async function interactivePrompt(options) {
45410
45436
  });
45411
45437
  }
45412
45438
  async function simplePrompt(prompt) {
45413
- return new Promise((resolve15) => {
45439
+ return new Promise((resolve19) => {
45414
45440
  const rl = readline.createInterface({
45415
45441
  input: process.stdin,
45416
45442
  output: process.stdout
@@ -45426,7 +45452,7 @@ async function simplePrompt(prompt) {
45426
45452
  rl.question(`${prompt}
45427
45453
  > `, (answer) => {
45428
45454
  rl.close();
45429
- resolve15(answer.trim());
45455
+ resolve19(answer.trim());
45430
45456
  });
45431
45457
  });
45432
45458
  }
@@ -45594,7 +45620,7 @@ function isStdinAvailable() {
45594
45620
  return !process.stdin.isTTY;
45595
45621
  }
45596
45622
  async function readStdin(timeout, maxSize = 1024 * 1024) {
45597
- return new Promise((resolve15, reject) => {
45623
+ return new Promise((resolve19, reject) => {
45598
45624
  let data = "";
45599
45625
  let timeoutId;
45600
45626
  if (timeout) {
@@ -45621,7 +45647,7 @@ async function readStdin(timeout, maxSize = 1024 * 1024) {
45621
45647
  };
45622
45648
  const onEnd = () => {
45623
45649
  cleanup();
45624
- resolve15(data.trim());
45650
+ resolve19(data.trim());
45625
45651
  };
45626
45652
  const onError = (err) => {
45627
45653
  cleanup();
@@ -49747,23 +49773,23 @@ __export(renderer_schema_exports, {
49747
49773
  });
49748
49774
  async function loadRendererSchema(name) {
49749
49775
  try {
49750
- const fs23 = await import("fs/promises");
49751
- const path27 = await import("path");
49776
+ const fs27 = await import("fs/promises");
49777
+ const path31 = await import("path");
49752
49778
  const sanitized = String(name).replace(/[^a-zA-Z0-9-]/g, "");
49753
49779
  if (!sanitized) return void 0;
49754
49780
  const candidates = [
49755
49781
  // When bundled with ncc, __dirname is dist/ and output/ is at dist/output/
49756
- path27.join(__dirname, "output", sanitized, "schema.json"),
49782
+ path31.join(__dirname, "output", sanitized, "schema.json"),
49757
49783
  // When running from source, __dirname is src/state-machine/dispatch/ and output/ is at output/
49758
- path27.join(__dirname, "..", "..", "output", sanitized, "schema.json"),
49784
+ path31.join(__dirname, "..", "..", "output", sanitized, "schema.json"),
49759
49785
  // When running from a checkout with output/ folder copied to CWD
49760
- path27.join(process.cwd(), "output", sanitized, "schema.json"),
49786
+ path31.join(process.cwd(), "output", sanitized, "schema.json"),
49761
49787
  // Fallback: cwd/dist/output/
49762
- path27.join(process.cwd(), "dist", "output", sanitized, "schema.json")
49788
+ path31.join(process.cwd(), "dist", "output", sanitized, "schema.json")
49763
49789
  ];
49764
49790
  for (const p of candidates) {
49765
49791
  try {
49766
- const raw = await fs23.readFile(p, "utf-8");
49792
+ const raw = await fs27.readFile(p, "utf-8");
49767
49793
  return JSON.parse(raw);
49768
49794
  } catch {
49769
49795
  }
@@ -50065,7 +50091,29 @@ async function executeCheckGroup(checks, context2, state, maxParallelism, emitEv
50065
50091
  } catch {
50066
50092
  }
50067
50093
  if (pool.length >= maxParallelism) {
50068
- await Promise.race(pool);
50094
+ const activeCount = pool.filter((p) => !p._settled).length;
50095
+ logger.info(
50096
+ `[LevelDispatch] Check pool full (${activeCount}/${maxParallelism} active). Check "${checkId}" queued, waiting for a slot...`
50097
+ );
50098
+ const queuedAt = Date.now();
50099
+ const reminder = setInterval(() => {
50100
+ const waited = Math.round((Date.now() - queuedAt) / 1e3);
50101
+ const stillActive = pool.filter((p) => !p._settled).length;
50102
+ logger.info(
50103
+ `[LevelDispatch] Check "${checkId}" still queued (${waited}s). ${stillActive}/${maxParallelism} slots busy.`
50104
+ );
50105
+ }, 15e3);
50106
+ try {
50107
+ await Promise.race(pool);
50108
+ } finally {
50109
+ clearInterval(reminder);
50110
+ }
50111
+ const waitedMs = Date.now() - queuedAt;
50112
+ if (waitedMs > 100) {
50113
+ logger.info(
50114
+ `[LevelDispatch] Check "${checkId}" dequeued after ${Math.round(waitedMs / 1e3)}s wait.`
50115
+ );
50116
+ }
50069
50117
  pool.splice(
50070
50118
  0,
50071
50119
  pool.length,
@@ -52182,8 +52230,8 @@ function updateStats2(results, state, isForEachIteration = false) {
52182
52230
  async function renderTemplateContent2(checkId, checkConfig, reviewSummary) {
52183
52231
  try {
52184
52232
  const { createExtendedLiquid: createExtendedLiquid2 } = await Promise.resolve().then(() => (init_liquid_extensions(), liquid_extensions_exports));
52185
- const fs23 = await import("fs/promises");
52186
- const path27 = await import("path");
52233
+ const fs27 = await import("fs/promises");
52234
+ const path31 = await import("path");
52187
52235
  const schemaRaw = checkConfig.schema || "plain";
52188
52236
  const schema = typeof schemaRaw === "string" && !schemaRaw.includes("{{") && !schemaRaw.includes("{%") ? schemaRaw : typeof schemaRaw === "object" ? "code-review" : "plain";
52189
52237
  let templateContent;
@@ -52192,27 +52240,27 @@ async function renderTemplateContent2(checkId, checkConfig, reviewSummary) {
52192
52240
  logger.debug(`[LevelDispatch] Using inline template for ${checkId}`);
52193
52241
  } else if (checkConfig.template && checkConfig.template.file) {
52194
52242
  const file = String(checkConfig.template.file);
52195
- const resolved = path27.resolve(process.cwd(), file);
52196
- templateContent = await fs23.readFile(resolved, "utf-8");
52243
+ const resolved = path31.resolve(process.cwd(), file);
52244
+ templateContent = await fs27.readFile(resolved, "utf-8");
52197
52245
  logger.debug(`[LevelDispatch] Using template file for ${checkId}: ${resolved}`);
52198
52246
  } else if (schema && schema !== "plain") {
52199
52247
  const sanitized = String(schema).replace(/[^a-zA-Z0-9-]/g, "");
52200
52248
  if (sanitized) {
52201
52249
  const candidatePaths = [
52202
- path27.join(__dirname, "output", sanitized, "template.liquid"),
52250
+ path31.join(__dirname, "output", sanitized, "template.liquid"),
52203
52251
  // bundled: dist/output/
52204
- path27.join(__dirname, "..", "..", "output", sanitized, "template.liquid"),
52252
+ path31.join(__dirname, "..", "..", "output", sanitized, "template.liquid"),
52205
52253
  // source (from state-machine/states)
52206
- path27.join(__dirname, "..", "..", "..", "output", sanitized, "template.liquid"),
52254
+ path31.join(__dirname, "..", "..", "..", "output", sanitized, "template.liquid"),
52207
52255
  // source (alternate)
52208
- path27.join(process.cwd(), "output", sanitized, "template.liquid"),
52256
+ path31.join(process.cwd(), "output", sanitized, "template.liquid"),
52209
52257
  // fallback: cwd/output/
52210
- path27.join(process.cwd(), "dist", "output", sanitized, "template.liquid")
52258
+ path31.join(process.cwd(), "dist", "output", sanitized, "template.liquid")
52211
52259
  // fallback: cwd/dist/output/
52212
52260
  ];
52213
52261
  for (const p of candidatePaths) {
52214
52262
  try {
52215
- templateContent = await fs23.readFile(p, "utf-8");
52263
+ templateContent = await fs27.readFile(p, "utf-8");
52216
52264
  if (templateContent) {
52217
52265
  logger.debug(`[LevelDispatch] Using schema template for ${checkId}: ${p}`);
52218
52266
  break;
@@ -54352,8 +54400,8 @@ var init_workspace_manager = __esm({
54352
54400
  );
54353
54401
  if (this.cleanupRequested && this.activeOperations === 0) {
54354
54402
  logger.debug(`[Workspace] All references released, proceeding with deferred cleanup`);
54355
- for (const resolve15 of this.cleanupResolvers) {
54356
- resolve15();
54403
+ for (const resolve19 of this.cleanupResolvers) {
54404
+ resolve19();
54357
54405
  }
54358
54406
  this.cleanupResolvers = [];
54359
54407
  }
@@ -54510,19 +54558,19 @@ var init_workspace_manager = __esm({
54510
54558
  );
54511
54559
  this.cleanupRequested = true;
54512
54560
  await Promise.race([
54513
- new Promise((resolve15) => {
54561
+ new Promise((resolve19) => {
54514
54562
  if (this.activeOperations === 0) {
54515
- resolve15();
54563
+ resolve19();
54516
54564
  } else {
54517
- this.cleanupResolvers.push(resolve15);
54565
+ this.cleanupResolvers.push(resolve19);
54518
54566
  }
54519
54567
  }),
54520
- new Promise((resolve15) => {
54568
+ new Promise((resolve19) => {
54521
54569
  setTimeout(() => {
54522
54570
  logger.warn(
54523
54571
  `[Workspace] Cleanup timeout after ${timeout}ms, proceeding anyway (${this.activeOperations} operations still active)`
54524
54572
  );
54525
- resolve15();
54573
+ resolve19();
54526
54574
  }, timeout);
54527
54575
  })
54528
54576
  ]);
@@ -54853,6 +54901,223 @@ var init_workspace_manager = __esm({
54853
54901
  }
54854
54902
  });
54855
54903
 
54904
+ // src/utils/fair-concurrency-limiter.ts
54905
+ var FairConcurrencyLimiter;
54906
+ var init_fair_concurrency_limiter = __esm({
54907
+ "src/utils/fair-concurrency-limiter.ts"() {
54908
+ "use strict";
54909
+ init_logger();
54910
+ FairConcurrencyLimiter = class _FairConcurrencyLimiter {
54911
+ maxConcurrent;
54912
+ globalActive = 0;
54913
+ // Per-session FIFO queues
54914
+ sessionQueues = /* @__PURE__ */ new Map();
54915
+ // Round-robin order of sessions with waiting entries
54916
+ roundRobinSessions = [];
54917
+ roundRobinIndex = 0;
54918
+ // Per-session active count (for stats)
54919
+ sessionActive = /* @__PURE__ */ new Map();
54920
+ constructor(maxConcurrent) {
54921
+ this.maxConcurrent = maxConcurrent;
54922
+ }
54923
+ static getInstance(maxConcurrent) {
54924
+ const key = Symbol.for("visor.fairConcurrencyLimiter");
54925
+ let instance = globalThis[key];
54926
+ if (!instance) {
54927
+ instance = new _FairConcurrencyLimiter(maxConcurrent);
54928
+ globalThis[key] = instance;
54929
+ logger.info(`[FairLimiter] Created global fair concurrency limiter (max: ${maxConcurrent})`);
54930
+ } else if (instance.maxConcurrent !== maxConcurrent) {
54931
+ const old = instance.maxConcurrent;
54932
+ instance.maxConcurrent = maxConcurrent;
54933
+ logger.info(`[FairLimiter] Updated max concurrency: ${old} -> ${maxConcurrent}`);
54934
+ instance._processQueue();
54935
+ }
54936
+ return instance;
54937
+ }
54938
+ /**
54939
+ * Try to acquire a slot immediately (non-blocking).
54940
+ */
54941
+ tryAcquire(sessionId) {
54942
+ if (this.globalActive >= this.maxConcurrent) {
54943
+ return false;
54944
+ }
54945
+ this.globalActive++;
54946
+ const sid = sessionId || "__anonymous__";
54947
+ this.sessionActive.set(sid, (this.sessionActive.get(sid) || 0) + 1);
54948
+ return true;
54949
+ }
54950
+ /**
54951
+ * Acquire a slot, waiting in a fair queue if necessary.
54952
+ * Sessions are served round-robin so no single session can starve others.
54953
+ */
54954
+ async acquire(sessionId, _debug, queueTimeout) {
54955
+ const sid = sessionId || "__anonymous__";
54956
+ if (this.tryAcquire(sid)) {
54957
+ return true;
54958
+ }
54959
+ const totalQueued = this._totalQueued();
54960
+ const sessionsWaiting = this.sessionQueues.size;
54961
+ const sessionQueueLen = this.sessionQueues.get(sid)?.length || 0;
54962
+ logger.info(
54963
+ `[FairLimiter] Slot unavailable (${this.globalActive}/${this.maxConcurrent} active). Session "${sid}" queued (${sessionQueueLen} own + ${totalQueued} total across ${sessionsWaiting} sessions). Waiting...`
54964
+ );
54965
+ const queuedAt = Date.now();
54966
+ const effectiveTimeout = queueTimeout ?? 12e4;
54967
+ return new Promise((resolve19, reject) => {
54968
+ const entry = { resolve: resolve19, reject, queuedAt };
54969
+ entry.reminder = setInterval(() => {
54970
+ const waited = Math.round((Date.now() - queuedAt) / 1e3);
54971
+ const curQueued = this._totalQueued();
54972
+ const curSessions = this._waitingSessions();
54973
+ logger.info(
54974
+ `[FairLimiter] Session "${sid}" still waiting (${waited}s). ${this.globalActive}/${this.maxConcurrent} active, ${curQueued} queued across ${curSessions} sessions.`
54975
+ );
54976
+ }, 15e3);
54977
+ let queue = this.sessionQueues.get(sid);
54978
+ if (!queue) {
54979
+ queue = [];
54980
+ this.sessionQueues.set(sid, queue);
54981
+ this.roundRobinSessions.push(sid);
54982
+ }
54983
+ queue.push(entry);
54984
+ if (effectiveTimeout > 0) {
54985
+ setTimeout(() => {
54986
+ const q = this.sessionQueues.get(sid);
54987
+ if (q) {
54988
+ const idx = q.indexOf(entry);
54989
+ if (idx !== -1) {
54990
+ q.splice(idx, 1);
54991
+ if (q.length === 0) {
54992
+ this.sessionQueues.delete(sid);
54993
+ this._removeFromRoundRobin(sid);
54994
+ }
54995
+ this._clearReminder(entry);
54996
+ reject(
54997
+ new Error(
54998
+ `[FairLimiter] Queue timeout: session "${sid}" waited ${effectiveTimeout}ms for a slot`
54999
+ )
55000
+ );
55001
+ }
55002
+ }
55003
+ }, effectiveTimeout);
55004
+ }
55005
+ });
55006
+ }
55007
+ /**
55008
+ * Release a slot and grant the next one fairly (round-robin across sessions).
55009
+ */
55010
+ release(sessionId, _debug) {
55011
+ const sid = sessionId || "__anonymous__";
55012
+ this.globalActive = Math.max(0, this.globalActive - 1);
55013
+ const active = this.sessionActive.get(sid);
55014
+ if (active !== void 0) {
55015
+ if (active <= 1) {
55016
+ this.sessionActive.delete(sid);
55017
+ } else {
55018
+ this.sessionActive.set(sid, active - 1);
55019
+ }
55020
+ }
55021
+ this._processQueue();
55022
+ }
55023
+ /**
55024
+ * Round-robin queue processing: cycle through sessions and grant one slot per session per round.
55025
+ */
55026
+ _processQueue() {
55027
+ const toGrant = [];
55028
+ while (this.globalActive < this.maxConcurrent && this.roundRobinSessions.length > 0) {
55029
+ if (this.roundRobinIndex >= this.roundRobinSessions.length) {
55030
+ this.roundRobinIndex = 0;
55031
+ }
55032
+ const sid = this.roundRobinSessions[this.roundRobinIndex];
55033
+ const queue = this.sessionQueues.get(sid);
55034
+ if (!queue || queue.length === 0) {
55035
+ this.sessionQueues.delete(sid);
55036
+ this.roundRobinSessions.splice(this.roundRobinIndex, 1);
55037
+ continue;
55038
+ }
55039
+ const entry = queue.shift();
55040
+ if (queue.length === 0) {
55041
+ this.sessionQueues.delete(sid);
55042
+ this.roundRobinSessions.splice(this.roundRobinIndex, 1);
55043
+ } else {
55044
+ this.roundRobinIndex++;
55045
+ }
55046
+ this.globalActive++;
55047
+ this.sessionActive.set(sid, (this.sessionActive.get(sid) || 0) + 1);
55048
+ toGrant.push({ entry, sid });
55049
+ }
55050
+ for (const { entry, sid } of toGrant) {
55051
+ this._clearReminder(entry);
55052
+ const waitedMs = Date.now() - entry.queuedAt;
55053
+ if (waitedMs > 100) {
55054
+ logger.info(
55055
+ `[FairLimiter] Session "${sid}" acquired slot after ${Math.round(waitedMs / 1e3)}s wait.`
55056
+ );
55057
+ }
55058
+ setImmediate(() => entry.resolve(true));
55059
+ }
55060
+ }
55061
+ getStats() {
55062
+ const perSession = {};
55063
+ const allSessions = /* @__PURE__ */ new Set([...this.sessionActive.keys(), ...this.sessionQueues.keys()]);
55064
+ for (const sid of allSessions) {
55065
+ perSession[sid] = {
55066
+ active: this.sessionActive.get(sid) || 0,
55067
+ queued: this.sessionQueues.get(sid)?.length || 0
55068
+ };
55069
+ }
55070
+ return {
55071
+ globalActive: this.globalActive,
55072
+ maxConcurrent: this.maxConcurrent,
55073
+ queueSize: this._totalQueued(),
55074
+ waitingSessions: this._waitingSessions(),
55075
+ perSession
55076
+ };
55077
+ }
55078
+ cleanup() {
55079
+ for (const queue of this.sessionQueues.values()) {
55080
+ for (const entry of queue) {
55081
+ this._clearReminder(entry);
55082
+ }
55083
+ }
55084
+ this.sessionQueues.clear();
55085
+ this.roundRobinSessions = [];
55086
+ this.roundRobinIndex = 0;
55087
+ const key = Symbol.for("visor.fairConcurrencyLimiter");
55088
+ delete globalThis[key];
55089
+ }
55090
+ shutdown() {
55091
+ this.cleanup();
55092
+ }
55093
+ // -- helpers --
55094
+ _totalQueued() {
55095
+ let n = 0;
55096
+ for (const q of this.sessionQueues.values()) n += q.length;
55097
+ return n;
55098
+ }
55099
+ _waitingSessions() {
55100
+ return this.roundRobinSessions.length;
55101
+ }
55102
+ _removeFromRoundRobin(sid) {
55103
+ const idx = this.roundRobinSessions.indexOf(sid);
55104
+ if (idx !== -1) {
55105
+ this.roundRobinSessions.splice(idx, 1);
55106
+ if (this.roundRobinIndex > idx) {
55107
+ this.roundRobinIndex--;
55108
+ }
55109
+ }
55110
+ }
55111
+ _clearReminder(entry) {
55112
+ if (entry.reminder) {
55113
+ clearInterval(entry.reminder);
55114
+ entry.reminder = void 0;
55115
+ }
55116
+ }
55117
+ };
55118
+ }
55119
+ });
55120
+
54856
55121
  // src/state-machine/context/build-engine-context.ts
54857
55122
  var build_engine_context_exports = {};
54858
55123
  __export(build_engine_context_exports, {
@@ -54908,15 +55173,30 @@ function buildEngineContextForRun(workingDirectory, config, prInfo, debug, maxPa
54908
55173
  const journal = new ExecutionJournal();
54909
55174
  const memory = MemoryStore.getInstance(clonedConfig.memory);
54910
55175
  let sharedConcurrencyLimiter = void 0;
54911
- if (clonedConfig.max_ai_concurrency && _DelegationManager) {
54912
- sharedConcurrencyLimiter = new _DelegationManager({
54913
- maxConcurrent: clonedConfig.max_ai_concurrency,
54914
- maxPerSession: 999
54915
- // No per-session limit needed for global AI gating
54916
- });
54917
- logger.debug(
54918
- `[EngineContext] Created shared AI concurrency limiter (max: ${clonedConfig.max_ai_concurrency})`
54919
- );
55176
+ const sessionId = generateHumanId();
55177
+ if (clonedConfig.max_ai_concurrency) {
55178
+ const fairLimiter = FairConcurrencyLimiter.getInstance(clonedConfig.max_ai_concurrency);
55179
+ sharedConcurrencyLimiter = {
55180
+ async acquire(parentSessionId, _dbg, queueTimeout) {
55181
+ const sid = parentSessionId || sessionId;
55182
+ return fairLimiter.acquire(sid, _dbg, queueTimeout);
55183
+ },
55184
+ release(parentSessionId, _dbg) {
55185
+ const sid = parentSessionId || sessionId;
55186
+ return fairLimiter.release(sid, _dbg);
55187
+ },
55188
+ tryAcquire(parentSessionId) {
55189
+ const sid = parentSessionId || sessionId;
55190
+ return fairLimiter.tryAcquire(sid);
55191
+ },
55192
+ getStats() {
55193
+ return fairLimiter.getStats();
55194
+ },
55195
+ shutdown() {
55196
+ },
55197
+ cleanup() {
55198
+ }
55199
+ };
54920
55200
  }
54921
55201
  return {
54922
55202
  mode: "state-machine",
@@ -54926,7 +55206,7 @@ function buildEngineContextForRun(workingDirectory, config, prInfo, debug, maxPa
54926
55206
  memory,
54927
55207
  workingDirectory,
54928
55208
  originalWorkingDirectory: workingDirectory,
54929
- sessionId: generateHumanId(),
55209
+ sessionId,
54930
55210
  event: prInfo.eventType,
54931
55211
  debug,
54932
55212
  maxParallelism,
@@ -54980,7 +55260,6 @@ async function initializeWorkspace(context2) {
54980
55260
  return context2;
54981
55261
  }
54982
55262
  }
54983
- var _DelegationManager;
54984
55263
  var init_build_engine_context = __esm({
54985
55264
  "src/state-machine/context/build-engine-context.ts"() {
54986
55265
  "use strict";
@@ -54989,14 +55268,1381 @@ var init_build_engine_context = __esm({
54989
55268
  init_human_id();
54990
55269
  init_logger();
54991
55270
  init_workspace_manager();
54992
- _DelegationManager = null;
54993
- try {
54994
- const probe = require("@probelabs/probe");
54995
- if (probe && typeof probe.DelegationManager === "function") {
54996
- _DelegationManager = probe.DelegationManager;
55271
+ init_fair_concurrency_limiter();
55272
+ }
55273
+ });
55274
+
55275
+ // src/policy/default-engine.ts
55276
+ var DefaultPolicyEngine;
55277
+ var init_default_engine = __esm({
55278
+ "src/policy/default-engine.ts"() {
55279
+ "use strict";
55280
+ DefaultPolicyEngine = class {
55281
+ async initialize(_config) {
55282
+ }
55283
+ async evaluateCheckExecution(_checkId, _checkConfig) {
55284
+ return { allowed: true };
55285
+ }
55286
+ async evaluateToolInvocation(_serverName, _methodName, _transport) {
55287
+ return { allowed: true };
55288
+ }
55289
+ async evaluateCapabilities(_checkId, _capabilities) {
55290
+ return { allowed: true };
55291
+ }
55292
+ async shutdown() {
55293
+ }
55294
+ };
55295
+ }
55296
+ });
55297
+
55298
+ // src/enterprise/license/validator.ts
55299
+ var validator_exports = {};
55300
+ __export(validator_exports, {
55301
+ LicenseValidator: () => LicenseValidator
55302
+ });
55303
+ var crypto2, fs21, path25, LicenseValidator;
55304
+ var init_validator = __esm({
55305
+ "src/enterprise/license/validator.ts"() {
55306
+ "use strict";
55307
+ crypto2 = __toESM(require("crypto"));
55308
+ fs21 = __toESM(require("fs"));
55309
+ path25 = __toESM(require("path"));
55310
+ LicenseValidator = class _LicenseValidator {
55311
+ /** Ed25519 public key for license verification (PEM format). */
55312
+ static PUBLIC_KEY = "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAI/Zd08EFmgIdrDm/HXd0l3/5GBt7R1PrdvhdmEXhJlU=\n-----END PUBLIC KEY-----\n";
55313
+ cache = null;
55314
+ static CACHE_TTL = 5 * 60 * 1e3;
55315
+ // 5 minutes
55316
+ static GRACE_PERIOD = 72 * 3600 * 1e3;
55317
+ // 72 hours after expiry
55318
+ /**
55319
+ * Load and validate license from environment or file.
55320
+ *
55321
+ * Resolution order:
55322
+ * 1. VISOR_LICENSE env var (JWT string)
55323
+ * 2. VISOR_LICENSE_FILE env var (path to file)
55324
+ * 3. .visor-license in project root (cwd)
55325
+ * 4. .visor-license in ~/.config/visor/
55326
+ */
55327
+ async loadAndValidate() {
55328
+ if (this.cache && Date.now() - this.cache.validatedAt < _LicenseValidator.CACHE_TTL) {
55329
+ return this.cache.payload;
55330
+ }
55331
+ const token = this.resolveToken();
55332
+ if (!token) return null;
55333
+ const payload = this.verifyAndDecode(token);
55334
+ if (!payload) return null;
55335
+ this.cache = { payload, validatedAt: Date.now() };
55336
+ return payload;
55337
+ }
55338
+ /** Check if a specific feature is licensed */
55339
+ hasFeature(feature) {
55340
+ if (!this.cache) return false;
55341
+ return this.cache.payload.features.includes(feature);
55342
+ }
55343
+ /** Check if license is valid (with grace period) */
55344
+ isValid() {
55345
+ if (!this.cache) return false;
55346
+ const now = Date.now();
55347
+ const expiryMs = this.cache.payload.exp * 1e3;
55348
+ return now < expiryMs + _LicenseValidator.GRACE_PERIOD;
55349
+ }
55350
+ /** Check if the license is within its grace period (expired but still valid) */
55351
+ isInGracePeriod() {
55352
+ if (!this.cache) return false;
55353
+ const now = Date.now();
55354
+ const expiryMs = this.cache.payload.exp * 1e3;
55355
+ return now >= expiryMs && now < expiryMs + _LicenseValidator.GRACE_PERIOD;
55356
+ }
55357
+ resolveToken() {
55358
+ if (process.env.VISOR_LICENSE) {
55359
+ return process.env.VISOR_LICENSE.trim();
55360
+ }
55361
+ if (process.env.VISOR_LICENSE_FILE) {
55362
+ const resolved = path25.resolve(process.env.VISOR_LICENSE_FILE);
55363
+ const home2 = process.env.HOME || process.env.USERPROFILE || "";
55364
+ const allowedPrefixes = [path25.normalize(process.cwd())];
55365
+ if (home2) allowedPrefixes.push(path25.normalize(path25.join(home2, ".config", "visor")));
55366
+ let realPath;
55367
+ try {
55368
+ realPath = fs21.realpathSync(resolved);
55369
+ } catch {
55370
+ return null;
55371
+ }
55372
+ const isSafe = allowedPrefixes.some(
55373
+ (prefix) => realPath === prefix || realPath.startsWith(prefix + path25.sep)
55374
+ );
55375
+ if (!isSafe) return null;
55376
+ return this.readFile(realPath);
55377
+ }
55378
+ const cwdPath = path25.join(process.cwd(), ".visor-license");
55379
+ const cwdToken = this.readFile(cwdPath);
55380
+ if (cwdToken) return cwdToken;
55381
+ const home = process.env.HOME || process.env.USERPROFILE || "";
55382
+ if (home) {
55383
+ const configPath = path25.join(home, ".config", "visor", ".visor-license");
55384
+ const configToken = this.readFile(configPath);
55385
+ if (configToken) return configToken;
55386
+ }
55387
+ return null;
55388
+ }
55389
+ readFile(filePath) {
55390
+ try {
55391
+ return fs21.readFileSync(filePath, "utf-8").trim();
55392
+ } catch {
55393
+ return null;
55394
+ }
55395
+ }
55396
+ verifyAndDecode(token) {
55397
+ try {
55398
+ const parts = token.split(".");
55399
+ if (parts.length !== 3) return null;
55400
+ const [headerB64, payloadB64, signatureB64] = parts;
55401
+ const header = JSON.parse(Buffer.from(headerB64, "base64url").toString());
55402
+ if (header.alg !== "EdDSA") return null;
55403
+ const data = `${headerB64}.${payloadB64}`;
55404
+ const signature = Buffer.from(signatureB64, "base64url");
55405
+ const publicKey = crypto2.createPublicKey(_LicenseValidator.PUBLIC_KEY);
55406
+ if (publicKey.asymmetricKeyType !== "ed25519") {
55407
+ return null;
55408
+ }
55409
+ const isValid = crypto2.verify(null, Buffer.from(data), publicKey, signature);
55410
+ if (!isValid) return null;
55411
+ const payload = JSON.parse(Buffer.from(payloadB64, "base64url").toString());
55412
+ if (!payload.org || !Array.isArray(payload.features) || typeof payload.exp !== "number" || typeof payload.iat !== "number" || !payload.sub) {
55413
+ return null;
55414
+ }
55415
+ const now = Date.now();
55416
+ const expiryMs = payload.exp * 1e3;
55417
+ if (now >= expiryMs + _LicenseValidator.GRACE_PERIOD) {
55418
+ return null;
55419
+ }
55420
+ return payload;
55421
+ } catch {
55422
+ return null;
55423
+ }
55424
+ }
55425
+ };
55426
+ }
55427
+ });
55428
+
55429
+ // src/enterprise/policy/opa-compiler.ts
55430
+ var fs22, path26, os2, crypto3, import_child_process8, OpaCompiler;
55431
+ var init_opa_compiler = __esm({
55432
+ "src/enterprise/policy/opa-compiler.ts"() {
55433
+ "use strict";
55434
+ fs22 = __toESM(require("fs"));
55435
+ path26 = __toESM(require("path"));
55436
+ os2 = __toESM(require("os"));
55437
+ crypto3 = __toESM(require("crypto"));
55438
+ import_child_process8 = require("child_process");
55439
+ OpaCompiler = class _OpaCompiler {
55440
+ static CACHE_DIR = path26.join(os2.tmpdir(), "visor-opa-cache");
55441
+ /**
55442
+ * Resolve the input paths to WASM bytes.
55443
+ *
55444
+ * Strategy:
55445
+ * 1. If any path is a .wasm file, read it directly
55446
+ * 2. If a directory contains policy.wasm, read it
55447
+ * 3. Otherwise, collect all .rego files and auto-compile via `opa build`
55448
+ */
55449
+ async resolveWasmBytes(paths) {
55450
+ const regoFiles = [];
55451
+ for (const p of paths) {
55452
+ const resolved = path26.resolve(p);
55453
+ if (path26.normalize(resolved).includes("..")) {
55454
+ throw new Error(`Policy path contains traversal sequences: ${p}`);
55455
+ }
55456
+ if (resolved.endsWith(".wasm") && fs22.existsSync(resolved)) {
55457
+ return fs22.readFileSync(resolved);
55458
+ }
55459
+ if (!fs22.existsSync(resolved)) continue;
55460
+ const stat2 = fs22.statSync(resolved);
55461
+ if (stat2.isDirectory()) {
55462
+ const wasmCandidate = path26.join(resolved, "policy.wasm");
55463
+ if (fs22.existsSync(wasmCandidate)) {
55464
+ return fs22.readFileSync(wasmCandidate);
55465
+ }
55466
+ const files = fs22.readdirSync(resolved);
55467
+ for (const f of files) {
55468
+ if (f.endsWith(".rego")) {
55469
+ regoFiles.push(path26.join(resolved, f));
55470
+ }
55471
+ }
55472
+ } else if (resolved.endsWith(".rego")) {
55473
+ regoFiles.push(resolved);
55474
+ }
55475
+ }
55476
+ if (regoFiles.length === 0) {
55477
+ throw new Error(
55478
+ `OPA WASM evaluator: no .wasm bundle or .rego files found in: ${paths.join(", ")}`
55479
+ );
55480
+ }
55481
+ return this.compileRego(regoFiles);
55482
+ }
55483
+ /**
55484
+ * Auto-compile .rego files to a WASM bundle using the `opa` CLI.
55485
+ *
55486
+ * Caches the compiled bundle based on a content hash of all input .rego files
55487
+ * so subsequent runs skip compilation if policies haven't changed.
55488
+ */
55489
+ compileRego(regoFiles) {
55490
+ try {
55491
+ (0, import_child_process8.execFileSync)("opa", ["version"], { stdio: "pipe" });
55492
+ } catch {
55493
+ throw new Error(
55494
+ "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(" ")
55495
+ );
55496
+ }
55497
+ const hash = crypto3.createHash("sha256");
55498
+ for (const f of regoFiles.sort()) {
55499
+ hash.update(fs22.readFileSync(f));
55500
+ hash.update(f);
55501
+ }
55502
+ const cacheKey = hash.digest("hex").slice(0, 16);
55503
+ const cacheDir = _OpaCompiler.CACHE_DIR;
55504
+ const cachedWasm = path26.join(cacheDir, `${cacheKey}.wasm`);
55505
+ if (fs22.existsSync(cachedWasm)) {
55506
+ return fs22.readFileSync(cachedWasm);
55507
+ }
55508
+ fs22.mkdirSync(cacheDir, { recursive: true });
55509
+ const bundleTar = path26.join(cacheDir, `${cacheKey}-bundle.tar.gz`);
55510
+ try {
55511
+ const args = [
55512
+ "build",
55513
+ "-t",
55514
+ "wasm",
55515
+ "-e",
55516
+ "visor",
55517
+ // entrypoint: the visor package tree
55518
+ "-o",
55519
+ bundleTar,
55520
+ ...regoFiles
55521
+ ];
55522
+ (0, import_child_process8.execFileSync)("opa", args, {
55523
+ stdio: "pipe",
55524
+ timeout: 3e4
55525
+ });
55526
+ } catch (err) {
55527
+ const stderr = err?.stderr?.toString() || "";
55528
+ throw new Error(
55529
+ `Failed to compile .rego files to WASM:
55530
+ ${stderr}
55531
+ Ensure your .rego files are valid and the \`opa\` CLI is installed.`
55532
+ );
55533
+ }
55534
+ try {
55535
+ (0, import_child_process8.execFileSync)("tar", ["-xzf", bundleTar, "-C", cacheDir, "/policy.wasm"], {
55536
+ stdio: "pipe"
55537
+ });
55538
+ const extractedWasm = path26.join(cacheDir, "policy.wasm");
55539
+ if (fs22.existsSync(extractedWasm)) {
55540
+ fs22.renameSync(extractedWasm, cachedWasm);
55541
+ }
55542
+ } catch {
55543
+ try {
55544
+ (0, import_child_process8.execFileSync)("tar", ["-xzf", bundleTar, "-C", cacheDir, "policy.wasm"], {
55545
+ stdio: "pipe"
55546
+ });
55547
+ const extractedWasm = path26.join(cacheDir, "policy.wasm");
55548
+ if (fs22.existsSync(extractedWasm)) {
55549
+ fs22.renameSync(extractedWasm, cachedWasm);
55550
+ }
55551
+ } catch (err2) {
55552
+ throw new Error(`Failed to extract policy.wasm from OPA bundle: ${err2?.message || err2}`);
55553
+ }
55554
+ }
55555
+ try {
55556
+ fs22.unlinkSync(bundleTar);
55557
+ } catch {
55558
+ }
55559
+ if (!fs22.existsSync(cachedWasm)) {
55560
+ throw new Error("OPA build succeeded but policy.wasm was not found in the bundle");
55561
+ }
55562
+ return fs22.readFileSync(cachedWasm);
55563
+ }
55564
+ };
55565
+ }
55566
+ });
55567
+
55568
+ // src/enterprise/policy/opa-wasm-evaluator.ts
55569
+ var fs23, path27, OpaWasmEvaluator;
55570
+ var init_opa_wasm_evaluator = __esm({
55571
+ "src/enterprise/policy/opa-wasm-evaluator.ts"() {
55572
+ "use strict";
55573
+ fs23 = __toESM(require("fs"));
55574
+ path27 = __toESM(require("path"));
55575
+ init_opa_compiler();
55576
+ OpaWasmEvaluator = class {
55577
+ policy = null;
55578
+ dataDocument = {};
55579
+ compiler = new OpaCompiler();
55580
+ async initialize(rulesPath) {
55581
+ const paths = Array.isArray(rulesPath) ? rulesPath : [rulesPath];
55582
+ const wasmBytes = await this.compiler.resolveWasmBytes(paths);
55583
+ try {
55584
+ const { createRequire } = require("module");
55585
+ const runtimeRequire = createRequire(__filename);
55586
+ const opaWasm = runtimeRequire("@open-policy-agent/opa-wasm");
55587
+ const loadPolicy = opaWasm.loadPolicy || opaWasm.default?.loadPolicy;
55588
+ if (!loadPolicy) {
55589
+ throw new Error("loadPolicy not found in @open-policy-agent/opa-wasm");
55590
+ }
55591
+ this.policy = await loadPolicy(wasmBytes);
55592
+ } catch (err) {
55593
+ if (err?.code === "MODULE_NOT_FOUND" || err?.code === "ERR_MODULE_NOT_FOUND") {
55594
+ throw new Error(
55595
+ "OPA WASM evaluator requires @open-policy-agent/opa-wasm. Install it with: npm install @open-policy-agent/opa-wasm"
55596
+ );
55597
+ }
55598
+ throw err;
55599
+ }
55600
+ }
55601
+ /**
55602
+ * Load external data from a JSON file to use as the OPA data document.
55603
+ * The loaded data will be passed to `policy.setData()` during evaluation,
55604
+ * making it available in Rego via `data.<key>`.
55605
+ */
55606
+ loadData(dataPath) {
55607
+ const resolved = path27.resolve(dataPath);
55608
+ if (path27.normalize(resolved).includes("..")) {
55609
+ throw new Error(`Data path contains traversal sequences: ${dataPath}`);
55610
+ }
55611
+ if (!fs23.existsSync(resolved)) {
55612
+ throw new Error(`OPA data file not found: ${resolved}`);
55613
+ }
55614
+ const stat2 = fs23.statSync(resolved);
55615
+ if (stat2.size > 10 * 1024 * 1024) {
55616
+ throw new Error(`OPA data file exceeds 10MB limit: ${resolved} (${stat2.size} bytes)`);
55617
+ }
55618
+ const raw = fs23.readFileSync(resolved, "utf-8");
55619
+ try {
55620
+ const parsed = JSON.parse(raw);
55621
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
55622
+ throw new Error("OPA data file must contain a JSON object (not an array or primitive)");
55623
+ }
55624
+ this.dataDocument = parsed;
55625
+ } catch (err) {
55626
+ if (err.message.startsWith("OPA data file must")) {
55627
+ throw err;
55628
+ }
55629
+ throw new Error(`Failed to parse OPA data file ${resolved}: ${err.message}`);
55630
+ }
55631
+ }
55632
+ async evaluate(input) {
55633
+ if (!this.policy) {
55634
+ throw new Error("OPA WASM evaluator not initialized");
55635
+ }
55636
+ this.policy.setData(this.dataDocument);
55637
+ const resultSet = this.policy.evaluate(input);
55638
+ if (Array.isArray(resultSet) && resultSet.length > 0) {
55639
+ return resultSet[0].result;
55640
+ }
55641
+ return void 0;
55642
+ }
55643
+ async shutdown() {
55644
+ if (this.policy) {
55645
+ if (typeof this.policy.close === "function") {
55646
+ try {
55647
+ this.policy.close();
55648
+ } catch {
55649
+ }
55650
+ } else if (typeof this.policy.free === "function") {
55651
+ try {
55652
+ this.policy.free();
55653
+ } catch {
55654
+ }
55655
+ }
55656
+ }
55657
+ this.policy = null;
55658
+ }
55659
+ };
55660
+ }
55661
+ });
55662
+
55663
+ // src/enterprise/policy/opa-http-evaluator.ts
55664
+ var OpaHttpEvaluator;
55665
+ var init_opa_http_evaluator = __esm({
55666
+ "src/enterprise/policy/opa-http-evaluator.ts"() {
55667
+ "use strict";
55668
+ OpaHttpEvaluator = class {
55669
+ baseUrl;
55670
+ timeout;
55671
+ constructor(baseUrl, timeout = 5e3) {
55672
+ let parsed;
55673
+ try {
55674
+ parsed = new URL(baseUrl);
55675
+ } catch {
55676
+ throw new Error(`OPA HTTP evaluator: invalid URL: ${baseUrl}`);
55677
+ }
55678
+ if (!["http:", "https:"].includes(parsed.protocol)) {
55679
+ throw new Error(
55680
+ `OPA HTTP evaluator: url must use http:// or https:// protocol, got: ${baseUrl}`
55681
+ );
55682
+ }
55683
+ const hostname = parsed.hostname;
55684
+ if (this.isBlockedHostname(hostname)) {
55685
+ throw new Error(
55686
+ `OPA HTTP evaluator: url must not point to internal, loopback, or private network addresses`
55687
+ );
55688
+ }
55689
+ this.baseUrl = baseUrl.replace(/\/+$/, "");
55690
+ this.timeout = timeout;
55691
+ }
55692
+ /**
55693
+ * Check if a hostname is blocked due to SSRF concerns.
55694
+ *
55695
+ * Blocks:
55696
+ * - Loopback addresses (127.x.x.x, localhost, 0.0.0.0, ::1)
55697
+ * - Link-local addresses (169.254.x.x)
55698
+ * - Private networks (10.x.x.x, 172.16-31.x.x, 192.168.x.x)
55699
+ * - IPv6 unique local addresses (fd00::/8)
55700
+ * - Cloud metadata services (*.internal)
55701
+ */
55702
+ isBlockedHostname(hostname) {
55703
+ if (!hostname) return true;
55704
+ const normalized = hostname.toLowerCase().replace(/^\[|\]$/g, "");
55705
+ if (normalized === "metadata.google.internal" || normalized.endsWith(".internal")) {
55706
+ return true;
55707
+ }
55708
+ if (normalized === "localhost" || normalized === "localhost.localdomain") {
55709
+ return true;
55710
+ }
55711
+ if (normalized === "::1" || normalized === "0:0:0:0:0:0:0:1") {
55712
+ return true;
55713
+ }
55714
+ const ipv4Pattern = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/;
55715
+ const ipv4Match = normalized.match(ipv4Pattern);
55716
+ if (ipv4Match) {
55717
+ const octets = ipv4Match.slice(1, 5).map(Number);
55718
+ if (octets.some((octet) => octet > 255)) {
55719
+ return false;
55720
+ }
55721
+ const [a, b] = octets;
55722
+ if (a === 127) {
55723
+ return true;
55724
+ }
55725
+ if (a === 0) {
55726
+ return true;
55727
+ }
55728
+ if (a === 169 && b === 254) {
55729
+ return true;
55730
+ }
55731
+ if (a === 10) {
55732
+ return true;
55733
+ }
55734
+ if (a === 172 && b >= 16 && b <= 31) {
55735
+ return true;
55736
+ }
55737
+ if (a === 192 && b === 168) {
55738
+ return true;
55739
+ }
55740
+ }
55741
+ if (normalized.startsWith("fd") || normalized.startsWith("fc")) {
55742
+ return true;
55743
+ }
55744
+ if (normalized.startsWith("fe80:")) {
55745
+ return true;
55746
+ }
55747
+ return false;
55748
+ }
55749
+ /**
55750
+ * Evaluate a policy rule against an input document via OPA REST API.
55751
+ *
55752
+ * @param input - The input document to evaluate
55753
+ * @param rulePath - OPA rule path (e.g., 'visor/check/execute')
55754
+ * @returns The result object from OPA, or undefined on error
55755
+ */
55756
+ async evaluate(input, rulePath) {
55757
+ const encodedPath = rulePath.split("/").map((s) => encodeURIComponent(s)).join("/");
55758
+ const url = `${this.baseUrl}/v1/data/${encodedPath}`;
55759
+ const controller = new AbortController();
55760
+ const timer = setTimeout(() => controller.abort(), this.timeout);
55761
+ try {
55762
+ const response = await fetch(url, {
55763
+ method: "POST",
55764
+ headers: { "Content-Type": "application/json" },
55765
+ body: JSON.stringify({ input }),
55766
+ signal: controller.signal
55767
+ });
55768
+ if (!response.ok) {
55769
+ throw new Error(`OPA HTTP ${response.status}: ${response.statusText}`);
55770
+ }
55771
+ let body;
55772
+ try {
55773
+ body = await response.json();
55774
+ } catch (jsonErr) {
55775
+ throw new Error(
55776
+ `OPA HTTP evaluator: failed to parse JSON response: ${jsonErr instanceof Error ? jsonErr.message : String(jsonErr)}`
55777
+ );
55778
+ }
55779
+ return body?.result;
55780
+ } finally {
55781
+ clearTimeout(timer);
55782
+ }
55783
+ }
55784
+ async shutdown() {
55785
+ }
55786
+ };
55787
+ }
55788
+ });
55789
+
55790
+ // src/enterprise/policy/policy-input-builder.ts
55791
+ var PolicyInputBuilder;
55792
+ var init_policy_input_builder = __esm({
55793
+ "src/enterprise/policy/policy-input-builder.ts"() {
55794
+ "use strict";
55795
+ PolicyInputBuilder = class {
55796
+ roles;
55797
+ actor;
55798
+ repository;
55799
+ pullRequest;
55800
+ constructor(policyConfig, actor, repository, pullRequest) {
55801
+ this.roles = policyConfig.roles || {};
55802
+ this.actor = actor;
55803
+ this.repository = repository;
55804
+ this.pullRequest = pullRequest;
55805
+ }
55806
+ /** Resolve which roles apply to the current actor. */
55807
+ resolveRoles() {
55808
+ const matched = [];
55809
+ for (const [roleName, roleConfig] of Object.entries(this.roles)) {
55810
+ let identityMatch = false;
55811
+ if (roleConfig.author_association && this.actor.authorAssociation && roleConfig.author_association.includes(this.actor.authorAssociation)) {
55812
+ identityMatch = true;
55813
+ }
55814
+ if (!identityMatch && roleConfig.users && this.actor.login && roleConfig.users.includes(this.actor.login)) {
55815
+ identityMatch = true;
55816
+ }
55817
+ if (!identityMatch && roleConfig.slack_users && this.actor.slack?.userId && roleConfig.slack_users.includes(this.actor.slack.userId)) {
55818
+ identityMatch = true;
55819
+ }
55820
+ if (!identityMatch && roleConfig.emails && this.actor.slack?.email) {
55821
+ const actorEmail = this.actor.slack.email.toLowerCase();
55822
+ if (roleConfig.emails.some((e) => e.toLowerCase() === actorEmail)) {
55823
+ identityMatch = true;
55824
+ }
55825
+ }
55826
+ if (!identityMatch) continue;
55827
+ if (roleConfig.slack_channels && roleConfig.slack_channels.length > 0) {
55828
+ if (!this.actor.slack?.channelId || !roleConfig.slack_channels.includes(this.actor.slack.channelId)) {
55829
+ continue;
55830
+ }
55831
+ }
55832
+ matched.push(roleName);
55833
+ }
55834
+ return matched;
55835
+ }
55836
+ buildActor() {
55837
+ return {
55838
+ authorAssociation: this.actor.authorAssociation,
55839
+ login: this.actor.login,
55840
+ roles: this.resolveRoles(),
55841
+ isLocalMode: this.actor.isLocalMode,
55842
+ ...this.actor.slack && { slack: this.actor.slack }
55843
+ };
55844
+ }
55845
+ forCheckExecution(check) {
55846
+ return {
55847
+ scope: "check.execute",
55848
+ check: {
55849
+ id: check.id,
55850
+ type: check.type,
55851
+ group: check.group,
55852
+ tags: check.tags,
55853
+ criticality: check.criticality,
55854
+ sandbox: check.sandbox,
55855
+ policy: check.policy
55856
+ },
55857
+ actor: this.buildActor(),
55858
+ repository: this.repository,
55859
+ pullRequest: this.pullRequest
55860
+ };
55861
+ }
55862
+ forToolInvocation(serverName, methodName, transport) {
55863
+ return {
55864
+ scope: "tool.invoke",
55865
+ tool: { serverName, methodName, transport },
55866
+ actor: this.buildActor(),
55867
+ repository: this.repository,
55868
+ pullRequest: this.pullRequest
55869
+ };
55870
+ }
55871
+ forCapabilityResolve(checkId, capabilities) {
55872
+ return {
55873
+ scope: "capability.resolve",
55874
+ check: { id: checkId, type: "ai" },
55875
+ capability: capabilities,
55876
+ actor: this.buildActor(),
55877
+ repository: this.repository,
55878
+ pullRequest: this.pullRequest
55879
+ };
54997
55880
  }
55881
+ };
55882
+ }
55883
+ });
55884
+
55885
+ // src/enterprise/policy/opa-policy-engine.ts
55886
+ var opa_policy_engine_exports = {};
55887
+ __export(opa_policy_engine_exports, {
55888
+ OpaPolicyEngine: () => OpaPolicyEngine
55889
+ });
55890
+ var OpaPolicyEngine;
55891
+ var init_opa_policy_engine = __esm({
55892
+ "src/enterprise/policy/opa-policy-engine.ts"() {
55893
+ "use strict";
55894
+ init_opa_wasm_evaluator();
55895
+ init_opa_http_evaluator();
55896
+ init_policy_input_builder();
55897
+ OpaPolicyEngine = class {
55898
+ evaluator = null;
55899
+ fallback;
55900
+ timeout;
55901
+ config;
55902
+ inputBuilder = null;
55903
+ logger = null;
55904
+ constructor(config) {
55905
+ this.config = config;
55906
+ this.fallback = config.fallback || "deny";
55907
+ this.timeout = config.timeout || 5e3;
55908
+ }
55909
+ async initialize(config) {
55910
+ try {
55911
+ this.logger = (init_logger(), __toCommonJS(logger_exports)).logger;
55912
+ } catch {
55913
+ }
55914
+ const actor = {
55915
+ authorAssociation: process.env.VISOR_AUTHOR_ASSOCIATION,
55916
+ login: process.env.VISOR_AUTHOR_LOGIN || process.env.GITHUB_ACTOR,
55917
+ isLocalMode: !process.env.GITHUB_ACTIONS
55918
+ };
55919
+ const repo = {
55920
+ owner: process.env.GITHUB_REPOSITORY_OWNER,
55921
+ name: process.env.GITHUB_REPOSITORY?.split("/")[1],
55922
+ branch: process.env.GITHUB_HEAD_REF,
55923
+ baseBranch: process.env.GITHUB_BASE_REF,
55924
+ event: process.env.GITHUB_EVENT_NAME
55925
+ };
55926
+ const prNum = process.env.GITHUB_PR_NUMBER ? parseInt(process.env.GITHUB_PR_NUMBER, 10) : void 0;
55927
+ const pullRequest = {
55928
+ number: prNum !== void 0 && Number.isFinite(prNum) ? prNum : void 0
55929
+ };
55930
+ this.inputBuilder = new PolicyInputBuilder(config, actor, repo, pullRequest);
55931
+ if (config.engine === "local") {
55932
+ if (!config.rules) {
55933
+ throw new Error("OPA local mode requires `policy.rules` path to .wasm or .rego files");
55934
+ }
55935
+ const wasm = new OpaWasmEvaluator();
55936
+ await wasm.initialize(config.rules);
55937
+ if (config.data) {
55938
+ wasm.loadData(config.data);
55939
+ }
55940
+ this.evaluator = wasm;
55941
+ } else if (config.engine === "remote") {
55942
+ if (!config.url) {
55943
+ throw new Error("OPA remote mode requires `policy.url` pointing to OPA server");
55944
+ }
55945
+ this.evaluator = new OpaHttpEvaluator(config.url, this.timeout);
55946
+ } else {
55947
+ this.evaluator = null;
55948
+ }
55949
+ }
55950
+ /**
55951
+ * Update actor/repo/PR context (e.g., after PR info becomes available).
55952
+ * Called by the enterprise loader when engine context is enriched.
55953
+ */
55954
+ setActorContext(actor, repo, pullRequest) {
55955
+ this.inputBuilder = new PolicyInputBuilder(this.config, actor, repo, pullRequest);
55956
+ }
55957
+ async evaluateCheckExecution(checkId, checkConfig) {
55958
+ if (!this.evaluator || !this.inputBuilder) return { allowed: true };
55959
+ const cfg = checkConfig && typeof checkConfig === "object" ? checkConfig : {};
55960
+ const policyOverride = cfg.policy;
55961
+ const input = this.inputBuilder.forCheckExecution({
55962
+ id: checkId,
55963
+ type: cfg.type || "ai",
55964
+ group: cfg.group,
55965
+ tags: cfg.tags,
55966
+ criticality: cfg.criticality,
55967
+ sandbox: cfg.sandbox,
55968
+ policy: policyOverride
55969
+ });
55970
+ return this.doEvaluate(input, this.resolveRulePath("check.execute", policyOverride?.rule));
55971
+ }
55972
+ async evaluateToolInvocation(serverName, methodName, transport) {
55973
+ if (!this.evaluator || !this.inputBuilder) return { allowed: true };
55974
+ const input = this.inputBuilder.forToolInvocation(serverName, methodName, transport);
55975
+ return this.doEvaluate(input, "visor/tool/invoke");
55976
+ }
55977
+ async evaluateCapabilities(checkId, capabilities) {
55978
+ if (!this.evaluator || !this.inputBuilder) return { allowed: true };
55979
+ const input = this.inputBuilder.forCapabilityResolve(checkId, capabilities);
55980
+ return this.doEvaluate(input, "visor/capability/resolve");
55981
+ }
55982
+ async shutdown() {
55983
+ if (this.evaluator && "shutdown" in this.evaluator) {
55984
+ await this.evaluator.shutdown();
55985
+ }
55986
+ this.evaluator = null;
55987
+ this.inputBuilder = null;
55988
+ }
55989
+ resolveRulePath(defaultScope, override) {
55990
+ if (override) {
55991
+ return override.startsWith("visor/") ? override : `visor/${override}`;
55992
+ }
55993
+ return `visor/${defaultScope.replace(/\./g, "/")}`;
55994
+ }
55995
+ async doEvaluate(input, rulePath) {
55996
+ try {
55997
+ this.logger?.debug(`[PolicyEngine] Evaluating ${rulePath}`, JSON.stringify(input));
55998
+ let timer;
55999
+ const timeoutPromise = new Promise((_resolve, reject) => {
56000
+ timer = setTimeout(() => reject(new Error("policy evaluation timeout")), this.timeout);
56001
+ });
56002
+ try {
56003
+ const result = await Promise.race([this.rawEvaluate(input, rulePath), timeoutPromise]);
56004
+ const decision = this.parseDecision(result);
56005
+ if (!decision.allowed && this.fallback === "warn") {
56006
+ decision.allowed = true;
56007
+ decision.warn = true;
56008
+ decision.reason = `audit: ${decision.reason || "policy denied"}`;
56009
+ }
56010
+ this.logger?.debug(
56011
+ `[PolicyEngine] Decision for ${rulePath}: allowed=${decision.allowed}, warn=${decision.warn || false}, reason=${decision.reason || "none"}`
56012
+ );
56013
+ return decision;
56014
+ } finally {
56015
+ if (timer) clearTimeout(timer);
56016
+ }
56017
+ } catch (err) {
56018
+ const msg = err instanceof Error ? err.message : String(err);
56019
+ this.logger?.warn(`[PolicyEngine] Evaluation failed for ${rulePath}: ${msg}`);
56020
+ return {
56021
+ allowed: this.fallback === "allow" || this.fallback === "warn",
56022
+ warn: this.fallback === "warn" ? true : void 0,
56023
+ reason: `policy evaluation failed, fallback=${this.fallback}`
56024
+ };
56025
+ }
56026
+ }
56027
+ async rawEvaluate(input, rulePath) {
56028
+ if (this.evaluator instanceof OpaWasmEvaluator) {
56029
+ const result = await this.evaluator.evaluate(input);
56030
+ return this.navigateWasmResult(result, rulePath);
56031
+ }
56032
+ return this.evaluator.evaluate(input, rulePath);
56033
+ }
56034
+ /**
56035
+ * Navigate nested OPA WASM result tree to reach the specific rule's output.
56036
+ * The WASM entrypoint `-e visor` means the result root IS the visor package,
56037
+ * so we strip the `visor/` prefix and walk the remaining segments.
56038
+ */
56039
+ navigateWasmResult(result, rulePath) {
56040
+ if (!result || typeof result !== "object") return result;
56041
+ const segments = rulePath.replace(/^visor\//, "").split("/");
56042
+ let current = result;
56043
+ for (const seg of segments) {
56044
+ if (current && typeof current === "object" && seg in current) {
56045
+ current = current[seg];
56046
+ } else {
56047
+ return void 0;
56048
+ }
56049
+ }
56050
+ return current;
56051
+ }
56052
+ parseDecision(result) {
56053
+ if (result === void 0 || result === null) {
56054
+ return {
56055
+ allowed: this.fallback === "allow" || this.fallback === "warn",
56056
+ warn: this.fallback === "warn" ? true : void 0,
56057
+ reason: this.fallback === "warn" ? "audit: no policy result" : "no policy result"
56058
+ };
56059
+ }
56060
+ const allowed = result.allowed !== false;
56061
+ const decision = {
56062
+ allowed,
56063
+ reason: result.reason
56064
+ };
56065
+ if (result.capabilities) {
56066
+ decision.capabilities = result.capabilities;
56067
+ }
56068
+ return decision;
56069
+ }
56070
+ };
56071
+ }
56072
+ });
56073
+
56074
+ // src/enterprise/scheduler/knex-store.ts
56075
+ var knex_store_exports = {};
56076
+ __export(knex_store_exports, {
56077
+ KnexStoreBackend: () => KnexStoreBackend
56078
+ });
56079
+ function toNum(val) {
56080
+ if (val === null || val === void 0) return void 0;
56081
+ return typeof val === "string" ? parseInt(val, 10) : val;
56082
+ }
56083
+ function safeJsonParse2(value) {
56084
+ if (!value) return void 0;
56085
+ try {
56086
+ return JSON.parse(value);
56087
+ } catch {
56088
+ return void 0;
56089
+ }
56090
+ }
56091
+ function fromTriggerRow2(row) {
56092
+ return {
56093
+ id: row.id,
56094
+ creatorId: row.creator_id,
56095
+ creatorContext: row.creator_context ?? void 0,
56096
+ creatorName: row.creator_name ?? void 0,
56097
+ description: row.description ?? void 0,
56098
+ channels: safeJsonParse2(row.channels),
56099
+ fromUsers: safeJsonParse2(row.from_users),
56100
+ fromBots: row.from_bots === true || row.from_bots === 1,
56101
+ contains: safeJsonParse2(row.contains),
56102
+ matchPattern: row.match_pattern ?? void 0,
56103
+ threads: row.threads,
56104
+ workflow: row.workflow,
56105
+ inputs: safeJsonParse2(row.inputs),
56106
+ outputContext: safeJsonParse2(row.output_context),
56107
+ status: row.status,
56108
+ enabled: row.enabled === true || row.enabled === 1,
56109
+ createdAt: toNum(row.created_at)
56110
+ };
56111
+ }
56112
+ function toTriggerInsertRow(trigger) {
56113
+ return {
56114
+ id: trigger.id,
56115
+ creator_id: trigger.creatorId,
56116
+ creator_context: trigger.creatorContext ?? null,
56117
+ creator_name: trigger.creatorName ?? null,
56118
+ description: trigger.description ?? null,
56119
+ channels: trigger.channels ? JSON.stringify(trigger.channels) : null,
56120
+ from_users: trigger.fromUsers ? JSON.stringify(trigger.fromUsers) : null,
56121
+ from_bots: trigger.fromBots,
56122
+ contains: trigger.contains ? JSON.stringify(trigger.contains) : null,
56123
+ match_pattern: trigger.matchPattern ?? null,
56124
+ threads: trigger.threads,
56125
+ workflow: trigger.workflow,
56126
+ inputs: trigger.inputs ? JSON.stringify(trigger.inputs) : null,
56127
+ output_context: trigger.outputContext ? JSON.stringify(trigger.outputContext) : null,
56128
+ status: trigger.status,
56129
+ enabled: trigger.enabled,
56130
+ created_at: trigger.createdAt
56131
+ };
56132
+ }
56133
+ function fromDbRow2(row) {
56134
+ return {
56135
+ id: row.id,
56136
+ creatorId: row.creator_id,
56137
+ creatorContext: row.creator_context ?? void 0,
56138
+ creatorName: row.creator_name ?? void 0,
56139
+ timezone: row.timezone,
56140
+ schedule: row.schedule_expr,
56141
+ runAt: toNum(row.run_at),
56142
+ isRecurring: row.is_recurring === true || row.is_recurring === 1,
56143
+ originalExpression: row.original_expression,
56144
+ workflow: row.workflow ?? void 0,
56145
+ workflowInputs: safeJsonParse2(row.workflow_inputs),
56146
+ outputContext: safeJsonParse2(row.output_context),
56147
+ status: row.status,
56148
+ createdAt: toNum(row.created_at),
56149
+ lastRunAt: toNum(row.last_run_at),
56150
+ nextRunAt: toNum(row.next_run_at),
56151
+ runCount: row.run_count,
56152
+ failureCount: row.failure_count,
56153
+ lastError: row.last_error ?? void 0,
56154
+ previousResponse: row.previous_response ?? void 0
56155
+ };
56156
+ }
56157
+ function toInsertRow(schedule) {
56158
+ return {
56159
+ id: schedule.id,
56160
+ creator_id: schedule.creatorId,
56161
+ creator_context: schedule.creatorContext ?? null,
56162
+ creator_name: schedule.creatorName ?? null,
56163
+ timezone: schedule.timezone,
56164
+ schedule_expr: schedule.schedule,
56165
+ run_at: schedule.runAt ?? null,
56166
+ is_recurring: schedule.isRecurring,
56167
+ original_expression: schedule.originalExpression,
56168
+ workflow: schedule.workflow ?? null,
56169
+ workflow_inputs: schedule.workflowInputs ? JSON.stringify(schedule.workflowInputs) : null,
56170
+ output_context: schedule.outputContext ? JSON.stringify(schedule.outputContext) : null,
56171
+ status: schedule.status,
56172
+ created_at: schedule.createdAt,
56173
+ last_run_at: schedule.lastRunAt ?? null,
56174
+ next_run_at: schedule.nextRunAt ?? null,
56175
+ run_count: schedule.runCount,
56176
+ failure_count: schedule.failureCount,
56177
+ last_error: schedule.lastError ?? null,
56178
+ previous_response: schedule.previousResponse ?? null
56179
+ };
56180
+ }
56181
+ var fs24, path28, import_uuid2, KnexStoreBackend;
56182
+ var init_knex_store = __esm({
56183
+ "src/enterprise/scheduler/knex-store.ts"() {
56184
+ "use strict";
56185
+ fs24 = __toESM(require("fs"));
56186
+ path28 = __toESM(require("path"));
56187
+ import_uuid2 = require("uuid");
56188
+ init_logger();
56189
+ KnexStoreBackend = class {
56190
+ knex = null;
56191
+ driver;
56192
+ connection;
56193
+ constructor(driver, storageConfig, _haConfig) {
56194
+ this.driver = driver;
56195
+ this.connection = storageConfig.connection || {};
56196
+ }
56197
+ async initialize() {
56198
+ const { createRequire } = require("module");
56199
+ const runtimeRequire = createRequire(__filename);
56200
+ let knexFactory;
56201
+ try {
56202
+ knexFactory = runtimeRequire("knex");
56203
+ } catch (err) {
56204
+ const code = err?.code;
56205
+ if (code === "MODULE_NOT_FOUND" || code === "ERR_MODULE_NOT_FOUND") {
56206
+ throw new Error(
56207
+ "knex is required for PostgreSQL/MySQL/MSSQL schedule storage. Install it with: npm install knex"
56208
+ );
56209
+ }
56210
+ throw err;
56211
+ }
56212
+ const clientMap = {
56213
+ postgresql: "pg",
56214
+ mysql: "mysql2",
56215
+ mssql: "tedious"
56216
+ };
56217
+ const client = clientMap[this.driver];
56218
+ let connection;
56219
+ if (this.connection.connection_string) {
56220
+ connection = this.connection.connection_string;
56221
+ } else if (this.driver === "mssql") {
56222
+ connection = this.buildMssqlConnection();
56223
+ } else {
56224
+ connection = this.buildStandardConnection();
56225
+ }
56226
+ this.knex = knexFactory({
56227
+ client,
56228
+ connection,
56229
+ pool: {
56230
+ min: this.connection.pool?.min ?? 0,
56231
+ max: this.connection.pool?.max ?? 10
56232
+ }
56233
+ });
56234
+ await this.migrateSchema();
56235
+ logger.info(`[KnexStore] Initialized (${this.driver})`);
56236
+ }
56237
+ buildStandardConnection() {
56238
+ return {
56239
+ host: this.connection.host || "localhost",
56240
+ port: this.connection.port,
56241
+ database: this.connection.database || "visor",
56242
+ user: this.connection.user,
56243
+ password: this.connection.password,
56244
+ ssl: this.resolveSslConfig()
56245
+ };
56246
+ }
56247
+ buildMssqlConnection() {
56248
+ const ssl = this.connection.ssl;
56249
+ const sslEnabled = ssl === true || typeof ssl === "object" && ssl.enabled !== false;
56250
+ return {
56251
+ server: this.connection.host || "localhost",
56252
+ port: this.connection.port,
56253
+ database: this.connection.database || "visor",
56254
+ user: this.connection.user,
56255
+ password: this.connection.password,
56256
+ options: {
56257
+ encrypt: sslEnabled,
56258
+ trustServerCertificate: typeof ssl === "object" ? ssl.reject_unauthorized === false : !sslEnabled
56259
+ }
56260
+ };
56261
+ }
56262
+ resolveSslConfig() {
56263
+ const ssl = this.connection.ssl;
56264
+ if (ssl === false || ssl === void 0) return false;
56265
+ if (ssl === true) return { rejectUnauthorized: true };
56266
+ if (ssl.enabled === false) return false;
56267
+ const result = {
56268
+ rejectUnauthorized: ssl.reject_unauthorized !== false
56269
+ };
56270
+ if (ssl.ca) {
56271
+ const caPath = this.validateSslPath(ssl.ca, "CA certificate");
56272
+ result.ca = fs24.readFileSync(caPath, "utf8");
56273
+ }
56274
+ if (ssl.cert) {
56275
+ const certPath = this.validateSslPath(ssl.cert, "client certificate");
56276
+ result.cert = fs24.readFileSync(certPath, "utf8");
56277
+ }
56278
+ if (ssl.key) {
56279
+ const keyPath = this.validateSslPath(ssl.key, "client key");
56280
+ result.key = fs24.readFileSync(keyPath, "utf8");
56281
+ }
56282
+ return result;
56283
+ }
56284
+ validateSslPath(filePath, label) {
56285
+ const resolved = path28.resolve(filePath);
56286
+ if (resolved !== path28.normalize(resolved)) {
56287
+ throw new Error(`SSL ${label} path contains invalid sequences: ${filePath}`);
56288
+ }
56289
+ if (!fs24.existsSync(resolved)) {
56290
+ throw new Error(`SSL ${label} not found: ${filePath}`);
56291
+ }
56292
+ return resolved;
56293
+ }
56294
+ async shutdown() {
56295
+ if (this.knex) {
56296
+ await this.knex.destroy();
56297
+ this.knex = null;
56298
+ }
56299
+ }
56300
+ async migrateSchema() {
56301
+ const knex = this.getKnex();
56302
+ const exists = await knex.schema.hasTable("schedules");
56303
+ if (!exists) {
56304
+ await knex.schema.createTable("schedules", (table) => {
56305
+ table.string("id", 36).primary();
56306
+ table.string("creator_id", 255).notNullable().index();
56307
+ table.string("creator_context", 255);
56308
+ table.string("creator_name", 255);
56309
+ table.string("timezone", 64).notNullable().defaultTo("UTC");
56310
+ table.string("schedule_expr", 255);
56311
+ table.bigInteger("run_at");
56312
+ table.boolean("is_recurring").notNullable();
56313
+ table.text("original_expression");
56314
+ table.string("workflow", 255);
56315
+ table.text("workflow_inputs");
56316
+ table.text("output_context");
56317
+ table.string("status", 20).notNullable().index();
56318
+ table.bigInteger("created_at").notNullable();
56319
+ table.bigInteger("last_run_at");
56320
+ table.bigInteger("next_run_at");
56321
+ table.integer("run_count").notNullable().defaultTo(0);
56322
+ table.integer("failure_count").notNullable().defaultTo(0);
56323
+ table.text("last_error");
56324
+ table.text("previous_response");
56325
+ table.index(["status", "next_run_at"]);
56326
+ });
56327
+ }
56328
+ const triggersExist = await knex.schema.hasTable("message_triggers");
56329
+ if (!triggersExist) {
56330
+ await knex.schema.createTable("message_triggers", (table) => {
56331
+ table.string("id", 36).primary();
56332
+ table.string("creator_id", 255).notNullable().index();
56333
+ table.string("creator_context", 255);
56334
+ table.string("creator_name", 255);
56335
+ table.text("description");
56336
+ table.text("channels");
56337
+ table.text("from_users");
56338
+ table.boolean("from_bots").notNullable().defaultTo(false);
56339
+ table.text("contains");
56340
+ table.text("match_pattern");
56341
+ table.string("threads", 20).notNullable().defaultTo("any");
56342
+ table.string("workflow", 255).notNullable();
56343
+ table.text("inputs");
56344
+ table.text("output_context");
56345
+ table.string("status", 20).notNullable().defaultTo("active").index();
56346
+ table.boolean("enabled").notNullable().defaultTo(true);
56347
+ table.bigInteger("created_at").notNullable();
56348
+ });
56349
+ }
56350
+ const locksExist = await knex.schema.hasTable("scheduler_locks");
56351
+ if (!locksExist) {
56352
+ await knex.schema.createTable("scheduler_locks", (table) => {
56353
+ table.string("lock_id", 255).primary();
56354
+ table.string("node_id", 255).notNullable();
56355
+ table.string("lock_token", 36).notNullable();
56356
+ table.bigInteger("acquired_at").notNullable();
56357
+ table.bigInteger("expires_at").notNullable();
56358
+ });
56359
+ }
56360
+ }
56361
+ getKnex() {
56362
+ if (!this.knex) {
56363
+ throw new Error("[KnexStore] Not initialized. Call initialize() first.");
56364
+ }
56365
+ return this.knex;
56366
+ }
56367
+ // --- CRUD ---
56368
+ async create(schedule) {
56369
+ const knex = this.getKnex();
56370
+ const newSchedule = {
56371
+ ...schedule,
56372
+ id: (0, import_uuid2.v4)(),
56373
+ createdAt: Date.now(),
56374
+ runCount: 0,
56375
+ failureCount: 0,
56376
+ status: "active"
56377
+ };
56378
+ await knex("schedules").insert(toInsertRow(newSchedule));
56379
+ logger.info(`[KnexStore] Created schedule ${newSchedule.id} for user ${newSchedule.creatorId}`);
56380
+ return newSchedule;
56381
+ }
56382
+ async importSchedule(schedule) {
56383
+ const knex = this.getKnex();
56384
+ const existing = await knex("schedules").where("id", schedule.id).first();
56385
+ if (existing) return;
56386
+ await knex("schedules").insert(toInsertRow(schedule));
56387
+ }
56388
+ async get(id) {
56389
+ const knex = this.getKnex();
56390
+ const row = await knex("schedules").where("id", id).first();
56391
+ return row ? fromDbRow2(row) : void 0;
56392
+ }
56393
+ async update(id, patch) {
56394
+ const knex = this.getKnex();
56395
+ const existing = await knex("schedules").where("id", id).first();
56396
+ if (!existing) return void 0;
56397
+ const current = fromDbRow2(existing);
56398
+ const updated = { ...current, ...patch, id: current.id };
56399
+ const row = toInsertRow(updated);
56400
+ delete row.id;
56401
+ await knex("schedules").where("id", id).update(row);
56402
+ return updated;
56403
+ }
56404
+ async delete(id) {
56405
+ const knex = this.getKnex();
56406
+ const deleted = await knex("schedules").where("id", id).del();
56407
+ if (deleted > 0) {
56408
+ logger.info(`[KnexStore] Deleted schedule ${id}`);
56409
+ return true;
56410
+ }
56411
+ return false;
56412
+ }
56413
+ // --- Queries ---
56414
+ async getByCreator(creatorId) {
56415
+ const knex = this.getKnex();
56416
+ const rows = await knex("schedules").where("creator_id", creatorId);
56417
+ return rows.map((r) => fromDbRow2(r));
56418
+ }
56419
+ async getActiveSchedules() {
56420
+ const knex = this.getKnex();
56421
+ const rows = await knex("schedules").where("status", "active");
56422
+ return rows.map((r) => fromDbRow2(r));
56423
+ }
56424
+ async getDueSchedules(now) {
56425
+ const ts = now ?? Date.now();
56426
+ const knex = this.getKnex();
56427
+ const bFalse = this.driver === "mssql" ? 0 : false;
56428
+ const bTrue = this.driver === "mssql" ? 1 : true;
56429
+ const rows = await knex("schedules").where("status", "active").andWhere(function() {
56430
+ this.where(function() {
56431
+ this.where("is_recurring", bFalse).whereNotNull("run_at").where("run_at", "<=", ts);
56432
+ }).orWhere(function() {
56433
+ this.where("is_recurring", bTrue).whereNotNull("next_run_at").where("next_run_at", "<=", ts);
56434
+ });
56435
+ });
56436
+ return rows.map((r) => fromDbRow2(r));
56437
+ }
56438
+ async findByWorkflow(creatorId, workflowName) {
56439
+ const knex = this.getKnex();
56440
+ const escaped = workflowName.toLowerCase().replace(/[%_\\]/g, "\\$&");
56441
+ const pattern = `%${escaped}%`;
56442
+ const rows = await knex("schedules").where("creator_id", creatorId).where("status", "active").whereRaw("LOWER(workflow) LIKE ? ESCAPE '\\'", [pattern]);
56443
+ return rows.map((r) => fromDbRow2(r));
56444
+ }
56445
+ async getAll() {
56446
+ const knex = this.getKnex();
56447
+ const rows = await knex("schedules");
56448
+ return rows.map((r) => fromDbRow2(r));
56449
+ }
56450
+ async getStats() {
56451
+ const knex = this.getKnex();
56452
+ const boolTrue = this.driver === "mssql" ? "1" : "true";
56453
+ const boolFalse = this.driver === "mssql" ? "0" : "false";
56454
+ const result = await knex("schedules").select(
56455
+ knex.raw("COUNT(*) as total"),
56456
+ knex.raw("SUM(CASE WHEN status = 'active' THEN 1 ELSE 0 END) as active"),
56457
+ knex.raw("SUM(CASE WHEN status = 'paused' THEN 1 ELSE 0 END) as paused"),
56458
+ knex.raw("SUM(CASE WHEN status = 'completed' THEN 1 ELSE 0 END) as completed"),
56459
+ knex.raw("SUM(CASE WHEN status = 'failed' THEN 1 ELSE 0 END) as failed"),
56460
+ knex.raw(`SUM(CASE WHEN is_recurring = ${boolTrue} THEN 1 ELSE 0 END) as recurring`),
56461
+ knex.raw(`SUM(CASE WHEN is_recurring = ${boolFalse} THEN 1 ELSE 0 END) as one_time`)
56462
+ ).first();
56463
+ return {
56464
+ total: Number(result.total) || 0,
56465
+ active: Number(result.active) || 0,
56466
+ paused: Number(result.paused) || 0,
56467
+ completed: Number(result.completed) || 0,
56468
+ failed: Number(result.failed) || 0,
56469
+ recurring: Number(result.recurring) || 0,
56470
+ oneTime: Number(result.one_time) || 0
56471
+ };
56472
+ }
56473
+ async validateLimits(creatorId, isRecurring, limits) {
56474
+ const knex = this.getKnex();
56475
+ if (limits.maxGlobal) {
56476
+ const result = await knex("schedules").count("* as cnt").first();
56477
+ if (Number(result?.cnt) >= limits.maxGlobal) {
56478
+ throw new Error(`Global schedule limit reached (${limits.maxGlobal})`);
56479
+ }
56480
+ }
56481
+ if (limits.maxPerUser) {
56482
+ const result = await knex("schedules").where("creator_id", creatorId).count("* as cnt").first();
56483
+ if (Number(result?.cnt) >= limits.maxPerUser) {
56484
+ throw new Error(`You have reached the maximum number of schedules (${limits.maxPerUser})`);
56485
+ }
56486
+ }
56487
+ if (isRecurring && limits.maxRecurringPerUser) {
56488
+ const bTrue = this.driver === "mssql" ? 1 : true;
56489
+ const result = await knex("schedules").where("creator_id", creatorId).where("is_recurring", bTrue).count("* as cnt").first();
56490
+ if (Number(result?.cnt) >= limits.maxRecurringPerUser) {
56491
+ throw new Error(
56492
+ `You have reached the maximum number of recurring schedules (${limits.maxRecurringPerUser})`
56493
+ );
56494
+ }
56495
+ }
56496
+ }
56497
+ // --- HA Distributed Locking (via scheduler_locks table) ---
56498
+ async tryAcquireLock(lockId, nodeId, ttlSeconds) {
56499
+ const knex = this.getKnex();
56500
+ const now = Date.now();
56501
+ const expiresAt = now + ttlSeconds * 1e3;
56502
+ const token = (0, import_uuid2.v4)();
56503
+ const updated = await knex("scheduler_locks").where("lock_id", lockId).where("expires_at", "<", now).update({
56504
+ node_id: nodeId,
56505
+ lock_token: token,
56506
+ acquired_at: now,
56507
+ expires_at: expiresAt
56508
+ });
56509
+ if (updated > 0) return token;
56510
+ try {
56511
+ await knex("scheduler_locks").insert({
56512
+ lock_id: lockId,
56513
+ node_id: nodeId,
56514
+ lock_token: token,
56515
+ acquired_at: now,
56516
+ expires_at: expiresAt
56517
+ });
56518
+ return token;
56519
+ } catch {
56520
+ return null;
56521
+ }
56522
+ }
56523
+ async releaseLock(lockId, lockToken) {
56524
+ const knex = this.getKnex();
56525
+ await knex("scheduler_locks").where("lock_id", lockId).where("lock_token", lockToken).del();
56526
+ }
56527
+ async renewLock(lockId, lockToken, ttlSeconds) {
56528
+ const knex = this.getKnex();
56529
+ const now = Date.now();
56530
+ const expiresAt = now + ttlSeconds * 1e3;
56531
+ const updated = await knex("scheduler_locks").where("lock_id", lockId).where("lock_token", lockToken).update({ acquired_at: now, expires_at: expiresAt });
56532
+ return updated > 0;
56533
+ }
56534
+ async flush() {
56535
+ }
56536
+ // --- Message Trigger CRUD ---
56537
+ async createTrigger(trigger) {
56538
+ const knex = this.getKnex();
56539
+ const newTrigger = {
56540
+ ...trigger,
56541
+ id: (0, import_uuid2.v4)(),
56542
+ createdAt: Date.now()
56543
+ };
56544
+ await knex("message_triggers").insert(toTriggerInsertRow(newTrigger));
56545
+ logger.info(`[KnexStore] Created trigger ${newTrigger.id} for user ${newTrigger.creatorId}`);
56546
+ return newTrigger;
56547
+ }
56548
+ async getTrigger(id) {
56549
+ const knex = this.getKnex();
56550
+ const row = await knex("message_triggers").where("id", id).first();
56551
+ return row ? fromTriggerRow2(row) : void 0;
56552
+ }
56553
+ async updateTrigger(id, patch) {
56554
+ const knex = this.getKnex();
56555
+ const existing = await knex("message_triggers").where("id", id).first();
56556
+ if (!existing) return void 0;
56557
+ const current = fromTriggerRow2(existing);
56558
+ const updated = {
56559
+ ...current,
56560
+ ...patch,
56561
+ id: current.id,
56562
+ createdAt: current.createdAt
56563
+ };
56564
+ const row = toTriggerInsertRow(updated);
56565
+ delete row.id;
56566
+ await knex("message_triggers").where("id", id).update(row);
56567
+ return updated;
56568
+ }
56569
+ async deleteTrigger(id) {
56570
+ const knex = this.getKnex();
56571
+ const deleted = await knex("message_triggers").where("id", id).del();
56572
+ if (deleted > 0) {
56573
+ logger.info(`[KnexStore] Deleted trigger ${id}`);
56574
+ return true;
56575
+ }
56576
+ return false;
56577
+ }
56578
+ async getTriggersByCreator(creatorId) {
56579
+ const knex = this.getKnex();
56580
+ const rows = await knex("message_triggers").where("creator_id", creatorId);
56581
+ return rows.map((r) => fromTriggerRow2(r));
56582
+ }
56583
+ async getActiveTriggers() {
56584
+ const knex = this.getKnex();
56585
+ const rows = await knex("message_triggers").where("status", "active").where("enabled", this.driver === "mssql" ? 1 : true);
56586
+ return rows.map((r) => fromTriggerRow2(r));
56587
+ }
56588
+ };
56589
+ }
56590
+ });
56591
+
56592
+ // src/enterprise/loader.ts
56593
+ var loader_exports = {};
56594
+ __export(loader_exports, {
56595
+ loadEnterprisePolicyEngine: () => loadEnterprisePolicyEngine,
56596
+ loadEnterpriseStoreBackend: () => loadEnterpriseStoreBackend
56597
+ });
56598
+ async function loadEnterprisePolicyEngine(config) {
56599
+ try {
56600
+ const { LicenseValidator: LicenseValidator2 } = await Promise.resolve().then(() => (init_validator(), validator_exports));
56601
+ const validator = new LicenseValidator2();
56602
+ const license = await validator.loadAndValidate();
56603
+ if (!license || !validator.hasFeature("policy")) {
56604
+ return new DefaultPolicyEngine();
56605
+ }
56606
+ if (validator.isInGracePeriod()) {
56607
+ console.warn(
56608
+ "[visor:enterprise] License has expired but is within the 72-hour grace period. Please renew your license."
56609
+ );
56610
+ }
56611
+ const { OpaPolicyEngine: OpaPolicyEngine2 } = await Promise.resolve().then(() => (init_opa_policy_engine(), opa_policy_engine_exports));
56612
+ const engine = new OpaPolicyEngine2(config);
56613
+ await engine.initialize(config);
56614
+ return engine;
56615
+ } catch (err) {
56616
+ const msg = err instanceof Error ? err.message : String(err);
56617
+ try {
56618
+ const { logger: logger2 } = (init_logger(), __toCommonJS(logger_exports));
56619
+ logger2.warn(`[PolicyEngine] Enterprise policy init failed, falling back to default: ${msg}`);
54998
56620
  } catch {
54999
56621
  }
56622
+ return new DefaultPolicyEngine();
56623
+ }
56624
+ }
56625
+ async function loadEnterpriseStoreBackend(driver, storageConfig, haConfig) {
56626
+ const { LicenseValidator: LicenseValidator2 } = await Promise.resolve().then(() => (init_validator(), validator_exports));
56627
+ const validator = new LicenseValidator2();
56628
+ const license = await validator.loadAndValidate();
56629
+ if (!license || !validator.hasFeature("scheduler-sql")) {
56630
+ throw new Error(
56631
+ `The ${driver} schedule storage driver requires a Visor Enterprise license with the 'scheduler-sql' feature. Please upgrade or use driver: 'sqlite' (default).`
56632
+ );
56633
+ }
56634
+ if (validator.isInGracePeriod()) {
56635
+ console.warn(
56636
+ "[visor:enterprise] License has expired but is within the 72-hour grace period. Please renew your license."
56637
+ );
56638
+ }
56639
+ const { KnexStoreBackend: KnexStoreBackend2 } = await Promise.resolve().then(() => (init_knex_store(), knex_store_exports));
56640
+ return new KnexStoreBackend2(driver, storageConfig, haConfig);
56641
+ }
56642
+ var init_loader = __esm({
56643
+ "src/enterprise/loader.ts"() {
56644
+ "use strict";
56645
+ init_default_engine();
55000
56646
  }
55001
56647
  });
55002
56648
 
@@ -55906,8 +57552,8 @@ ${content}
55906
57552
  * Sleep utility
55907
57553
  */
55908
57554
  sleep(ms) {
55909
- return new Promise((resolve15) => {
55910
- const t = setTimeout(resolve15, ms);
57555
+ return new Promise((resolve19) => {
57556
+ const t = setTimeout(resolve19, ms);
55911
57557
  if (typeof t.unref === "function") {
55912
57558
  try {
55913
57559
  t.unref();
@@ -56192,18 +57838,36 @@ ${end}`);
56192
57838
  async updateGroupedComment(ctx, comments, group, changedIds) {
56193
57839
  const existingLock = this.updateLocks.get(group);
56194
57840
  let resolveLock;
56195
- const ourLock = new Promise((resolve15) => {
56196
- resolveLock = resolve15;
57841
+ const ourLock = new Promise((resolve19) => {
57842
+ resolveLock = resolve19;
56197
57843
  });
56198
57844
  this.updateLocks.set(group, ourLock);
56199
57845
  try {
56200
57846
  if (existingLock) {
57847
+ logger.info(
57848
+ `[github-frontend] Comment update for group "${group}" queued, waiting for previous update to finish...`
57849
+ );
57850
+ const queuedAt = Date.now();
57851
+ const reminder = setInterval(() => {
57852
+ const waited = Math.round((Date.now() - queuedAt) / 1e3);
57853
+ logger.info(
57854
+ `[github-frontend] Comment update for group "${group}" still queued (${waited}s).`
57855
+ );
57856
+ }, 1e4);
56201
57857
  try {
56202
57858
  await existingLock;
56203
57859
  } catch (error) {
56204
57860
  logger.warn(
56205
57861
  `[github-frontend] Previous update for group ${group} failed: ${error instanceof Error ? error.message : error}`
56206
57862
  );
57863
+ } finally {
57864
+ clearInterval(reminder);
57865
+ const waitedMs = Date.now() - queuedAt;
57866
+ if (waitedMs > 100) {
57867
+ logger.info(
57868
+ `[github-frontend] Comment update for group "${group}" dequeued after ${Math.round(waitedMs / 1e3)}s.`
57869
+ );
57870
+ }
56207
57871
  }
56208
57872
  }
56209
57873
  await this.performGroupedCommentUpdate(ctx, comments, group, changedIds);
@@ -56506,7 +58170,7 @@ ${blocks}
56506
58170
  * Sleep utility for enforcing delays
56507
58171
  */
56508
58172
  sleep(ms) {
56509
- return new Promise((resolve15) => setTimeout(resolve15, ms));
58173
+ return new Promise((resolve19) => setTimeout(resolve19, ms));
56510
58174
  }
56511
58175
  };
56512
58176
  }
@@ -57798,15 +59462,15 @@ function serializeRunState(state) {
57798
59462
  ])
57799
59463
  };
57800
59464
  }
57801
- var path26, fs22, StateMachineExecutionEngine;
59465
+ var path30, fs26, StateMachineExecutionEngine;
57802
59466
  var init_state_machine_execution_engine = __esm({
57803
59467
  "src/state-machine-execution-engine.ts"() {
57804
59468
  "use strict";
57805
59469
  init_runner();
57806
59470
  init_logger();
57807
59471
  init_sandbox_manager();
57808
- path26 = __toESM(require("path"));
57809
- fs22 = __toESM(require("fs"));
59472
+ path30 = __toESM(require("path"));
59473
+ fs26 = __toESM(require("fs"));
57810
59474
  StateMachineExecutionEngine = class _StateMachineExecutionEngine {
57811
59475
  workingDirectory;
57812
59476
  executionContext;
@@ -58038,8 +59702,8 @@ var init_state_machine_execution_engine = __esm({
58038
59702
  logger.debug(
58039
59703
  `[PolicyEngine] Loading enterprise policy engine (engine=${configWithTagFilter.policy.engine})`
58040
59704
  );
58041
- const { loadEnterprisePolicyEngine } = await import("./enterprise/loader");
58042
- context2.policyEngine = await loadEnterprisePolicyEngine(configWithTagFilter.policy);
59705
+ const { loadEnterprisePolicyEngine: loadEnterprisePolicyEngine2 } = await Promise.resolve().then(() => (init_loader(), loader_exports));
59706
+ context2.policyEngine = await loadEnterprisePolicyEngine2(configWithTagFilter.policy);
58043
59707
  logger.debug(
58044
59708
  `[PolicyEngine] Initialized: ${context2.policyEngine?.constructor?.name || "unknown"}`
58045
59709
  );
@@ -58191,9 +59855,9 @@ var init_state_machine_execution_engine = __esm({
58191
59855
  }
58192
59856
  const checkId = String(ev?.checkId || "unknown");
58193
59857
  const threadKey = ev?.threadKey || (channel && threadTs ? `${channel}:${threadTs}` : "session");
58194
- const baseDir = process.env.VISOR_SNAPSHOT_DIR || path26.resolve(process.cwd(), ".visor", "snapshots");
58195
- fs22.mkdirSync(baseDir, { recursive: true });
58196
- const filePath = path26.join(baseDir, `${threadKey}-${checkId}.json`);
59858
+ const baseDir = process.env.VISOR_SNAPSHOT_DIR || path30.resolve(process.cwd(), ".visor", "snapshots");
59859
+ fs26.mkdirSync(baseDir, { recursive: true });
59860
+ const filePath = path30.join(baseDir, `${threadKey}-${checkId}.json`);
58197
59861
  await this.saveSnapshotToFile(filePath);
58198
59862
  logger.info(`[Snapshot] Saved run snapshot: ${filePath}`);
58199
59863
  try {
@@ -58334,7 +59998,7 @@ var init_state_machine_execution_engine = __esm({
58334
59998
  * Does not include secrets. Intended for debugging and future resume support.
58335
59999
  */
58336
60000
  async saveSnapshotToFile(filePath) {
58337
- const fs23 = await import("fs/promises");
60001
+ const fs27 = await import("fs/promises");
58338
60002
  const ctx = this._lastContext;
58339
60003
  const runner = this._lastRunner;
58340
60004
  if (!ctx || !runner) {
@@ -58354,14 +60018,14 @@ var init_state_machine_execution_engine = __esm({
58354
60018
  journal: entries,
58355
60019
  requestedChecks: ctx.requestedChecks || []
58356
60020
  };
58357
- await fs23.writeFile(filePath, JSON.stringify(payload, null, 2), "utf8");
60021
+ await fs27.writeFile(filePath, JSON.stringify(payload, null, 2), "utf8");
58358
60022
  }
58359
60023
  /**
58360
60024
  * Load a snapshot JSON from file and return it. Resume support can build on this.
58361
60025
  */
58362
60026
  async loadSnapshotFromFile(filePath) {
58363
- const fs23 = await import("fs/promises");
58364
- const raw = await fs23.readFile(filePath, "utf8");
60027
+ const fs27 = await import("fs/promises");
60028
+ const raw = await fs27.readFile(filePath, "utf8");
58365
60029
  return JSON.parse(raw);
58366
60030
  }
58367
60031
  /**