@probelabs/visor 0.1.177-ee → 0.1.178
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/defaults/code-talk.yaml +10 -5
- package/dist/defaults/code-talk.yaml +10 -5
- package/dist/docs/ai-custom-tools.md +49 -0
- package/dist/docs/http.md +23 -0
- package/dist/docs/testing/cookbook.md +48 -0
- package/dist/docs/testing/dsl-reference.md +4 -2
- package/dist/docs/testing/flows.md +33 -1
- package/dist/examples/http-integration-config.yaml +16 -0
- package/dist/generated/config-schema.d.ts +51 -6
- package/dist/generated/config-schema.d.ts.map +1 -1
- package/dist/generated/config-schema.json +61 -6
- package/dist/github-comments.d.ts +5 -1
- package/dist/github-comments.d.ts.map +1 -1
- package/dist/index.js +407 -1910
- package/dist/output/traces/run-2026-03-11T06-33-05-398Z.ndjson +138 -0
- package/dist/output/traces/run-2026-03-11T06-33-47-884Z.ndjson +2296 -0
- package/dist/providers/api-tool-executor.d.ts +2 -0
- package/dist/providers/api-tool-executor.d.ts.map +1 -1
- package/dist/providers/http-client-provider.d.ts.map +1 -1
- package/dist/providers/mcp-custom-sse-server.d.ts.map +1 -1
- package/dist/providers/workflow-check-provider.d.ts.map +1 -1
- package/dist/sdk/{a2a-frontend-BPWLYLCG.mjs → a2a-frontend-U3PTNCLR.mjs} +2 -2
- package/dist/sdk/{a2a-frontend-FUJRKHJB.mjs → a2a-frontend-WYBMBBYG.mjs} +2 -2
- package/dist/sdk/{check-provider-registry-G64PWDCZ.mjs → check-provider-registry-3DZOXYIA.mjs} +6 -6
- package/dist/sdk/{check-provider-registry-HW4QPPSA.mjs → check-provider-registry-T5J3H2N7.mjs} +6 -6
- package/dist/sdk/check-provider-registry-ZX76MY2L.mjs +30 -0
- package/dist/sdk/{chunk-OPI632LK.mjs → chunk-4ECMTCOM.mjs} +2 -2
- package/dist/sdk/{chunk-65SHRIQF.mjs → chunk-6YGCACBF.mjs} +2 -2
- package/dist/sdk/{chunk-65SHRIQF.mjs.map → chunk-6YGCACBF.mjs.map} +1 -1
- package/dist/sdk/{chunk-IYXOLUDJ.mjs → chunk-AK64Y6Y2.mjs} +222 -37
- package/dist/sdk/chunk-AK64Y6Y2.mjs.map +1 -0
- package/dist/sdk/chunk-ANEKFNAS.mjs +45424 -0
- package/dist/sdk/chunk-ANEKFNAS.mjs.map +1 -0
- package/dist/sdk/{chunk-Y6PVSFCS.mjs → chunk-B7XHSG3L.mjs} +237 -47
- package/dist/sdk/chunk-B7XHSG3L.mjs.map +1 -0
- package/dist/sdk/{chunk-MM3TGVQ4.mjs → chunk-BMXVAJ2M.mjs} +52 -7
- package/dist/sdk/chunk-BMXVAJ2M.mjs.map +1 -0
- package/dist/sdk/{chunk-EFNNJIMY.mjs → chunk-CDRKH5HH.mjs} +2 -2
- package/dist/sdk/{chunk-OHOBWVPP.mjs → chunk-ENSZDV3O.mjs} +3 -3
- package/dist/sdk/{chunk-GVTWESYN.mjs → chunk-KG6PM4OL.mjs} +3 -3
- package/dist/sdk/chunk-KG6PM4OL.mjs.map +1 -0
- package/dist/sdk/{chunk-WJIV7MKY.mjs → chunk-WZS4ARZB.mjs} +3 -3
- package/dist/sdk/{config-OOUMTCEA.mjs → config-DFOF7LP4.mjs} +2 -2
- package/dist/sdk/{failure-condition-evaluator-HL33X7MH.mjs → failure-condition-evaluator-MMPKQGUA.mjs} +3 -3
- package/dist/sdk/{failure-condition-evaluator-DL6H57NX.mjs → failure-condition-evaluator-P3MS5DRL.mjs} +3 -3
- package/dist/sdk/{github-frontend-F2YCPK6H.mjs → github-frontend-7RLEBJWG.mjs} +11 -3
- package/dist/sdk/github-frontend-7RLEBJWG.mjs.map +1 -0
- package/dist/sdk/{github-frontend-U2U42CKV.mjs → github-frontend-QTKOYB56.mjs} +11 -3
- package/dist/sdk/github-frontend-QTKOYB56.mjs.map +1 -0
- package/dist/sdk/{host-HFOJQIOF.mjs → host-I2TBBKD5.mjs} +3 -3
- package/dist/sdk/{host-6TBS44ER.mjs → host-SE3MQHWG.mjs} +4 -4
- package/dist/sdk/{routing-GF2CF3JT.mjs → routing-2X6QF5IW.mjs} +4 -4
- package/dist/sdk/{routing-SFP4D6O3.mjs → routing-QHXBQS6X.mjs} +4 -4
- package/dist/sdk/{schedule-tool-45NAALKS.mjs → schedule-tool-MKT5FZ6J.mjs} +6 -6
- package/dist/sdk/{schedule-tool-7O7SWSJ4.mjs → schedule-tool-R6JJIDZ6.mjs} +6 -6
- package/dist/sdk/schedule-tool-W4SQ334O.mjs +36 -0
- package/dist/sdk/{schedule-tool-handler-6MPP5DXK.mjs → schedule-tool-handler-AOMZV3Q3.mjs} +6 -6
- package/dist/sdk/{schedule-tool-handler-KYDXJ2ZL.mjs → schedule-tool-handler-MPJFLH4J.mjs} +6 -6
- package/dist/sdk/schedule-tool-handler-WY7WCFE5.mjs +40 -0
- package/dist/sdk/sdk.d.mts +21 -0
- package/dist/sdk/sdk.d.ts +21 -0
- package/dist/sdk/sdk.js +545 -1681
- package/dist/sdk/sdk.js.map +1 -1
- package/dist/sdk/sdk.mjs +5 -5
- package/dist/sdk/{trace-helpers-FKM2MEDW.mjs → trace-helpers-4ADQ4GB3.mjs} +2 -2
- package/dist/sdk/{trace-helpers-L3EOYW5P.mjs → trace-helpers-K47ZVJSU.mjs} +2 -2
- package/dist/sdk/trace-helpers-K47ZVJSU.mjs.map +1 -0
- package/dist/sdk/{workflow-check-provider-JIXZJNV5.mjs → workflow-check-provider-A3YH2UZJ.mjs} +6 -6
- package/dist/sdk/workflow-check-provider-A3YH2UZJ.mjs.map +1 -0
- package/dist/sdk/{workflow-check-provider-OA33MESM.mjs → workflow-check-provider-WHZP7BDF.mjs} +6 -6
- package/dist/sdk/workflow-check-provider-WHZP7BDF.mjs.map +1 -0
- package/dist/sdk/workflow-check-provider-WZN3B2S2.mjs +30 -0
- package/dist/sdk/workflow-check-provider-WZN3B2S2.mjs.map +1 -0
- package/dist/state-machine/context/build-engine-context.d.ts.map +1 -1
- package/dist/test-runner/conversation-sugar.d.ts +3 -0
- package/dist/test-runner/conversation-sugar.d.ts.map +1 -1
- package/dist/test-runner/validator.d.ts.map +1 -1
- package/dist/traces/run-2026-03-11T06-33-05-398Z.ndjson +138 -0
- package/dist/traces/run-2026-03-11T06-33-47-884Z.ndjson +2296 -0
- package/dist/types/config.d.ts +21 -0
- package/dist/types/config.d.ts.map +1 -1
- package/dist/utils/rate-limiter.d.ts +61 -0
- package/dist/utils/rate-limiter.d.ts.map +1 -0
- package/package.json +2 -2
- package/dist/sdk/chunk-GVTWESYN.mjs.map +0 -1
- package/dist/sdk/chunk-IYXOLUDJ.mjs.map +0 -1
- package/dist/sdk/chunk-MM3TGVQ4.mjs.map +0 -1
- package/dist/sdk/chunk-Y6PVSFCS.mjs.map +0 -1
- package/dist/sdk/github-frontend-F2YCPK6H.mjs.map +0 -1
- package/dist/sdk/github-frontend-U2U42CKV.mjs.map +0 -1
- package/dist/sdk/knex-store-QCEW4I4R.mjs +0 -527
- package/dist/sdk/knex-store-QCEW4I4R.mjs.map +0 -1
- package/dist/sdk/loader-Q7K76ZIY.mjs +0 -89
- package/dist/sdk/loader-Q7K76ZIY.mjs.map +0 -1
- package/dist/sdk/opa-policy-engine-QCSSIMUF.mjs +0 -655
- package/dist/sdk/opa-policy-engine-QCSSIMUF.mjs.map +0 -1
- package/dist/sdk/slack-frontend-6SXPTQDI.mjs +0 -895
- package/dist/sdk/slack-frontend-6SXPTQDI.mjs.map +0 -1
- package/dist/sdk/validator-XTZJZZJH.mjs +0 -134
- package/dist/sdk/validator-XTZJZZJH.mjs.map +0 -1
- /package/dist/sdk/{a2a-frontend-BPWLYLCG.mjs.map → a2a-frontend-U3PTNCLR.mjs.map} +0 -0
- /package/dist/sdk/{a2a-frontend-FUJRKHJB.mjs.map → a2a-frontend-WYBMBBYG.mjs.map} +0 -0
- /package/dist/sdk/{check-provider-registry-G64PWDCZ.mjs.map → check-provider-registry-3DZOXYIA.mjs.map} +0 -0
- /package/dist/sdk/{check-provider-registry-HW4QPPSA.mjs.map → check-provider-registry-T5J3H2N7.mjs.map} +0 -0
- /package/dist/sdk/{config-OOUMTCEA.mjs.map → check-provider-registry-ZX76MY2L.mjs.map} +0 -0
- /package/dist/sdk/{chunk-EFNNJIMY.mjs.map → chunk-4ECMTCOM.mjs.map} +0 -0
- /package/dist/sdk/{chunk-OPI632LK.mjs.map → chunk-CDRKH5HH.mjs.map} +0 -0
- /package/dist/sdk/{chunk-OHOBWVPP.mjs.map → chunk-ENSZDV3O.mjs.map} +0 -0
- /package/dist/sdk/{chunk-WJIV7MKY.mjs.map → chunk-WZS4ARZB.mjs.map} +0 -0
- /package/dist/sdk/{failure-condition-evaluator-DL6H57NX.mjs.map → config-DFOF7LP4.mjs.map} +0 -0
- /package/dist/sdk/{failure-condition-evaluator-HL33X7MH.mjs.map → failure-condition-evaluator-MMPKQGUA.mjs.map} +0 -0
- /package/dist/sdk/{routing-GF2CF3JT.mjs.map → failure-condition-evaluator-P3MS5DRL.mjs.map} +0 -0
- /package/dist/sdk/{host-6TBS44ER.mjs.map → host-I2TBBKD5.mjs.map} +0 -0
- /package/dist/sdk/{host-HFOJQIOF.mjs.map → host-SE3MQHWG.mjs.map} +0 -0
- /package/dist/sdk/{routing-SFP4D6O3.mjs.map → routing-2X6QF5IW.mjs.map} +0 -0
- /package/dist/sdk/{schedule-tool-45NAALKS.mjs.map → routing-QHXBQS6X.mjs.map} +0 -0
- /package/dist/sdk/{schedule-tool-7O7SWSJ4.mjs.map → schedule-tool-MKT5FZ6J.mjs.map} +0 -0
- /package/dist/sdk/{schedule-tool-handler-6MPP5DXK.mjs.map → schedule-tool-R6JJIDZ6.mjs.map} +0 -0
- /package/dist/sdk/{schedule-tool-handler-KYDXJ2ZL.mjs.map → schedule-tool-W4SQ334O.mjs.map} +0 -0
- /package/dist/sdk/{trace-helpers-FKM2MEDW.mjs.map → schedule-tool-handler-AOMZV3Q3.mjs.map} +0 -0
- /package/dist/sdk/{trace-helpers-L3EOYW5P.mjs.map → schedule-tool-handler-MPJFLH4J.mjs.map} +0 -0
- /package/dist/sdk/{workflow-check-provider-JIXZJNV5.mjs.map → schedule-tool-handler-WY7WCFE5.mjs.map} +0 -0
- /package/dist/sdk/{workflow-check-provider-OA33MESM.mjs.map → trace-helpers-4ADQ4GB3.mjs.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
process.env.VISOR_VERSION = '0.1.
|
|
3
|
-
process.env.PROBE_VERSION = '0.6.0-
|
|
4
|
-
process.env.VISOR_COMMIT_SHA = '
|
|
5
|
-
process.env.VISOR_COMMIT_SHORT = '
|
|
2
|
+
process.env.VISOR_VERSION = '0.1.178';
|
|
3
|
+
process.env.PROBE_VERSION = '0.6.0-rc293';
|
|
4
|
+
process.env.VISOR_COMMIT_SHA = '79fcc6344e1ab954501ff6a7f9614a0372019b2b';
|
|
5
|
+
process.env.VISOR_COMMIT_SHORT = '79fcc6344';
|
|
6
6
|
/******/ (() => { // webpackBootstrap
|
|
7
7
|
/******/ var __webpack_modules__ = ({
|
|
8
8
|
|
|
@@ -302997,7 +302997,7 @@ async function handleDumpPolicyInput(checkId, argv) {
|
|
|
302997
302997
|
let PolicyInputBuilder;
|
|
302998
302998
|
try {
|
|
302999
302999
|
// @ts-ignore — enterprise/ may not exist in OSS builds (caught at runtime)
|
|
303000
|
-
const mod = await Promise.resolve().then(() => __importStar(__nccwpck_require__(
|
|
303000
|
+
const mod = await Promise.resolve().then(() => __importStar(__nccwpck_require__(71370)));
|
|
303001
303001
|
PolicyInputBuilder = mod.PolicyInputBuilder;
|
|
303002
303002
|
}
|
|
303003
303003
|
catch {
|
|
@@ -303229,7 +303229,7 @@ steps:
|
|
|
303229
303229
|
You are a senior software engineer. Use the provided tools to explore
|
|
303230
303230
|
the codebase. Always verify your assumptions by reading actual code.
|
|
303231
303231
|
Be concise and cite file paths in your response.
|
|
303232
|
-
max_iterations:
|
|
303232
|
+
max_iterations: 50
|
|
303233
303233
|
ai_custom_tools: [search-code, list-files, read-file]
|
|
303234
303234
|
enable_bash: true # also allow direct shell commands
|
|
303235
303235
|
tags: [agent]
|
|
@@ -311069,1810 +311069,6 @@ class EmailPollingRunner {
|
|
|
311069
311069
|
exports.EmailPollingRunner = EmailPollingRunner;
|
|
311070
311070
|
|
|
311071
311071
|
|
|
311072
|
-
/***/ }),
|
|
311073
|
-
|
|
311074
|
-
/***/ 50069:
|
|
311075
|
-
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
|
|
311076
|
-
|
|
311077
|
-
"use strict";
|
|
311078
|
-
|
|
311079
|
-
/**
|
|
311080
|
-
* Copyright (c) ProbeLabs. All rights reserved.
|
|
311081
|
-
* Licensed under the Elastic License 2.0; you may not use this file except
|
|
311082
|
-
* in compliance with the Elastic License 2.0.
|
|
311083
|
-
*/
|
|
311084
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
311085
|
-
if (k2 === undefined) k2 = k;
|
|
311086
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
311087
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
311088
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
311089
|
-
}
|
|
311090
|
-
Object.defineProperty(o, k2, desc);
|
|
311091
|
-
}) : (function(o, m, k, k2) {
|
|
311092
|
-
if (k2 === undefined) k2 = k;
|
|
311093
|
-
o[k2] = m[k];
|
|
311094
|
-
}));
|
|
311095
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
311096
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
311097
|
-
}) : function(o, v) {
|
|
311098
|
-
o["default"] = v;
|
|
311099
|
-
});
|
|
311100
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
311101
|
-
var ownKeys = function(o) {
|
|
311102
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
311103
|
-
var ar = [];
|
|
311104
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
311105
|
-
return ar;
|
|
311106
|
-
};
|
|
311107
|
-
return ownKeys(o);
|
|
311108
|
-
};
|
|
311109
|
-
return function (mod) {
|
|
311110
|
-
if (mod && mod.__esModule) return mod;
|
|
311111
|
-
var result = {};
|
|
311112
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
311113
|
-
__setModuleDefault(result, mod);
|
|
311114
|
-
return result;
|
|
311115
|
-
};
|
|
311116
|
-
})();
|
|
311117
|
-
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
311118
|
-
exports.LicenseValidator = void 0;
|
|
311119
|
-
const crypto = __importStar(__nccwpck_require__(76982));
|
|
311120
|
-
const fs = __importStar(__nccwpck_require__(79896));
|
|
311121
|
-
const path = __importStar(__nccwpck_require__(16928));
|
|
311122
|
-
class LicenseValidator {
|
|
311123
|
-
/** Ed25519 public key for license verification (PEM format). */
|
|
311124
|
-
static PUBLIC_KEY = '-----BEGIN PUBLIC KEY-----\n' +
|
|
311125
|
-
'MCowBQYDK2VwAyEAI/Zd08EFmgIdrDm/HXd0l3/5GBt7R1PrdvhdmEXhJlU=\n' +
|
|
311126
|
-
'-----END PUBLIC KEY-----\n';
|
|
311127
|
-
cache = null;
|
|
311128
|
-
static CACHE_TTL = 5 * 60 * 1000; // 5 minutes
|
|
311129
|
-
static GRACE_PERIOD = 72 * 3600 * 1000; // 72 hours after expiry
|
|
311130
|
-
/**
|
|
311131
|
-
* Load and validate license from environment or file.
|
|
311132
|
-
*
|
|
311133
|
-
* Resolution order:
|
|
311134
|
-
* 1. VISOR_LICENSE env var (JWT string)
|
|
311135
|
-
* 2. VISOR_LICENSE_FILE env var (path to file)
|
|
311136
|
-
* 3. .visor-license in project root (cwd)
|
|
311137
|
-
* 4. .visor-license in ~/.config/visor/
|
|
311138
|
-
*/
|
|
311139
|
-
async loadAndValidate() {
|
|
311140
|
-
// Return cached result if still fresh
|
|
311141
|
-
if (this.cache && Date.now() - this.cache.validatedAt < LicenseValidator.CACHE_TTL) {
|
|
311142
|
-
return this.cache.payload;
|
|
311143
|
-
}
|
|
311144
|
-
const token = this.resolveToken();
|
|
311145
|
-
if (!token)
|
|
311146
|
-
return null;
|
|
311147
|
-
const payload = this.verifyAndDecode(token);
|
|
311148
|
-
if (!payload)
|
|
311149
|
-
return null;
|
|
311150
|
-
this.cache = { payload, validatedAt: Date.now() };
|
|
311151
|
-
return payload;
|
|
311152
|
-
}
|
|
311153
|
-
/** Check if a specific feature is licensed */
|
|
311154
|
-
hasFeature(feature) {
|
|
311155
|
-
if (!this.cache)
|
|
311156
|
-
return false;
|
|
311157
|
-
return this.cache.payload.features.includes(feature);
|
|
311158
|
-
}
|
|
311159
|
-
/** Check if license is valid (with grace period) */
|
|
311160
|
-
isValid() {
|
|
311161
|
-
if (!this.cache)
|
|
311162
|
-
return false;
|
|
311163
|
-
const now = Date.now();
|
|
311164
|
-
const expiryMs = this.cache.payload.exp * 1000;
|
|
311165
|
-
return now < expiryMs + LicenseValidator.GRACE_PERIOD;
|
|
311166
|
-
}
|
|
311167
|
-
/** Check if the license is within its grace period (expired but still valid) */
|
|
311168
|
-
isInGracePeriod() {
|
|
311169
|
-
if (!this.cache)
|
|
311170
|
-
return false;
|
|
311171
|
-
const now = Date.now();
|
|
311172
|
-
const expiryMs = this.cache.payload.exp * 1000;
|
|
311173
|
-
return now >= expiryMs && now < expiryMs + LicenseValidator.GRACE_PERIOD;
|
|
311174
|
-
}
|
|
311175
|
-
resolveToken() {
|
|
311176
|
-
// 1. Direct env var
|
|
311177
|
-
if (process.env.VISOR_LICENSE) {
|
|
311178
|
-
return process.env.VISOR_LICENSE.trim();
|
|
311179
|
-
}
|
|
311180
|
-
// 2. File path from env (validate against path traversal)
|
|
311181
|
-
if (process.env.VISOR_LICENSE_FILE) {
|
|
311182
|
-
// path.resolve() produces an absolute path with all '..' segments resolved,
|
|
311183
|
-
// so a separate resolved.includes('..') check is unnecessary.
|
|
311184
|
-
const resolved = path.resolve(process.env.VISOR_LICENSE_FILE);
|
|
311185
|
-
const home = process.env.HOME || process.env.USERPROFILE || '';
|
|
311186
|
-
const allowedPrefixes = [path.normalize(process.cwd())];
|
|
311187
|
-
if (home)
|
|
311188
|
-
allowedPrefixes.push(path.normalize(path.join(home, '.config', 'visor')));
|
|
311189
|
-
// Resolve symlinks so an attacker cannot create a symlink inside an
|
|
311190
|
-
// allowed prefix that points to an arbitrary file outside it.
|
|
311191
|
-
let realPath;
|
|
311192
|
-
try {
|
|
311193
|
-
realPath = fs.realpathSync(resolved);
|
|
311194
|
-
}
|
|
311195
|
-
catch {
|
|
311196
|
-
return null; // File doesn't exist or isn't accessible
|
|
311197
|
-
}
|
|
311198
|
-
const isSafe = allowedPrefixes.some(prefix => realPath === prefix || realPath.startsWith(prefix + path.sep));
|
|
311199
|
-
if (!isSafe)
|
|
311200
|
-
return null;
|
|
311201
|
-
return this.readFile(realPath);
|
|
311202
|
-
}
|
|
311203
|
-
// 3. .visor-license in cwd
|
|
311204
|
-
const cwdPath = path.join(process.cwd(), '.visor-license');
|
|
311205
|
-
const cwdToken = this.readFile(cwdPath);
|
|
311206
|
-
if (cwdToken)
|
|
311207
|
-
return cwdToken;
|
|
311208
|
-
// 4. ~/.config/visor/.visor-license
|
|
311209
|
-
const home = process.env.HOME || process.env.USERPROFILE || '';
|
|
311210
|
-
if (home) {
|
|
311211
|
-
const configPath = path.join(home, '.config', 'visor', '.visor-license');
|
|
311212
|
-
const configToken = this.readFile(configPath);
|
|
311213
|
-
if (configToken)
|
|
311214
|
-
return configToken;
|
|
311215
|
-
}
|
|
311216
|
-
return null;
|
|
311217
|
-
}
|
|
311218
|
-
readFile(filePath) {
|
|
311219
|
-
try {
|
|
311220
|
-
return fs.readFileSync(filePath, 'utf-8').trim();
|
|
311221
|
-
}
|
|
311222
|
-
catch {
|
|
311223
|
-
return null;
|
|
311224
|
-
}
|
|
311225
|
-
}
|
|
311226
|
-
verifyAndDecode(token) {
|
|
311227
|
-
try {
|
|
311228
|
-
const parts = token.split('.');
|
|
311229
|
-
if (parts.length !== 3)
|
|
311230
|
-
return null;
|
|
311231
|
-
const [headerB64, payloadB64, signatureB64] = parts;
|
|
311232
|
-
// Decode header to verify algorithm
|
|
311233
|
-
const header = JSON.parse(Buffer.from(headerB64, 'base64url').toString());
|
|
311234
|
-
if (header.alg !== 'EdDSA')
|
|
311235
|
-
return null;
|
|
311236
|
-
// Verify signature
|
|
311237
|
-
const data = `${headerB64}.${payloadB64}`;
|
|
311238
|
-
const signature = Buffer.from(signatureB64, 'base64url');
|
|
311239
|
-
const publicKey = crypto.createPublicKey(LicenseValidator.PUBLIC_KEY);
|
|
311240
|
-
// Validate that the loaded public key is actually Ed25519 (OID 1.3.101.112).
|
|
311241
|
-
// This prevents algorithm-confusion attacks if the embedded key were ever
|
|
311242
|
-
// swapped to a different type.
|
|
311243
|
-
if (publicKey.asymmetricKeyType !== 'ed25519') {
|
|
311244
|
-
return null;
|
|
311245
|
-
}
|
|
311246
|
-
// Ed25519 verification: algorithm must be null because EdDSA performs its
|
|
311247
|
-
// own internal hashing (SHA-512) — passing a digest algorithm here would
|
|
311248
|
-
// cause Node.js to throw. The key type is validated above.
|
|
311249
|
-
const isValid = crypto.verify(null, Buffer.from(data), publicKey, signature);
|
|
311250
|
-
if (!isValid)
|
|
311251
|
-
return null;
|
|
311252
|
-
// Decode payload
|
|
311253
|
-
const payload = JSON.parse(Buffer.from(payloadB64, 'base64url').toString());
|
|
311254
|
-
// Validate required fields
|
|
311255
|
-
if (!payload.org ||
|
|
311256
|
-
!Array.isArray(payload.features) ||
|
|
311257
|
-
typeof payload.exp !== 'number' ||
|
|
311258
|
-
typeof payload.iat !== 'number' ||
|
|
311259
|
-
!payload.sub) {
|
|
311260
|
-
return null;
|
|
311261
|
-
}
|
|
311262
|
-
// Check expiry (with grace period)
|
|
311263
|
-
const now = Date.now();
|
|
311264
|
-
const expiryMs = payload.exp * 1000;
|
|
311265
|
-
if (now >= expiryMs + LicenseValidator.GRACE_PERIOD) {
|
|
311266
|
-
return null;
|
|
311267
|
-
}
|
|
311268
|
-
return payload;
|
|
311269
|
-
}
|
|
311270
|
-
catch {
|
|
311271
|
-
return null;
|
|
311272
|
-
}
|
|
311273
|
-
}
|
|
311274
|
-
}
|
|
311275
|
-
exports.LicenseValidator = LicenseValidator;
|
|
311276
|
-
|
|
311277
|
-
|
|
311278
|
-
/***/ }),
|
|
311279
|
-
|
|
311280
|
-
/***/ 87068:
|
|
311281
|
-
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
|
|
311282
|
-
|
|
311283
|
-
"use strict";
|
|
311284
|
-
|
|
311285
|
-
/**
|
|
311286
|
-
* Copyright (c) ProbeLabs. All rights reserved.
|
|
311287
|
-
* Licensed under the Elastic License 2.0; you may not use this file except
|
|
311288
|
-
* in compliance with the Elastic License 2.0.
|
|
311289
|
-
*/
|
|
311290
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
311291
|
-
if (k2 === undefined) k2 = k;
|
|
311292
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
311293
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
311294
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
311295
|
-
}
|
|
311296
|
-
Object.defineProperty(o, k2, desc);
|
|
311297
|
-
}) : (function(o, m, k, k2) {
|
|
311298
|
-
if (k2 === undefined) k2 = k;
|
|
311299
|
-
o[k2] = m[k];
|
|
311300
|
-
}));
|
|
311301
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
311302
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
311303
|
-
}) : function(o, v) {
|
|
311304
|
-
o["default"] = v;
|
|
311305
|
-
});
|
|
311306
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
311307
|
-
var ownKeys = function(o) {
|
|
311308
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
311309
|
-
var ar = [];
|
|
311310
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
311311
|
-
return ar;
|
|
311312
|
-
};
|
|
311313
|
-
return ownKeys(o);
|
|
311314
|
-
};
|
|
311315
|
-
return function (mod) {
|
|
311316
|
-
if (mod && mod.__esModule) return mod;
|
|
311317
|
-
var result = {};
|
|
311318
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
311319
|
-
__setModuleDefault(result, mod);
|
|
311320
|
-
return result;
|
|
311321
|
-
};
|
|
311322
|
-
})();
|
|
311323
|
-
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
311324
|
-
exports.loadEnterprisePolicyEngine = loadEnterprisePolicyEngine;
|
|
311325
|
-
exports.loadEnterpriseStoreBackend = loadEnterpriseStoreBackend;
|
|
311326
|
-
const default_engine_1 = __nccwpck_require__(93866);
|
|
311327
|
-
/**
|
|
311328
|
-
* Load the enterprise policy engine if licensed, otherwise return the default no-op engine.
|
|
311329
|
-
*
|
|
311330
|
-
* This is the sole import boundary between OSS and enterprise code. Core code
|
|
311331
|
-
* must only import from this module (via dynamic `await import()`), never from
|
|
311332
|
-
* individual enterprise submodules.
|
|
311333
|
-
*/
|
|
311334
|
-
async function loadEnterprisePolicyEngine(config) {
|
|
311335
|
-
try {
|
|
311336
|
-
const { LicenseValidator } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(50069)));
|
|
311337
|
-
const validator = new LicenseValidator();
|
|
311338
|
-
const license = await validator.loadAndValidate();
|
|
311339
|
-
if (!license || !validator.hasFeature('policy')) {
|
|
311340
|
-
return new default_engine_1.DefaultPolicyEngine();
|
|
311341
|
-
}
|
|
311342
|
-
if (validator.isInGracePeriod()) {
|
|
311343
|
-
// eslint-disable-next-line no-console
|
|
311344
|
-
console.warn('[visor:enterprise] License has expired but is within the 72-hour grace period. ' +
|
|
311345
|
-
'Please renew your license.');
|
|
311346
|
-
}
|
|
311347
|
-
const { OpaPolicyEngine } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(39530)));
|
|
311348
|
-
const engine = new OpaPolicyEngine(config);
|
|
311349
|
-
await engine.initialize(config);
|
|
311350
|
-
return engine;
|
|
311351
|
-
}
|
|
311352
|
-
catch (err) {
|
|
311353
|
-
// Enterprise code not available or initialization failed
|
|
311354
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
311355
|
-
try {
|
|
311356
|
-
const { logger } = __nccwpck_require__(86999);
|
|
311357
|
-
logger.warn(`[PolicyEngine] Enterprise policy init failed, falling back to default: ${msg}`);
|
|
311358
|
-
}
|
|
311359
|
-
catch {
|
|
311360
|
-
// silent
|
|
311361
|
-
}
|
|
311362
|
-
return new default_engine_1.DefaultPolicyEngine();
|
|
311363
|
-
}
|
|
311364
|
-
}
|
|
311365
|
-
/**
|
|
311366
|
-
* Load the enterprise schedule store backend if licensed.
|
|
311367
|
-
*
|
|
311368
|
-
* @param driver Database driver ('postgresql', 'mysql', or 'mssql')
|
|
311369
|
-
* @param storageConfig Storage configuration with connection details
|
|
311370
|
-
* @param haConfig Optional HA configuration
|
|
311371
|
-
* @throws Error if enterprise license is not available or missing 'scheduler-sql' feature
|
|
311372
|
-
*/
|
|
311373
|
-
async function loadEnterpriseStoreBackend(driver, storageConfig, haConfig) {
|
|
311374
|
-
const { LicenseValidator } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(50069)));
|
|
311375
|
-
const validator = new LicenseValidator();
|
|
311376
|
-
const license = await validator.loadAndValidate();
|
|
311377
|
-
if (!license || !validator.hasFeature('scheduler-sql')) {
|
|
311378
|
-
throw new Error(`The ${driver} schedule storage driver requires a Visor Enterprise license ` +
|
|
311379
|
-
`with the 'scheduler-sql' feature. Please upgrade or use driver: 'sqlite' (default).`);
|
|
311380
|
-
}
|
|
311381
|
-
if (validator.isInGracePeriod()) {
|
|
311382
|
-
// eslint-disable-next-line no-console
|
|
311383
|
-
console.warn('[visor:enterprise] License has expired but is within the 72-hour grace period. ' +
|
|
311384
|
-
'Please renew your license.');
|
|
311385
|
-
}
|
|
311386
|
-
const { KnexStoreBackend } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(63737)));
|
|
311387
|
-
return new KnexStoreBackend(driver, storageConfig, haConfig);
|
|
311388
|
-
}
|
|
311389
|
-
|
|
311390
|
-
|
|
311391
|
-
/***/ }),
|
|
311392
|
-
|
|
311393
|
-
/***/ 628:
|
|
311394
|
-
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
|
|
311395
|
-
|
|
311396
|
-
"use strict";
|
|
311397
|
-
|
|
311398
|
-
/**
|
|
311399
|
-
* Copyright (c) ProbeLabs. All rights reserved.
|
|
311400
|
-
* Licensed under the Elastic License 2.0; you may not use this file except
|
|
311401
|
-
* in compliance with the Elastic License 2.0.
|
|
311402
|
-
*/
|
|
311403
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
311404
|
-
if (k2 === undefined) k2 = k;
|
|
311405
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
311406
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
311407
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
311408
|
-
}
|
|
311409
|
-
Object.defineProperty(o, k2, desc);
|
|
311410
|
-
}) : (function(o, m, k, k2) {
|
|
311411
|
-
if (k2 === undefined) k2 = k;
|
|
311412
|
-
o[k2] = m[k];
|
|
311413
|
-
}));
|
|
311414
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
311415
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
311416
|
-
}) : function(o, v) {
|
|
311417
|
-
o["default"] = v;
|
|
311418
|
-
});
|
|
311419
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
311420
|
-
var ownKeys = function(o) {
|
|
311421
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
311422
|
-
var ar = [];
|
|
311423
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
311424
|
-
return ar;
|
|
311425
|
-
};
|
|
311426
|
-
return ownKeys(o);
|
|
311427
|
-
};
|
|
311428
|
-
return function (mod) {
|
|
311429
|
-
if (mod && mod.__esModule) return mod;
|
|
311430
|
-
var result = {};
|
|
311431
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
311432
|
-
__setModuleDefault(result, mod);
|
|
311433
|
-
return result;
|
|
311434
|
-
};
|
|
311435
|
-
})();
|
|
311436
|
-
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
311437
|
-
exports.OpaCompiler = void 0;
|
|
311438
|
-
const fs = __importStar(__nccwpck_require__(79896));
|
|
311439
|
-
const path = __importStar(__nccwpck_require__(16928));
|
|
311440
|
-
const os = __importStar(__nccwpck_require__(70857));
|
|
311441
|
-
const crypto = __importStar(__nccwpck_require__(76982));
|
|
311442
|
-
const child_process_1 = __nccwpck_require__(35317);
|
|
311443
|
-
/**
|
|
311444
|
-
* OPA Rego Compiler - compiles .rego policy files to WASM bundles using the `opa` CLI.
|
|
311445
|
-
*
|
|
311446
|
-
* Handles:
|
|
311447
|
-
* - Resolving input paths to WASM bytes (direct .wasm, directory with policy.wasm, or .rego files)
|
|
311448
|
-
* - Compiling .rego files to WASM via `opa build`
|
|
311449
|
-
* - Caching compiled bundles based on content hashes
|
|
311450
|
-
* - Extracting policy.wasm from OPA tar.gz bundles
|
|
311451
|
-
*
|
|
311452
|
-
* Requires:
|
|
311453
|
-
* - `opa` CLI on PATH (only when auto-compiling .rego files)
|
|
311454
|
-
*/
|
|
311455
|
-
class OpaCompiler {
|
|
311456
|
-
static CACHE_DIR = path.join(os.tmpdir(), 'visor-opa-cache');
|
|
311457
|
-
/**
|
|
311458
|
-
* Resolve the input paths to WASM bytes.
|
|
311459
|
-
*
|
|
311460
|
-
* Strategy:
|
|
311461
|
-
* 1. If any path is a .wasm file, read it directly
|
|
311462
|
-
* 2. If a directory contains policy.wasm, read it
|
|
311463
|
-
* 3. Otherwise, collect all .rego files and auto-compile via `opa build`
|
|
311464
|
-
*/
|
|
311465
|
-
async resolveWasmBytes(paths) {
|
|
311466
|
-
// Collect .rego files and check for existing .wasm
|
|
311467
|
-
const regoFiles = [];
|
|
311468
|
-
for (const p of paths) {
|
|
311469
|
-
const resolved = path.resolve(p);
|
|
311470
|
-
// Reject paths containing '..' after resolution (path traversal)
|
|
311471
|
-
if (path.normalize(resolved).includes('..')) {
|
|
311472
|
-
throw new Error(`Policy path contains traversal sequences: ${p}`);
|
|
311473
|
-
}
|
|
311474
|
-
// Direct .wasm file
|
|
311475
|
-
if (resolved.endsWith('.wasm') && fs.existsSync(resolved)) {
|
|
311476
|
-
return fs.readFileSync(resolved);
|
|
311477
|
-
}
|
|
311478
|
-
if (!fs.existsSync(resolved))
|
|
311479
|
-
continue;
|
|
311480
|
-
const stat = fs.statSync(resolved);
|
|
311481
|
-
if (stat.isDirectory()) {
|
|
311482
|
-
// Check for pre-compiled policy.wasm in directory
|
|
311483
|
-
const wasmCandidate = path.join(resolved, 'policy.wasm');
|
|
311484
|
-
if (fs.existsSync(wasmCandidate)) {
|
|
311485
|
-
return fs.readFileSync(wasmCandidate);
|
|
311486
|
-
}
|
|
311487
|
-
// Collect all .rego files from directory
|
|
311488
|
-
const files = fs.readdirSync(resolved);
|
|
311489
|
-
for (const f of files) {
|
|
311490
|
-
if (f.endsWith('.rego')) {
|
|
311491
|
-
regoFiles.push(path.join(resolved, f));
|
|
311492
|
-
}
|
|
311493
|
-
}
|
|
311494
|
-
}
|
|
311495
|
-
else if (resolved.endsWith('.rego')) {
|
|
311496
|
-
regoFiles.push(resolved);
|
|
311497
|
-
}
|
|
311498
|
-
}
|
|
311499
|
-
if (regoFiles.length === 0) {
|
|
311500
|
-
throw new Error(`OPA WASM evaluator: no .wasm bundle or .rego files found in: ${paths.join(', ')}`);
|
|
311501
|
-
}
|
|
311502
|
-
// Auto-compile .rego -> .wasm
|
|
311503
|
-
return this.compileRego(regoFiles);
|
|
311504
|
-
}
|
|
311505
|
-
/**
|
|
311506
|
-
* Auto-compile .rego files to a WASM bundle using the `opa` CLI.
|
|
311507
|
-
*
|
|
311508
|
-
* Caches the compiled bundle based on a content hash of all input .rego files
|
|
311509
|
-
* so subsequent runs skip compilation if policies haven't changed.
|
|
311510
|
-
*/
|
|
311511
|
-
compileRego(regoFiles) {
|
|
311512
|
-
// Check that `opa` CLI is available
|
|
311513
|
-
try {
|
|
311514
|
-
(0, child_process_1.execFileSync)('opa', ['version'], { stdio: 'pipe' });
|
|
311515
|
-
}
|
|
311516
|
-
catch {
|
|
311517
|
-
throw new Error('OPA CLI (`opa`) not found on PATH. Install it from https://www.openpolicyagent.org/docs/latest/#running-opa\n' +
|
|
311518
|
-
'Or pre-compile your .rego files: opa build -t wasm -e visor -o bundle.tar.gz ' +
|
|
311519
|
-
regoFiles.join(' '));
|
|
311520
|
-
}
|
|
311521
|
-
// Compute content hash for cache key
|
|
311522
|
-
const hash = crypto.createHash('sha256');
|
|
311523
|
-
for (const f of regoFiles.sort()) {
|
|
311524
|
-
hash.update(fs.readFileSync(f));
|
|
311525
|
-
hash.update(f); // include filename for disambiguation
|
|
311526
|
-
}
|
|
311527
|
-
const cacheKey = hash.digest('hex').slice(0, 16);
|
|
311528
|
-
const cacheDir = OpaCompiler.CACHE_DIR;
|
|
311529
|
-
const cachedWasm = path.join(cacheDir, `${cacheKey}.wasm`);
|
|
311530
|
-
// Return cached bundle if still valid
|
|
311531
|
-
if (fs.existsSync(cachedWasm)) {
|
|
311532
|
-
return fs.readFileSync(cachedWasm);
|
|
311533
|
-
}
|
|
311534
|
-
// Compile to WASM via opa build
|
|
311535
|
-
fs.mkdirSync(cacheDir, { recursive: true });
|
|
311536
|
-
const bundleTar = path.join(cacheDir, `${cacheKey}-bundle.tar.gz`);
|
|
311537
|
-
try {
|
|
311538
|
-
const args = [
|
|
311539
|
-
'build',
|
|
311540
|
-
'-t',
|
|
311541
|
-
'wasm',
|
|
311542
|
-
'-e',
|
|
311543
|
-
'visor', // entrypoint: the visor package tree
|
|
311544
|
-
'-o',
|
|
311545
|
-
bundleTar,
|
|
311546
|
-
...regoFiles,
|
|
311547
|
-
];
|
|
311548
|
-
(0, child_process_1.execFileSync)('opa', args, {
|
|
311549
|
-
stdio: 'pipe',
|
|
311550
|
-
timeout: 30000,
|
|
311551
|
-
});
|
|
311552
|
-
}
|
|
311553
|
-
catch (err) {
|
|
311554
|
-
const stderr = err?.stderr?.toString() || '';
|
|
311555
|
-
throw new Error(`Failed to compile .rego files to WASM:\n${stderr}\n` +
|
|
311556
|
-
'Ensure your .rego files are valid and the `opa` CLI is installed.');
|
|
311557
|
-
}
|
|
311558
|
-
// Extract policy.wasm from the tar.gz bundle
|
|
311559
|
-
// OPA bundles are tar.gz with /policy.wasm inside
|
|
311560
|
-
try {
|
|
311561
|
-
(0, child_process_1.execFileSync)('tar', ['-xzf', bundleTar, '-C', cacheDir, '/policy.wasm'], {
|
|
311562
|
-
stdio: 'pipe',
|
|
311563
|
-
});
|
|
311564
|
-
const extractedWasm = path.join(cacheDir, 'policy.wasm');
|
|
311565
|
-
if (fs.existsSync(extractedWasm)) {
|
|
311566
|
-
// Move to cache-key named file
|
|
311567
|
-
fs.renameSync(extractedWasm, cachedWasm);
|
|
311568
|
-
}
|
|
311569
|
-
}
|
|
311570
|
-
catch {
|
|
311571
|
-
// Some tar implementations don't like leading /
|
|
311572
|
-
try {
|
|
311573
|
-
(0, child_process_1.execFileSync)('tar', ['-xzf', bundleTar, '-C', cacheDir, 'policy.wasm'], {
|
|
311574
|
-
stdio: 'pipe',
|
|
311575
|
-
});
|
|
311576
|
-
const extractedWasm = path.join(cacheDir, 'policy.wasm');
|
|
311577
|
-
if (fs.existsSync(extractedWasm)) {
|
|
311578
|
-
fs.renameSync(extractedWasm, cachedWasm);
|
|
311579
|
-
}
|
|
311580
|
-
}
|
|
311581
|
-
catch (err2) {
|
|
311582
|
-
throw new Error(`Failed to extract policy.wasm from OPA bundle: ${err2?.message || err2}`);
|
|
311583
|
-
}
|
|
311584
|
-
}
|
|
311585
|
-
// Clean up tar
|
|
311586
|
-
try {
|
|
311587
|
-
fs.unlinkSync(bundleTar);
|
|
311588
|
-
}
|
|
311589
|
-
catch { }
|
|
311590
|
-
if (!fs.existsSync(cachedWasm)) {
|
|
311591
|
-
throw new Error('OPA build succeeded but policy.wasm was not found in the bundle');
|
|
311592
|
-
}
|
|
311593
|
-
return fs.readFileSync(cachedWasm);
|
|
311594
|
-
}
|
|
311595
|
-
}
|
|
311596
|
-
exports.OpaCompiler = OpaCompiler;
|
|
311597
|
-
|
|
311598
|
-
|
|
311599
|
-
/***/ }),
|
|
311600
|
-
|
|
311601
|
-
/***/ 44693:
|
|
311602
|
-
/***/ ((__unused_webpack_module, exports) => {
|
|
311603
|
-
|
|
311604
|
-
"use strict";
|
|
311605
|
-
|
|
311606
|
-
/**
|
|
311607
|
-
* Copyright (c) ProbeLabs. All rights reserved.
|
|
311608
|
-
* Licensed under the Elastic License 2.0; you may not use this file except
|
|
311609
|
-
* in compliance with the Elastic License 2.0.
|
|
311610
|
-
*/
|
|
311611
|
-
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
311612
|
-
exports.OpaHttpEvaluator = void 0;
|
|
311613
|
-
/**
|
|
311614
|
-
* OPA HTTP Evaluator - evaluates policies via an external OPA server's REST API.
|
|
311615
|
-
*
|
|
311616
|
-
* Uses the built-in `fetch` API (Node 18+), so no extra dependencies are needed.
|
|
311617
|
-
*/
|
|
311618
|
-
class OpaHttpEvaluator {
|
|
311619
|
-
baseUrl;
|
|
311620
|
-
timeout;
|
|
311621
|
-
constructor(baseUrl, timeout = 5000) {
|
|
311622
|
-
// Validate URL format and protocol
|
|
311623
|
-
let parsed;
|
|
311624
|
-
try {
|
|
311625
|
-
parsed = new URL(baseUrl);
|
|
311626
|
-
}
|
|
311627
|
-
catch {
|
|
311628
|
-
throw new Error(`OPA HTTP evaluator: invalid URL: ${baseUrl}`);
|
|
311629
|
-
}
|
|
311630
|
-
if (!['http:', 'https:'].includes(parsed.protocol)) {
|
|
311631
|
-
throw new Error(`OPA HTTP evaluator: url must use http:// or https:// protocol, got: ${baseUrl}`);
|
|
311632
|
-
}
|
|
311633
|
-
// Block cloud metadata, loopback, link-local, and private network addresses
|
|
311634
|
-
const hostname = parsed.hostname;
|
|
311635
|
-
if (this.isBlockedHostname(hostname)) {
|
|
311636
|
-
throw new Error(`OPA HTTP evaluator: url must not point to internal, loopback, or private network addresses`);
|
|
311637
|
-
}
|
|
311638
|
-
// Normalize: strip trailing slash
|
|
311639
|
-
this.baseUrl = baseUrl.replace(/\/+$/, '');
|
|
311640
|
-
this.timeout = timeout;
|
|
311641
|
-
}
|
|
311642
|
-
/**
|
|
311643
|
-
* Check if a hostname is blocked due to SSRF concerns.
|
|
311644
|
-
*
|
|
311645
|
-
* Blocks:
|
|
311646
|
-
* - Loopback addresses (127.x.x.x, localhost, 0.0.0.0, ::1)
|
|
311647
|
-
* - Link-local addresses (169.254.x.x)
|
|
311648
|
-
* - Private networks (10.x.x.x, 172.16-31.x.x, 192.168.x.x)
|
|
311649
|
-
* - IPv6 unique local addresses (fd00::/8)
|
|
311650
|
-
* - Cloud metadata services (*.internal)
|
|
311651
|
-
*/
|
|
311652
|
-
isBlockedHostname(hostname) {
|
|
311653
|
-
if (!hostname)
|
|
311654
|
-
return true; // block empty hostnames
|
|
311655
|
-
// Normalize hostname: lowercase and remove brackets for IPv6
|
|
311656
|
-
const normalized = hostname.toLowerCase().replace(/^\[|\]$/g, '');
|
|
311657
|
-
// Block .internal domains (cloud metadata services)
|
|
311658
|
-
if (normalized === 'metadata.google.internal' || normalized.endsWith('.internal')) {
|
|
311659
|
-
return true;
|
|
311660
|
-
}
|
|
311661
|
-
// Block localhost variants
|
|
311662
|
-
if (normalized === 'localhost' || normalized === 'localhost.localdomain') {
|
|
311663
|
-
return true;
|
|
311664
|
-
}
|
|
311665
|
-
// Block IPv6 loopback
|
|
311666
|
-
if (normalized === '::1' || normalized === '0:0:0:0:0:0:0:1') {
|
|
311667
|
-
return true;
|
|
311668
|
-
}
|
|
311669
|
-
// Check IPv4 patterns
|
|
311670
|
-
const ipv4Pattern = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/;
|
|
311671
|
-
const ipv4Match = normalized.match(ipv4Pattern);
|
|
311672
|
-
if (ipv4Match) {
|
|
311673
|
-
const octets = ipv4Match.slice(1, 5).map(Number);
|
|
311674
|
-
// Validate octets are in range [0, 255]
|
|
311675
|
-
if (octets.some(octet => octet > 255)) {
|
|
311676
|
-
return false;
|
|
311677
|
-
}
|
|
311678
|
-
const [a, b] = octets;
|
|
311679
|
-
// Block loopback: 127.0.0.0/8
|
|
311680
|
-
if (a === 127) {
|
|
311681
|
-
return true;
|
|
311682
|
-
}
|
|
311683
|
-
// Block 0.0.0.0/8 (this host)
|
|
311684
|
-
if (a === 0) {
|
|
311685
|
-
return true;
|
|
311686
|
-
}
|
|
311687
|
-
// Block link-local: 169.254.0.0/16
|
|
311688
|
-
if (a === 169 && b === 254) {
|
|
311689
|
-
return true;
|
|
311690
|
-
}
|
|
311691
|
-
// Block private networks
|
|
311692
|
-
// 10.0.0.0/8
|
|
311693
|
-
if (a === 10) {
|
|
311694
|
-
return true;
|
|
311695
|
-
}
|
|
311696
|
-
// 172.16.0.0/12 (172.16.x.x through 172.31.x.x)
|
|
311697
|
-
if (a === 172 && b >= 16 && b <= 31) {
|
|
311698
|
-
return true;
|
|
311699
|
-
}
|
|
311700
|
-
// 192.168.0.0/16
|
|
311701
|
-
if (a === 192 && b === 168) {
|
|
311702
|
-
return true;
|
|
311703
|
-
}
|
|
311704
|
-
}
|
|
311705
|
-
// Check IPv6 patterns
|
|
311706
|
-
// Block unique local addresses: fd00::/8
|
|
311707
|
-
if (normalized.startsWith('fd') || normalized.startsWith('fc')) {
|
|
311708
|
-
return true;
|
|
311709
|
-
}
|
|
311710
|
-
// Block link-local: fe80::/10
|
|
311711
|
-
if (normalized.startsWith('fe80:')) {
|
|
311712
|
-
return true;
|
|
311713
|
-
}
|
|
311714
|
-
return false;
|
|
311715
|
-
}
|
|
311716
|
-
/**
|
|
311717
|
-
* Evaluate a policy rule against an input document via OPA REST API.
|
|
311718
|
-
*
|
|
311719
|
-
* @param input - The input document to evaluate
|
|
311720
|
-
* @param rulePath - OPA rule path (e.g., 'visor/check/execute')
|
|
311721
|
-
* @returns The result object from OPA, or undefined on error
|
|
311722
|
-
*/
|
|
311723
|
-
async evaluate(input, rulePath) {
|
|
311724
|
-
// OPA Data API: POST /v1/data/<path>
|
|
311725
|
-
const encodedPath = rulePath
|
|
311726
|
-
.split('/')
|
|
311727
|
-
.map(s => encodeURIComponent(s))
|
|
311728
|
-
.join('/');
|
|
311729
|
-
const url = `${this.baseUrl}/v1/data/${encodedPath}`;
|
|
311730
|
-
const controller = new AbortController();
|
|
311731
|
-
const timer = setTimeout(() => controller.abort(), this.timeout);
|
|
311732
|
-
try {
|
|
311733
|
-
const response = await fetch(url, {
|
|
311734
|
-
method: 'POST',
|
|
311735
|
-
headers: { 'Content-Type': 'application/json' },
|
|
311736
|
-
body: JSON.stringify({ input }),
|
|
311737
|
-
signal: controller.signal,
|
|
311738
|
-
});
|
|
311739
|
-
if (!response.ok) {
|
|
311740
|
-
throw new Error(`OPA HTTP ${response.status}: ${response.statusText}`);
|
|
311741
|
-
}
|
|
311742
|
-
let body;
|
|
311743
|
-
try {
|
|
311744
|
-
body = await response.json();
|
|
311745
|
-
}
|
|
311746
|
-
catch (jsonErr) {
|
|
311747
|
-
throw new Error(`OPA HTTP evaluator: failed to parse JSON response: ${jsonErr instanceof Error ? jsonErr.message : String(jsonErr)}`);
|
|
311748
|
-
}
|
|
311749
|
-
// OPA returns { result: { ... } }
|
|
311750
|
-
return body?.result;
|
|
311751
|
-
}
|
|
311752
|
-
finally {
|
|
311753
|
-
clearTimeout(timer);
|
|
311754
|
-
}
|
|
311755
|
-
}
|
|
311756
|
-
async shutdown() {
|
|
311757
|
-
// No persistent connections to close
|
|
311758
|
-
}
|
|
311759
|
-
}
|
|
311760
|
-
exports.OpaHttpEvaluator = OpaHttpEvaluator;
|
|
311761
|
-
|
|
311762
|
-
|
|
311763
|
-
/***/ }),
|
|
311764
|
-
|
|
311765
|
-
/***/ 39530:
|
|
311766
|
-
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
311767
|
-
|
|
311768
|
-
"use strict";
|
|
311769
|
-
|
|
311770
|
-
/**
|
|
311771
|
-
* Copyright (c) ProbeLabs. All rights reserved.
|
|
311772
|
-
* Licensed under the Elastic License 2.0; you may not use this file except
|
|
311773
|
-
* in compliance with the Elastic License 2.0.
|
|
311774
|
-
*/
|
|
311775
|
-
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
311776
|
-
exports.OpaPolicyEngine = void 0;
|
|
311777
|
-
const opa_wasm_evaluator_1 = __nccwpck_require__(8613);
|
|
311778
|
-
const opa_http_evaluator_1 = __nccwpck_require__(44693);
|
|
311779
|
-
const policy_input_builder_1 = __nccwpck_require__(17117);
|
|
311780
|
-
/**
|
|
311781
|
-
* Enterprise OPA Policy Engine.
|
|
311782
|
-
*
|
|
311783
|
-
* Wraps both WASM (local) and HTTP (remote) OPA evaluators behind the
|
|
311784
|
-
* OSS PolicyEngine interface. All OPA input building and role resolution
|
|
311785
|
-
* is handled internally — the OSS call sites pass only plain types.
|
|
311786
|
-
*/
|
|
311787
|
-
class OpaPolicyEngine {
|
|
311788
|
-
evaluator = null;
|
|
311789
|
-
fallback;
|
|
311790
|
-
timeout;
|
|
311791
|
-
config;
|
|
311792
|
-
inputBuilder = null;
|
|
311793
|
-
logger = null;
|
|
311794
|
-
constructor(config) {
|
|
311795
|
-
this.config = config;
|
|
311796
|
-
this.fallback = config.fallback || 'deny';
|
|
311797
|
-
this.timeout = config.timeout || 5000;
|
|
311798
|
-
}
|
|
311799
|
-
async initialize(config) {
|
|
311800
|
-
// Resolve logger once at initialization
|
|
311801
|
-
try {
|
|
311802
|
-
this.logger = (__nccwpck_require__(86999).logger);
|
|
311803
|
-
}
|
|
311804
|
-
catch {
|
|
311805
|
-
// logger not available in this context
|
|
311806
|
-
}
|
|
311807
|
-
// Build actor/repo context from environment (available at engine init time)
|
|
311808
|
-
const actor = {
|
|
311809
|
-
authorAssociation: process.env.VISOR_AUTHOR_ASSOCIATION,
|
|
311810
|
-
login: process.env.VISOR_AUTHOR_LOGIN || process.env.GITHUB_ACTOR,
|
|
311811
|
-
isLocalMode: !process.env.GITHUB_ACTIONS,
|
|
311812
|
-
};
|
|
311813
|
-
const repo = {
|
|
311814
|
-
owner: process.env.GITHUB_REPOSITORY_OWNER,
|
|
311815
|
-
name: process.env.GITHUB_REPOSITORY?.split('/')[1],
|
|
311816
|
-
branch: process.env.GITHUB_HEAD_REF,
|
|
311817
|
-
baseBranch: process.env.GITHUB_BASE_REF,
|
|
311818
|
-
event: process.env.GITHUB_EVENT_NAME,
|
|
311819
|
-
};
|
|
311820
|
-
const prNum = process.env.GITHUB_PR_NUMBER
|
|
311821
|
-
? parseInt(process.env.GITHUB_PR_NUMBER, 10)
|
|
311822
|
-
: undefined;
|
|
311823
|
-
const pullRequest = {
|
|
311824
|
-
number: prNum !== undefined && Number.isFinite(prNum) ? prNum : undefined,
|
|
311825
|
-
};
|
|
311826
|
-
this.inputBuilder = new policy_input_builder_1.PolicyInputBuilder(config, actor, repo, pullRequest);
|
|
311827
|
-
if (config.engine === 'local') {
|
|
311828
|
-
if (!config.rules) {
|
|
311829
|
-
throw new Error('OPA local mode requires `policy.rules` path to .wasm or .rego files');
|
|
311830
|
-
}
|
|
311831
|
-
const wasm = new opa_wasm_evaluator_1.OpaWasmEvaluator();
|
|
311832
|
-
await wasm.initialize(config.rules);
|
|
311833
|
-
if (config.data) {
|
|
311834
|
-
wasm.loadData(config.data);
|
|
311835
|
-
}
|
|
311836
|
-
this.evaluator = wasm;
|
|
311837
|
-
}
|
|
311838
|
-
else if (config.engine === 'remote') {
|
|
311839
|
-
if (!config.url) {
|
|
311840
|
-
throw new Error('OPA remote mode requires `policy.url` pointing to OPA server');
|
|
311841
|
-
}
|
|
311842
|
-
this.evaluator = new opa_http_evaluator_1.OpaHttpEvaluator(config.url, this.timeout);
|
|
311843
|
-
}
|
|
311844
|
-
else {
|
|
311845
|
-
this.evaluator = null;
|
|
311846
|
-
}
|
|
311847
|
-
}
|
|
311848
|
-
/**
|
|
311849
|
-
* Update actor/repo/PR context (e.g., after PR info becomes available).
|
|
311850
|
-
* Called by the enterprise loader when engine context is enriched.
|
|
311851
|
-
*/
|
|
311852
|
-
setActorContext(actor, repo, pullRequest) {
|
|
311853
|
-
this.inputBuilder = new policy_input_builder_1.PolicyInputBuilder(this.config, actor, repo, pullRequest);
|
|
311854
|
-
}
|
|
311855
|
-
async evaluateCheckExecution(checkId, checkConfig) {
|
|
311856
|
-
if (!this.evaluator || !this.inputBuilder)
|
|
311857
|
-
return { allowed: true };
|
|
311858
|
-
const cfg = checkConfig && typeof checkConfig === 'object'
|
|
311859
|
-
? checkConfig
|
|
311860
|
-
: {};
|
|
311861
|
-
const policyOverride = cfg.policy;
|
|
311862
|
-
const input = this.inputBuilder.forCheckExecution({
|
|
311863
|
-
id: checkId,
|
|
311864
|
-
type: cfg.type || 'ai',
|
|
311865
|
-
group: cfg.group,
|
|
311866
|
-
tags: cfg.tags,
|
|
311867
|
-
criticality: cfg.criticality,
|
|
311868
|
-
sandbox: cfg.sandbox,
|
|
311869
|
-
policy: policyOverride,
|
|
311870
|
-
});
|
|
311871
|
-
return this.doEvaluate(input, this.resolveRulePath('check.execute', policyOverride?.rule));
|
|
311872
|
-
}
|
|
311873
|
-
async evaluateToolInvocation(serverName, methodName, transport) {
|
|
311874
|
-
if (!this.evaluator || !this.inputBuilder)
|
|
311875
|
-
return { allowed: true };
|
|
311876
|
-
const input = this.inputBuilder.forToolInvocation(serverName, methodName, transport);
|
|
311877
|
-
return this.doEvaluate(input, 'visor/tool/invoke');
|
|
311878
|
-
}
|
|
311879
|
-
async evaluateCapabilities(checkId, capabilities) {
|
|
311880
|
-
if (!this.evaluator || !this.inputBuilder)
|
|
311881
|
-
return { allowed: true };
|
|
311882
|
-
const input = this.inputBuilder.forCapabilityResolve(checkId, capabilities);
|
|
311883
|
-
return this.doEvaluate(input, 'visor/capability/resolve');
|
|
311884
|
-
}
|
|
311885
|
-
async shutdown() {
|
|
311886
|
-
if (this.evaluator && 'shutdown' in this.evaluator) {
|
|
311887
|
-
await this.evaluator.shutdown();
|
|
311888
|
-
}
|
|
311889
|
-
this.evaluator = null;
|
|
311890
|
-
this.inputBuilder = null;
|
|
311891
|
-
}
|
|
311892
|
-
resolveRulePath(defaultScope, override) {
|
|
311893
|
-
if (override) {
|
|
311894
|
-
return override.startsWith('visor/') ? override : `visor/${override}`;
|
|
311895
|
-
}
|
|
311896
|
-
return `visor/${defaultScope.replace(/\./g, '/')}`;
|
|
311897
|
-
}
|
|
311898
|
-
async doEvaluate(input, rulePath) {
|
|
311899
|
-
try {
|
|
311900
|
-
this.logger?.debug(`[PolicyEngine] Evaluating ${rulePath}`, JSON.stringify(input));
|
|
311901
|
-
let timer;
|
|
311902
|
-
const timeoutPromise = new Promise((_resolve, reject) => {
|
|
311903
|
-
timer = setTimeout(() => reject(new Error('policy evaluation timeout')), this.timeout);
|
|
311904
|
-
});
|
|
311905
|
-
try {
|
|
311906
|
-
const result = await Promise.race([this.rawEvaluate(input, rulePath), timeoutPromise]);
|
|
311907
|
-
const decision = this.parseDecision(result);
|
|
311908
|
-
// In warn mode, override denied decisions to allowed but flag as warn
|
|
311909
|
-
if (!decision.allowed && this.fallback === 'warn') {
|
|
311910
|
-
decision.allowed = true;
|
|
311911
|
-
decision.warn = true;
|
|
311912
|
-
decision.reason = `audit: ${decision.reason || 'policy denied'}`;
|
|
311913
|
-
}
|
|
311914
|
-
this.logger?.debug(`[PolicyEngine] Decision for ${rulePath}: allowed=${decision.allowed}, warn=${decision.warn || false}, reason=${decision.reason || 'none'}`);
|
|
311915
|
-
return decision;
|
|
311916
|
-
}
|
|
311917
|
-
finally {
|
|
311918
|
-
if (timer)
|
|
311919
|
-
clearTimeout(timer);
|
|
311920
|
-
}
|
|
311921
|
-
}
|
|
311922
|
-
catch (err) {
|
|
311923
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
311924
|
-
this.logger?.warn(`[PolicyEngine] Evaluation failed for ${rulePath}: ${msg}`);
|
|
311925
|
-
return {
|
|
311926
|
-
allowed: this.fallback === 'allow' || this.fallback === 'warn',
|
|
311927
|
-
warn: this.fallback === 'warn' ? true : undefined,
|
|
311928
|
-
reason: `policy evaluation failed, fallback=${this.fallback}`,
|
|
311929
|
-
};
|
|
311930
|
-
}
|
|
311931
|
-
}
|
|
311932
|
-
async rawEvaluate(input, rulePath) {
|
|
311933
|
-
if (this.evaluator instanceof opa_wasm_evaluator_1.OpaWasmEvaluator) {
|
|
311934
|
-
const result = await this.evaluator.evaluate(input);
|
|
311935
|
-
// WASM compiled with `-e visor` entrypoint returns the full visor package tree.
|
|
311936
|
-
// Navigate to the specific rule subtree using rulePath segments.
|
|
311937
|
-
// e.g., 'visor/check/execute' → result.check.execute
|
|
311938
|
-
return this.navigateWasmResult(result, rulePath);
|
|
311939
|
-
}
|
|
311940
|
-
return this.evaluator.evaluate(input, rulePath);
|
|
311941
|
-
}
|
|
311942
|
-
/**
|
|
311943
|
-
* Navigate nested OPA WASM result tree to reach the specific rule's output.
|
|
311944
|
-
* The WASM entrypoint `-e visor` means the result root IS the visor package,
|
|
311945
|
-
* so we strip the `visor/` prefix and walk the remaining segments.
|
|
311946
|
-
*/
|
|
311947
|
-
navigateWasmResult(result, rulePath) {
|
|
311948
|
-
if (!result || typeof result !== 'object')
|
|
311949
|
-
return result;
|
|
311950
|
-
// Strip the 'visor/' prefix (matches our compilation entrypoint)
|
|
311951
|
-
const segments = rulePath.replace(/^visor\//, '').split('/');
|
|
311952
|
-
let current = result;
|
|
311953
|
-
for (const seg of segments) {
|
|
311954
|
-
if (current && typeof current === 'object' && seg in current) {
|
|
311955
|
-
current = current[seg];
|
|
311956
|
-
}
|
|
311957
|
-
else {
|
|
311958
|
-
return undefined; // path not found in result tree
|
|
311959
|
-
}
|
|
311960
|
-
}
|
|
311961
|
-
return current;
|
|
311962
|
-
}
|
|
311963
|
-
parseDecision(result) {
|
|
311964
|
-
if (result === undefined || result === null) {
|
|
311965
|
-
return {
|
|
311966
|
-
allowed: this.fallback === 'allow' || this.fallback === 'warn',
|
|
311967
|
-
warn: this.fallback === 'warn' ? true : undefined,
|
|
311968
|
-
reason: this.fallback === 'warn' ? 'audit: no policy result' : 'no policy result',
|
|
311969
|
-
};
|
|
311970
|
-
}
|
|
311971
|
-
const allowed = result.allowed !== false;
|
|
311972
|
-
const decision = {
|
|
311973
|
-
allowed,
|
|
311974
|
-
reason: result.reason,
|
|
311975
|
-
};
|
|
311976
|
-
if (result.capabilities) {
|
|
311977
|
-
decision.capabilities = result.capabilities;
|
|
311978
|
-
}
|
|
311979
|
-
return decision;
|
|
311980
|
-
}
|
|
311981
|
-
}
|
|
311982
|
-
exports.OpaPolicyEngine = OpaPolicyEngine;
|
|
311983
|
-
|
|
311984
|
-
|
|
311985
|
-
/***/ }),
|
|
311986
|
-
|
|
311987
|
-
/***/ 8613:
|
|
311988
|
-
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
|
|
311989
|
-
|
|
311990
|
-
"use strict";
|
|
311991
|
-
|
|
311992
|
-
/**
|
|
311993
|
-
* Copyright (c) ProbeLabs. All rights reserved.
|
|
311994
|
-
* Licensed under the Elastic License 2.0; you may not use this file except
|
|
311995
|
-
* in compliance with the Elastic License 2.0.
|
|
311996
|
-
*/
|
|
311997
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
311998
|
-
if (k2 === undefined) k2 = k;
|
|
311999
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
312000
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
312001
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
312002
|
-
}
|
|
312003
|
-
Object.defineProperty(o, k2, desc);
|
|
312004
|
-
}) : (function(o, m, k, k2) {
|
|
312005
|
-
if (k2 === undefined) k2 = k;
|
|
312006
|
-
o[k2] = m[k];
|
|
312007
|
-
}));
|
|
312008
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
312009
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
312010
|
-
}) : function(o, v) {
|
|
312011
|
-
o["default"] = v;
|
|
312012
|
-
});
|
|
312013
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
312014
|
-
var ownKeys = function(o) {
|
|
312015
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
312016
|
-
var ar = [];
|
|
312017
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
312018
|
-
return ar;
|
|
312019
|
-
};
|
|
312020
|
-
return ownKeys(o);
|
|
312021
|
-
};
|
|
312022
|
-
return function (mod) {
|
|
312023
|
-
if (mod && mod.__esModule) return mod;
|
|
312024
|
-
var result = {};
|
|
312025
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
312026
|
-
__setModuleDefault(result, mod);
|
|
312027
|
-
return result;
|
|
312028
|
-
};
|
|
312029
|
-
})();
|
|
312030
|
-
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
312031
|
-
exports.OpaWasmEvaluator = void 0;
|
|
312032
|
-
const fs = __importStar(__nccwpck_require__(79896));
|
|
312033
|
-
const path = __importStar(__nccwpck_require__(16928));
|
|
312034
|
-
const opa_compiler_1 = __nccwpck_require__(628);
|
|
312035
|
-
/**
|
|
312036
|
-
* OPA WASM Evaluator - loads and evaluates OPA policies locally.
|
|
312037
|
-
*
|
|
312038
|
-
* Supports three input formats:
|
|
312039
|
-
* 1. Pre-compiled `.wasm` bundle — loaded directly (fastest startup)
|
|
312040
|
-
* 2. `.rego` files or directory — auto-compiled to WASM via `opa build` CLI
|
|
312041
|
-
* 3. Directory with `policy.wasm` inside — loaded directly
|
|
312042
|
-
*
|
|
312043
|
-
* Compilation and caching of .rego files is delegated to {@link OpaCompiler}.
|
|
312044
|
-
*
|
|
312045
|
-
* Requires:
|
|
312046
|
-
* - `@open-policy-agent/opa-wasm` npm package (optional dep)
|
|
312047
|
-
* - `opa` CLI on PATH (only when auto-compiling .rego files)
|
|
312048
|
-
*/
|
|
312049
|
-
class OpaWasmEvaluator {
|
|
312050
|
-
policy = null;
|
|
312051
|
-
dataDocument = {};
|
|
312052
|
-
compiler = new opa_compiler_1.OpaCompiler();
|
|
312053
|
-
async initialize(rulesPath) {
|
|
312054
|
-
const paths = Array.isArray(rulesPath) ? rulesPath : [rulesPath];
|
|
312055
|
-
const wasmBytes = await this.compiler.resolveWasmBytes(paths);
|
|
312056
|
-
try {
|
|
312057
|
-
// Use createRequire to load the optional dep at runtime without ncc bundling it.
|
|
312058
|
-
// `new Function('id', 'return require(id)')` fails in ncc bundles because
|
|
312059
|
-
// `require` is not in the `new Function` scope. `createRequire` works correctly
|
|
312060
|
-
// because it creates a real Node.js require rooted at the given path.
|
|
312061
|
-
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
312062
|
-
const { createRequire } = __nccwpck_require__(73339);
|
|
312063
|
-
const runtimeRequire = createRequire(__filename);
|
|
312064
|
-
const opaWasm = runtimeRequire('@open-policy-agent/opa-wasm');
|
|
312065
|
-
const loadPolicy = opaWasm.loadPolicy || opaWasm.default?.loadPolicy;
|
|
312066
|
-
if (!loadPolicy) {
|
|
312067
|
-
throw new Error('loadPolicy not found in @open-policy-agent/opa-wasm');
|
|
312068
|
-
}
|
|
312069
|
-
this.policy = await loadPolicy(wasmBytes);
|
|
312070
|
-
}
|
|
312071
|
-
catch (err) {
|
|
312072
|
-
if (err?.code === 'MODULE_NOT_FOUND' || err?.code === 'ERR_MODULE_NOT_FOUND') {
|
|
312073
|
-
throw new Error('OPA WASM evaluator requires @open-policy-agent/opa-wasm. ' +
|
|
312074
|
-
'Install it with: npm install @open-policy-agent/opa-wasm');
|
|
312075
|
-
}
|
|
312076
|
-
throw err;
|
|
312077
|
-
}
|
|
312078
|
-
}
|
|
312079
|
-
/**
|
|
312080
|
-
* Load external data from a JSON file to use as the OPA data document.
|
|
312081
|
-
* The loaded data will be passed to `policy.setData()` during evaluation,
|
|
312082
|
-
* making it available in Rego via `data.<key>`.
|
|
312083
|
-
*/
|
|
312084
|
-
loadData(dataPath) {
|
|
312085
|
-
const resolved = path.resolve(dataPath);
|
|
312086
|
-
if (path.normalize(resolved).includes('..')) {
|
|
312087
|
-
throw new Error(`Data path contains traversal sequences: ${dataPath}`);
|
|
312088
|
-
}
|
|
312089
|
-
if (!fs.existsSync(resolved)) {
|
|
312090
|
-
throw new Error(`OPA data file not found: ${resolved}`);
|
|
312091
|
-
}
|
|
312092
|
-
const stat = fs.statSync(resolved);
|
|
312093
|
-
if (stat.size > 10 * 1024 * 1024) {
|
|
312094
|
-
throw new Error(`OPA data file exceeds 10MB limit: ${resolved} (${stat.size} bytes)`);
|
|
312095
|
-
}
|
|
312096
|
-
const raw = fs.readFileSync(resolved, 'utf-8');
|
|
312097
|
-
try {
|
|
312098
|
-
const parsed = JSON.parse(raw);
|
|
312099
|
-
if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
|
|
312100
|
-
throw new Error('OPA data file must contain a JSON object (not an array or primitive)');
|
|
312101
|
-
}
|
|
312102
|
-
this.dataDocument = parsed;
|
|
312103
|
-
}
|
|
312104
|
-
catch (err) {
|
|
312105
|
-
if (err.message.startsWith('OPA data file must')) {
|
|
312106
|
-
throw err;
|
|
312107
|
-
}
|
|
312108
|
-
throw new Error(`Failed to parse OPA data file ${resolved}: ${err.message}`);
|
|
312109
|
-
}
|
|
312110
|
-
}
|
|
312111
|
-
async evaluate(input) {
|
|
312112
|
-
if (!this.policy) {
|
|
312113
|
-
throw new Error('OPA WASM evaluator not initialized');
|
|
312114
|
-
}
|
|
312115
|
-
this.policy.setData(this.dataDocument);
|
|
312116
|
-
const resultSet = this.policy.evaluate(input);
|
|
312117
|
-
if (Array.isArray(resultSet) && resultSet.length > 0) {
|
|
312118
|
-
return resultSet[0].result;
|
|
312119
|
-
}
|
|
312120
|
-
return undefined;
|
|
312121
|
-
}
|
|
312122
|
-
async shutdown() {
|
|
312123
|
-
if (this.policy) {
|
|
312124
|
-
// opa-wasm policy objects may have a close/free method for WASM cleanup
|
|
312125
|
-
if (typeof this.policy.close === 'function') {
|
|
312126
|
-
try {
|
|
312127
|
-
this.policy.close();
|
|
312128
|
-
}
|
|
312129
|
-
catch { }
|
|
312130
|
-
}
|
|
312131
|
-
else if (typeof this.policy.free === 'function') {
|
|
312132
|
-
try {
|
|
312133
|
-
this.policy.free();
|
|
312134
|
-
}
|
|
312135
|
-
catch { }
|
|
312136
|
-
}
|
|
312137
|
-
}
|
|
312138
|
-
this.policy = null;
|
|
312139
|
-
}
|
|
312140
|
-
}
|
|
312141
|
-
exports.OpaWasmEvaluator = OpaWasmEvaluator;
|
|
312142
|
-
|
|
312143
|
-
|
|
312144
|
-
/***/ }),
|
|
312145
|
-
|
|
312146
|
-
/***/ 17117:
|
|
312147
|
-
/***/ ((__unused_webpack_module, exports) => {
|
|
312148
|
-
|
|
312149
|
-
"use strict";
|
|
312150
|
-
|
|
312151
|
-
/**
|
|
312152
|
-
* Copyright (c) ProbeLabs. All rights reserved.
|
|
312153
|
-
* Licensed under the Elastic License 2.0; you may not use this file except
|
|
312154
|
-
* in compliance with the Elastic License 2.0.
|
|
312155
|
-
*/
|
|
312156
|
-
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
312157
|
-
exports.PolicyInputBuilder = void 0;
|
|
312158
|
-
/**
|
|
312159
|
-
* Builds OPA-compatible input documents from engine context.
|
|
312160
|
-
*
|
|
312161
|
-
* Resolves actor roles from the `policy.roles` config section by matching
|
|
312162
|
-
* the actor's authorAssociation and login against role definitions.
|
|
312163
|
-
*/
|
|
312164
|
-
class PolicyInputBuilder {
|
|
312165
|
-
roles;
|
|
312166
|
-
actor;
|
|
312167
|
-
repository;
|
|
312168
|
-
pullRequest;
|
|
312169
|
-
constructor(policyConfig, actor, repository, pullRequest) {
|
|
312170
|
-
this.roles = policyConfig.roles || {};
|
|
312171
|
-
this.actor = actor;
|
|
312172
|
-
this.repository = repository;
|
|
312173
|
-
this.pullRequest = pullRequest;
|
|
312174
|
-
}
|
|
312175
|
-
/** Resolve which roles apply to the current actor. */
|
|
312176
|
-
resolveRoles() {
|
|
312177
|
-
const matched = [];
|
|
312178
|
-
for (const [roleName, roleConfig] of Object.entries(this.roles)) {
|
|
312179
|
-
let identityMatch = false;
|
|
312180
|
-
if (roleConfig.author_association &&
|
|
312181
|
-
this.actor.authorAssociation &&
|
|
312182
|
-
roleConfig.author_association.includes(this.actor.authorAssociation)) {
|
|
312183
|
-
identityMatch = true;
|
|
312184
|
-
}
|
|
312185
|
-
if (!identityMatch &&
|
|
312186
|
-
roleConfig.users &&
|
|
312187
|
-
this.actor.login &&
|
|
312188
|
-
roleConfig.users.includes(this.actor.login)) {
|
|
312189
|
-
identityMatch = true;
|
|
312190
|
-
}
|
|
312191
|
-
// Slack user ID match
|
|
312192
|
-
if (!identityMatch &&
|
|
312193
|
-
roleConfig.slack_users &&
|
|
312194
|
-
this.actor.slack?.userId &&
|
|
312195
|
-
roleConfig.slack_users.includes(this.actor.slack.userId)) {
|
|
312196
|
-
identityMatch = true;
|
|
312197
|
-
}
|
|
312198
|
-
// Email match (case-insensitive)
|
|
312199
|
-
if (!identityMatch && roleConfig.emails && this.actor.slack?.email) {
|
|
312200
|
-
const actorEmail = this.actor.slack.email.toLowerCase();
|
|
312201
|
-
if (roleConfig.emails.some(e => e.toLowerCase() === actorEmail)) {
|
|
312202
|
-
identityMatch = true;
|
|
312203
|
-
}
|
|
312204
|
-
}
|
|
312205
|
-
// Note: teams-based role resolution requires GitHub API access (read:org scope)
|
|
312206
|
-
// and is not yet implemented. If configured, the role will not match via teams.
|
|
312207
|
-
if (!identityMatch)
|
|
312208
|
-
continue;
|
|
312209
|
-
// slack_channels gate: if set, the role only applies when triggered from one of these channels
|
|
312210
|
-
if (roleConfig.slack_channels && roleConfig.slack_channels.length > 0) {
|
|
312211
|
-
if (!this.actor.slack?.channelId ||
|
|
312212
|
-
!roleConfig.slack_channels.includes(this.actor.slack.channelId)) {
|
|
312213
|
-
continue;
|
|
312214
|
-
}
|
|
312215
|
-
}
|
|
312216
|
-
matched.push(roleName);
|
|
312217
|
-
}
|
|
312218
|
-
return matched;
|
|
312219
|
-
}
|
|
312220
|
-
buildActor() {
|
|
312221
|
-
return {
|
|
312222
|
-
authorAssociation: this.actor.authorAssociation,
|
|
312223
|
-
login: this.actor.login,
|
|
312224
|
-
roles: this.resolveRoles(),
|
|
312225
|
-
isLocalMode: this.actor.isLocalMode,
|
|
312226
|
-
...(this.actor.slack && { slack: this.actor.slack }),
|
|
312227
|
-
};
|
|
312228
|
-
}
|
|
312229
|
-
forCheckExecution(check) {
|
|
312230
|
-
return {
|
|
312231
|
-
scope: 'check.execute',
|
|
312232
|
-
check: {
|
|
312233
|
-
id: check.id,
|
|
312234
|
-
type: check.type,
|
|
312235
|
-
group: check.group,
|
|
312236
|
-
tags: check.tags,
|
|
312237
|
-
criticality: check.criticality,
|
|
312238
|
-
sandbox: check.sandbox,
|
|
312239
|
-
policy: check.policy,
|
|
312240
|
-
},
|
|
312241
|
-
actor: this.buildActor(),
|
|
312242
|
-
repository: this.repository,
|
|
312243
|
-
pullRequest: this.pullRequest,
|
|
312244
|
-
};
|
|
312245
|
-
}
|
|
312246
|
-
forToolInvocation(serverName, methodName, transport) {
|
|
312247
|
-
return {
|
|
312248
|
-
scope: 'tool.invoke',
|
|
312249
|
-
tool: { serverName, methodName, transport },
|
|
312250
|
-
actor: this.buildActor(),
|
|
312251
|
-
repository: this.repository,
|
|
312252
|
-
pullRequest: this.pullRequest,
|
|
312253
|
-
};
|
|
312254
|
-
}
|
|
312255
|
-
forCapabilityResolve(checkId, capabilities) {
|
|
312256
|
-
return {
|
|
312257
|
-
scope: 'capability.resolve',
|
|
312258
|
-
check: { id: checkId, type: 'ai' },
|
|
312259
|
-
capability: capabilities,
|
|
312260
|
-
actor: this.buildActor(),
|
|
312261
|
-
repository: this.repository,
|
|
312262
|
-
pullRequest: this.pullRequest,
|
|
312263
|
-
};
|
|
312264
|
-
}
|
|
312265
|
-
}
|
|
312266
|
-
exports.PolicyInputBuilder = PolicyInputBuilder;
|
|
312267
|
-
|
|
312268
|
-
|
|
312269
|
-
/***/ }),
|
|
312270
|
-
|
|
312271
|
-
/***/ 63737:
|
|
312272
|
-
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
|
|
312273
|
-
|
|
312274
|
-
"use strict";
|
|
312275
|
-
|
|
312276
|
-
/**
|
|
312277
|
-
* Copyright (c) ProbeLabs. All rights reserved.
|
|
312278
|
-
* Licensed under the Elastic License 2.0; you may not use this file except
|
|
312279
|
-
* in compliance with the Elastic License 2.0.
|
|
312280
|
-
*/
|
|
312281
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
312282
|
-
if (k2 === undefined) k2 = k;
|
|
312283
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
312284
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
312285
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
312286
|
-
}
|
|
312287
|
-
Object.defineProperty(o, k2, desc);
|
|
312288
|
-
}) : (function(o, m, k, k2) {
|
|
312289
|
-
if (k2 === undefined) k2 = k;
|
|
312290
|
-
o[k2] = m[k];
|
|
312291
|
-
}));
|
|
312292
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
312293
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
312294
|
-
}) : function(o, v) {
|
|
312295
|
-
o["default"] = v;
|
|
312296
|
-
});
|
|
312297
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
312298
|
-
var ownKeys = function(o) {
|
|
312299
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
312300
|
-
var ar = [];
|
|
312301
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
312302
|
-
return ar;
|
|
312303
|
-
};
|
|
312304
|
-
return ownKeys(o);
|
|
312305
|
-
};
|
|
312306
|
-
return function (mod) {
|
|
312307
|
-
if (mod && mod.__esModule) return mod;
|
|
312308
|
-
var result = {};
|
|
312309
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
312310
|
-
__setModuleDefault(result, mod);
|
|
312311
|
-
return result;
|
|
312312
|
-
};
|
|
312313
|
-
})();
|
|
312314
|
-
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
312315
|
-
exports.KnexStoreBackend = void 0;
|
|
312316
|
-
/**
|
|
312317
|
-
* Knex-backed schedule store for PostgreSQL, MySQL, and MSSQL (Enterprise)
|
|
312318
|
-
*
|
|
312319
|
-
* Uses Knex query builder for database-agnostic SQL. Same schema as SQLite backend
|
|
312320
|
-
* but with real distributed locking via row-level claims (claimed_by/claimed_at/lock_token).
|
|
312321
|
-
*/
|
|
312322
|
-
const fs = __importStar(__nccwpck_require__(79896));
|
|
312323
|
-
const path = __importStar(__nccwpck_require__(16928));
|
|
312324
|
-
const uuid_1 = __nccwpck_require__(31914);
|
|
312325
|
-
const logger_1 = __nccwpck_require__(86999);
|
|
312326
|
-
function toNum(val) {
|
|
312327
|
-
if (val === null || val === undefined)
|
|
312328
|
-
return undefined;
|
|
312329
|
-
return typeof val === 'string' ? parseInt(val, 10) : val;
|
|
312330
|
-
}
|
|
312331
|
-
function safeJsonParse(value) {
|
|
312332
|
-
if (!value)
|
|
312333
|
-
return undefined;
|
|
312334
|
-
try {
|
|
312335
|
-
return JSON.parse(value);
|
|
312336
|
-
}
|
|
312337
|
-
catch {
|
|
312338
|
-
return undefined;
|
|
312339
|
-
}
|
|
312340
|
-
}
|
|
312341
|
-
function fromTriggerRow(row) {
|
|
312342
|
-
return {
|
|
312343
|
-
id: row.id,
|
|
312344
|
-
creatorId: row.creator_id,
|
|
312345
|
-
creatorContext: row.creator_context ?? undefined,
|
|
312346
|
-
creatorName: row.creator_name ?? undefined,
|
|
312347
|
-
description: row.description ?? undefined,
|
|
312348
|
-
channels: safeJsonParse(row.channels),
|
|
312349
|
-
fromUsers: safeJsonParse(row.from_users),
|
|
312350
|
-
fromBots: row.from_bots === true || row.from_bots === 1,
|
|
312351
|
-
contains: safeJsonParse(row.contains),
|
|
312352
|
-
matchPattern: row.match_pattern ?? undefined,
|
|
312353
|
-
threads: row.threads,
|
|
312354
|
-
workflow: row.workflow,
|
|
312355
|
-
inputs: safeJsonParse(row.inputs),
|
|
312356
|
-
outputContext: safeJsonParse(row.output_context),
|
|
312357
|
-
status: row.status,
|
|
312358
|
-
enabled: row.enabled === true || row.enabled === 1,
|
|
312359
|
-
createdAt: toNum(row.created_at),
|
|
312360
|
-
};
|
|
312361
|
-
}
|
|
312362
|
-
function toTriggerInsertRow(trigger) {
|
|
312363
|
-
return {
|
|
312364
|
-
id: trigger.id,
|
|
312365
|
-
creator_id: trigger.creatorId,
|
|
312366
|
-
creator_context: trigger.creatorContext ?? null,
|
|
312367
|
-
creator_name: trigger.creatorName ?? null,
|
|
312368
|
-
description: trigger.description ?? null,
|
|
312369
|
-
channels: trigger.channels ? JSON.stringify(trigger.channels) : null,
|
|
312370
|
-
from_users: trigger.fromUsers ? JSON.stringify(trigger.fromUsers) : null,
|
|
312371
|
-
from_bots: trigger.fromBots,
|
|
312372
|
-
contains: trigger.contains ? JSON.stringify(trigger.contains) : null,
|
|
312373
|
-
match_pattern: trigger.matchPattern ?? null,
|
|
312374
|
-
threads: trigger.threads,
|
|
312375
|
-
workflow: trigger.workflow,
|
|
312376
|
-
inputs: trigger.inputs ? JSON.stringify(trigger.inputs) : null,
|
|
312377
|
-
output_context: trigger.outputContext ? JSON.stringify(trigger.outputContext) : null,
|
|
312378
|
-
status: trigger.status,
|
|
312379
|
-
enabled: trigger.enabled,
|
|
312380
|
-
created_at: trigger.createdAt,
|
|
312381
|
-
};
|
|
312382
|
-
}
|
|
312383
|
-
function fromDbRow(row) {
|
|
312384
|
-
return {
|
|
312385
|
-
id: row.id,
|
|
312386
|
-
creatorId: row.creator_id,
|
|
312387
|
-
creatorContext: row.creator_context ?? undefined,
|
|
312388
|
-
creatorName: row.creator_name ?? undefined,
|
|
312389
|
-
timezone: row.timezone,
|
|
312390
|
-
schedule: row.schedule_expr,
|
|
312391
|
-
runAt: toNum(row.run_at),
|
|
312392
|
-
isRecurring: row.is_recurring === true || row.is_recurring === 1,
|
|
312393
|
-
originalExpression: row.original_expression,
|
|
312394
|
-
workflow: row.workflow ?? undefined,
|
|
312395
|
-
workflowInputs: safeJsonParse(row.workflow_inputs),
|
|
312396
|
-
outputContext: safeJsonParse(row.output_context),
|
|
312397
|
-
status: row.status,
|
|
312398
|
-
createdAt: toNum(row.created_at),
|
|
312399
|
-
lastRunAt: toNum(row.last_run_at),
|
|
312400
|
-
nextRunAt: toNum(row.next_run_at),
|
|
312401
|
-
runCount: row.run_count,
|
|
312402
|
-
failureCount: row.failure_count,
|
|
312403
|
-
lastError: row.last_error ?? undefined,
|
|
312404
|
-
previousResponse: row.previous_response ?? undefined,
|
|
312405
|
-
};
|
|
312406
|
-
}
|
|
312407
|
-
function toInsertRow(schedule) {
|
|
312408
|
-
return {
|
|
312409
|
-
id: schedule.id,
|
|
312410
|
-
creator_id: schedule.creatorId,
|
|
312411
|
-
creator_context: schedule.creatorContext ?? null,
|
|
312412
|
-
creator_name: schedule.creatorName ?? null,
|
|
312413
|
-
timezone: schedule.timezone,
|
|
312414
|
-
schedule_expr: schedule.schedule,
|
|
312415
|
-
run_at: schedule.runAt ?? null,
|
|
312416
|
-
is_recurring: schedule.isRecurring,
|
|
312417
|
-
original_expression: schedule.originalExpression,
|
|
312418
|
-
workflow: schedule.workflow ?? null,
|
|
312419
|
-
workflow_inputs: schedule.workflowInputs ? JSON.stringify(schedule.workflowInputs) : null,
|
|
312420
|
-
output_context: schedule.outputContext ? JSON.stringify(schedule.outputContext) : null,
|
|
312421
|
-
status: schedule.status,
|
|
312422
|
-
created_at: schedule.createdAt,
|
|
312423
|
-
last_run_at: schedule.lastRunAt ?? null,
|
|
312424
|
-
next_run_at: schedule.nextRunAt ?? null,
|
|
312425
|
-
run_count: schedule.runCount,
|
|
312426
|
-
failure_count: schedule.failureCount,
|
|
312427
|
-
last_error: schedule.lastError ?? null,
|
|
312428
|
-
previous_response: schedule.previousResponse ?? null,
|
|
312429
|
-
};
|
|
312430
|
-
}
|
|
312431
|
-
/**
|
|
312432
|
-
* Enterprise Knex-backed store for PostgreSQL, MySQL, and MSSQL
|
|
312433
|
-
*/
|
|
312434
|
-
class KnexStoreBackend {
|
|
312435
|
-
knex = null;
|
|
312436
|
-
driver;
|
|
312437
|
-
connection;
|
|
312438
|
-
constructor(driver, storageConfig, _haConfig) {
|
|
312439
|
-
this.driver = driver;
|
|
312440
|
-
this.connection = (storageConfig.connection || {});
|
|
312441
|
-
}
|
|
312442
|
-
async initialize() {
|
|
312443
|
-
// Load knex dynamically
|
|
312444
|
-
const { createRequire } = __nccwpck_require__(73339);
|
|
312445
|
-
const runtimeRequire = createRequire(__filename);
|
|
312446
|
-
let knexFactory;
|
|
312447
|
-
try {
|
|
312448
|
-
knexFactory = runtimeRequire('knex');
|
|
312449
|
-
}
|
|
312450
|
-
catch (err) {
|
|
312451
|
-
const code = err?.code;
|
|
312452
|
-
if (code === 'MODULE_NOT_FOUND' || code === 'ERR_MODULE_NOT_FOUND') {
|
|
312453
|
-
throw new Error('knex is required for PostgreSQL/MySQL/MSSQL schedule storage. ' +
|
|
312454
|
-
'Install it with: npm install knex');
|
|
312455
|
-
}
|
|
312456
|
-
throw err;
|
|
312457
|
-
}
|
|
312458
|
-
const clientMap = {
|
|
312459
|
-
postgresql: 'pg',
|
|
312460
|
-
mysql: 'mysql2',
|
|
312461
|
-
mssql: 'tedious',
|
|
312462
|
-
};
|
|
312463
|
-
const client = clientMap[this.driver];
|
|
312464
|
-
// Build connection config
|
|
312465
|
-
let connection;
|
|
312466
|
-
if (this.connection.connection_string) {
|
|
312467
|
-
connection = this.connection.connection_string;
|
|
312468
|
-
}
|
|
312469
|
-
else if (this.driver === 'mssql') {
|
|
312470
|
-
connection = this.buildMssqlConnection();
|
|
312471
|
-
}
|
|
312472
|
-
else {
|
|
312473
|
-
connection = this.buildStandardConnection();
|
|
312474
|
-
}
|
|
312475
|
-
this.knex = knexFactory({
|
|
312476
|
-
client,
|
|
312477
|
-
connection,
|
|
312478
|
-
pool: {
|
|
312479
|
-
min: this.connection.pool?.min ?? 0,
|
|
312480
|
-
max: this.connection.pool?.max ?? 10,
|
|
312481
|
-
},
|
|
312482
|
-
});
|
|
312483
|
-
// Run schema migration
|
|
312484
|
-
await this.migrateSchema();
|
|
312485
|
-
logger_1.logger.info(`[KnexStore] Initialized (${this.driver})`);
|
|
312486
|
-
}
|
|
312487
|
-
buildStandardConnection() {
|
|
312488
|
-
return {
|
|
312489
|
-
host: this.connection.host || 'localhost',
|
|
312490
|
-
port: this.connection.port,
|
|
312491
|
-
database: this.connection.database || 'visor',
|
|
312492
|
-
user: this.connection.user,
|
|
312493
|
-
password: this.connection.password,
|
|
312494
|
-
ssl: this.resolveSslConfig(),
|
|
312495
|
-
};
|
|
312496
|
-
}
|
|
312497
|
-
buildMssqlConnection() {
|
|
312498
|
-
const ssl = this.connection.ssl;
|
|
312499
|
-
const sslEnabled = ssl === true || (typeof ssl === 'object' && ssl.enabled !== false);
|
|
312500
|
-
return {
|
|
312501
|
-
server: this.connection.host || 'localhost',
|
|
312502
|
-
port: this.connection.port,
|
|
312503
|
-
database: this.connection.database || 'visor',
|
|
312504
|
-
user: this.connection.user,
|
|
312505
|
-
password: this.connection.password,
|
|
312506
|
-
options: {
|
|
312507
|
-
encrypt: sslEnabled,
|
|
312508
|
-
trustServerCertificate: typeof ssl === 'object' ? ssl.reject_unauthorized === false : !sslEnabled,
|
|
312509
|
-
},
|
|
312510
|
-
};
|
|
312511
|
-
}
|
|
312512
|
-
resolveSslConfig() {
|
|
312513
|
-
const ssl = this.connection.ssl;
|
|
312514
|
-
if (ssl === false || ssl === undefined)
|
|
312515
|
-
return false;
|
|
312516
|
-
if (ssl === true)
|
|
312517
|
-
return { rejectUnauthorized: true };
|
|
312518
|
-
// Object config
|
|
312519
|
-
if (ssl.enabled === false)
|
|
312520
|
-
return false;
|
|
312521
|
-
const result = {
|
|
312522
|
-
rejectUnauthorized: ssl.reject_unauthorized !== false,
|
|
312523
|
-
};
|
|
312524
|
-
if (ssl.ca) {
|
|
312525
|
-
const caPath = this.validateSslPath(ssl.ca, 'CA certificate');
|
|
312526
|
-
result.ca = fs.readFileSync(caPath, 'utf8');
|
|
312527
|
-
}
|
|
312528
|
-
if (ssl.cert) {
|
|
312529
|
-
const certPath = this.validateSslPath(ssl.cert, 'client certificate');
|
|
312530
|
-
result.cert = fs.readFileSync(certPath, 'utf8');
|
|
312531
|
-
}
|
|
312532
|
-
if (ssl.key) {
|
|
312533
|
-
const keyPath = this.validateSslPath(ssl.key, 'client key');
|
|
312534
|
-
result.key = fs.readFileSync(keyPath, 'utf8');
|
|
312535
|
-
}
|
|
312536
|
-
return result;
|
|
312537
|
-
}
|
|
312538
|
-
validateSslPath(filePath, label) {
|
|
312539
|
-
const resolved = path.resolve(filePath);
|
|
312540
|
-
if (resolved !== path.normalize(resolved)) {
|
|
312541
|
-
throw new Error(`SSL ${label} path contains invalid sequences: ${filePath}`);
|
|
312542
|
-
}
|
|
312543
|
-
if (!fs.existsSync(resolved)) {
|
|
312544
|
-
throw new Error(`SSL ${label} not found: ${filePath}`);
|
|
312545
|
-
}
|
|
312546
|
-
return resolved;
|
|
312547
|
-
}
|
|
312548
|
-
async shutdown() {
|
|
312549
|
-
if (this.knex) {
|
|
312550
|
-
await this.knex.destroy();
|
|
312551
|
-
this.knex = null;
|
|
312552
|
-
}
|
|
312553
|
-
}
|
|
312554
|
-
async migrateSchema() {
|
|
312555
|
-
const knex = this.getKnex();
|
|
312556
|
-
const exists = await knex.schema.hasTable('schedules');
|
|
312557
|
-
if (!exists) {
|
|
312558
|
-
await knex.schema.createTable('schedules', table => {
|
|
312559
|
-
table.string('id', 36).primary();
|
|
312560
|
-
table.string('creator_id', 255).notNullable().index();
|
|
312561
|
-
table.string('creator_context', 255);
|
|
312562
|
-
table.string('creator_name', 255);
|
|
312563
|
-
table.string('timezone', 64).notNullable().defaultTo('UTC');
|
|
312564
|
-
table.string('schedule_expr', 255);
|
|
312565
|
-
table.bigInteger('run_at');
|
|
312566
|
-
table.boolean('is_recurring').notNullable();
|
|
312567
|
-
table.text('original_expression');
|
|
312568
|
-
table.string('workflow', 255);
|
|
312569
|
-
table.text('workflow_inputs');
|
|
312570
|
-
table.text('output_context');
|
|
312571
|
-
table.string('status', 20).notNullable().index();
|
|
312572
|
-
table.bigInteger('created_at').notNullable();
|
|
312573
|
-
table.bigInteger('last_run_at');
|
|
312574
|
-
table.bigInteger('next_run_at');
|
|
312575
|
-
table.integer('run_count').notNullable().defaultTo(0);
|
|
312576
|
-
table.integer('failure_count').notNullable().defaultTo(0);
|
|
312577
|
-
table.text('last_error');
|
|
312578
|
-
table.text('previous_response');
|
|
312579
|
-
table.index(['status', 'next_run_at']);
|
|
312580
|
-
});
|
|
312581
|
-
}
|
|
312582
|
-
// Create message_triggers table
|
|
312583
|
-
const triggersExist = await knex.schema.hasTable('message_triggers');
|
|
312584
|
-
if (!triggersExist) {
|
|
312585
|
-
await knex.schema.createTable('message_triggers', table => {
|
|
312586
|
-
table.string('id', 36).primary();
|
|
312587
|
-
table.string('creator_id', 255).notNullable().index();
|
|
312588
|
-
table.string('creator_context', 255);
|
|
312589
|
-
table.string('creator_name', 255);
|
|
312590
|
-
table.text('description');
|
|
312591
|
-
table.text('channels'); // JSON array
|
|
312592
|
-
table.text('from_users'); // JSON array
|
|
312593
|
-
table.boolean('from_bots').notNullable().defaultTo(false);
|
|
312594
|
-
table.text('contains'); // JSON array
|
|
312595
|
-
table.text('match_pattern');
|
|
312596
|
-
table.string('threads', 20).notNullable().defaultTo('any');
|
|
312597
|
-
table.string('workflow', 255).notNullable();
|
|
312598
|
-
table.text('inputs'); // JSON
|
|
312599
|
-
table.text('output_context'); // JSON
|
|
312600
|
-
table.string('status', 20).notNullable().defaultTo('active').index();
|
|
312601
|
-
table.boolean('enabled').notNullable().defaultTo(true);
|
|
312602
|
-
table.bigInteger('created_at').notNullable();
|
|
312603
|
-
});
|
|
312604
|
-
}
|
|
312605
|
-
// Create scheduler_locks table for distributed locking
|
|
312606
|
-
const locksExist = await knex.schema.hasTable('scheduler_locks');
|
|
312607
|
-
if (!locksExist) {
|
|
312608
|
-
await knex.schema.createTable('scheduler_locks', table => {
|
|
312609
|
-
table.string('lock_id', 255).primary();
|
|
312610
|
-
table.string('node_id', 255).notNullable();
|
|
312611
|
-
table.string('lock_token', 36).notNullable();
|
|
312612
|
-
table.bigInteger('acquired_at').notNullable();
|
|
312613
|
-
table.bigInteger('expires_at').notNullable();
|
|
312614
|
-
});
|
|
312615
|
-
}
|
|
312616
|
-
}
|
|
312617
|
-
getKnex() {
|
|
312618
|
-
if (!this.knex) {
|
|
312619
|
-
throw new Error('[KnexStore] Not initialized. Call initialize() first.');
|
|
312620
|
-
}
|
|
312621
|
-
return this.knex;
|
|
312622
|
-
}
|
|
312623
|
-
// --- CRUD ---
|
|
312624
|
-
async create(schedule) {
|
|
312625
|
-
const knex = this.getKnex();
|
|
312626
|
-
const newSchedule = {
|
|
312627
|
-
...schedule,
|
|
312628
|
-
id: (0, uuid_1.v4)(),
|
|
312629
|
-
createdAt: Date.now(),
|
|
312630
|
-
runCount: 0,
|
|
312631
|
-
failureCount: 0,
|
|
312632
|
-
status: 'active',
|
|
312633
|
-
};
|
|
312634
|
-
await knex('schedules').insert(toInsertRow(newSchedule));
|
|
312635
|
-
logger_1.logger.info(`[KnexStore] Created schedule ${newSchedule.id} for user ${newSchedule.creatorId}`);
|
|
312636
|
-
return newSchedule;
|
|
312637
|
-
}
|
|
312638
|
-
async importSchedule(schedule) {
|
|
312639
|
-
const knex = this.getKnex();
|
|
312640
|
-
const existing = await knex('schedules').where('id', schedule.id).first();
|
|
312641
|
-
if (existing)
|
|
312642
|
-
return; // Already imported (idempotent)
|
|
312643
|
-
await knex('schedules').insert(toInsertRow(schedule));
|
|
312644
|
-
}
|
|
312645
|
-
async get(id) {
|
|
312646
|
-
const knex = this.getKnex();
|
|
312647
|
-
const row = await knex('schedules').where('id', id).first();
|
|
312648
|
-
return row ? fromDbRow(row) : undefined;
|
|
312649
|
-
}
|
|
312650
|
-
async update(id, patch) {
|
|
312651
|
-
const knex = this.getKnex();
|
|
312652
|
-
const existing = await knex('schedules').where('id', id).first();
|
|
312653
|
-
if (!existing)
|
|
312654
|
-
return undefined;
|
|
312655
|
-
const current = fromDbRow(existing);
|
|
312656
|
-
const updated = { ...current, ...patch, id: current.id };
|
|
312657
|
-
const row = toInsertRow(updated);
|
|
312658
|
-
// Remove id from update (PK cannot change)
|
|
312659
|
-
delete row.id;
|
|
312660
|
-
await knex('schedules').where('id', id).update(row);
|
|
312661
|
-
return updated;
|
|
312662
|
-
}
|
|
312663
|
-
async delete(id) {
|
|
312664
|
-
const knex = this.getKnex();
|
|
312665
|
-
const deleted = await knex('schedules').where('id', id).del();
|
|
312666
|
-
if (deleted > 0) {
|
|
312667
|
-
logger_1.logger.info(`[KnexStore] Deleted schedule ${id}`);
|
|
312668
|
-
return true;
|
|
312669
|
-
}
|
|
312670
|
-
return false;
|
|
312671
|
-
}
|
|
312672
|
-
// --- Queries ---
|
|
312673
|
-
async getByCreator(creatorId) {
|
|
312674
|
-
const knex = this.getKnex();
|
|
312675
|
-
const rows = await knex('schedules').where('creator_id', creatorId);
|
|
312676
|
-
return rows.map((r) => fromDbRow(r));
|
|
312677
|
-
}
|
|
312678
|
-
async getActiveSchedules() {
|
|
312679
|
-
const knex = this.getKnex();
|
|
312680
|
-
const rows = await knex('schedules').where('status', 'active');
|
|
312681
|
-
return rows.map((r) => fromDbRow(r));
|
|
312682
|
-
}
|
|
312683
|
-
async getDueSchedules(now) {
|
|
312684
|
-
const ts = now ?? Date.now();
|
|
312685
|
-
const knex = this.getKnex();
|
|
312686
|
-
// MSSQL uses 1/0 for booleans
|
|
312687
|
-
const bFalse = this.driver === 'mssql' ? 0 : false;
|
|
312688
|
-
const bTrue = this.driver === 'mssql' ? 1 : true;
|
|
312689
|
-
const rows = await knex('schedules')
|
|
312690
|
-
.where('status', 'active')
|
|
312691
|
-
.andWhere(function () {
|
|
312692
|
-
this.where(function () {
|
|
312693
|
-
this.where('is_recurring', bFalse)
|
|
312694
|
-
.whereNotNull('run_at')
|
|
312695
|
-
.where('run_at', '<=', ts);
|
|
312696
|
-
}).orWhere(function () {
|
|
312697
|
-
this.where('is_recurring', bTrue)
|
|
312698
|
-
.whereNotNull('next_run_at')
|
|
312699
|
-
.where('next_run_at', '<=', ts);
|
|
312700
|
-
});
|
|
312701
|
-
});
|
|
312702
|
-
return rows.map((r) => fromDbRow(r));
|
|
312703
|
-
}
|
|
312704
|
-
async findByWorkflow(creatorId, workflowName) {
|
|
312705
|
-
const knex = this.getKnex();
|
|
312706
|
-
const escaped = workflowName.toLowerCase().replace(/[%_\\]/g, '\\$&');
|
|
312707
|
-
const pattern = `%${escaped}%`;
|
|
312708
|
-
const rows = await knex('schedules')
|
|
312709
|
-
.where('creator_id', creatorId)
|
|
312710
|
-
.where('status', 'active')
|
|
312711
|
-
.whereRaw("LOWER(workflow) LIKE ? ESCAPE '\\'", [pattern]);
|
|
312712
|
-
return rows.map((r) => fromDbRow(r));
|
|
312713
|
-
}
|
|
312714
|
-
async getAll() {
|
|
312715
|
-
const knex = this.getKnex();
|
|
312716
|
-
const rows = await knex('schedules');
|
|
312717
|
-
return rows.map((r) => fromDbRow(r));
|
|
312718
|
-
}
|
|
312719
|
-
async getStats() {
|
|
312720
|
-
const knex = this.getKnex();
|
|
312721
|
-
// MSSQL uses 1/0 for booleans; PostgreSQL/MySQL accept both true/1
|
|
312722
|
-
const boolTrue = this.driver === 'mssql' ? '1' : 'true';
|
|
312723
|
-
const boolFalse = this.driver === 'mssql' ? '0' : 'false';
|
|
312724
|
-
const result = await knex('schedules')
|
|
312725
|
-
.select(knex.raw('COUNT(*) as total'), knex.raw("SUM(CASE WHEN status = 'active' THEN 1 ELSE 0 END) as active"), knex.raw("SUM(CASE WHEN status = 'paused' THEN 1 ELSE 0 END) as paused"), knex.raw("SUM(CASE WHEN status = 'completed' THEN 1 ELSE 0 END) as completed"), knex.raw("SUM(CASE WHEN status = 'failed' THEN 1 ELSE 0 END) as failed"), knex.raw(`SUM(CASE WHEN is_recurring = ${boolTrue} THEN 1 ELSE 0 END) as recurring`), knex.raw(`SUM(CASE WHEN is_recurring = ${boolFalse} THEN 1 ELSE 0 END) as one_time`))
|
|
312726
|
-
.first();
|
|
312727
|
-
return {
|
|
312728
|
-
total: Number(result.total) || 0,
|
|
312729
|
-
active: Number(result.active) || 0,
|
|
312730
|
-
paused: Number(result.paused) || 0,
|
|
312731
|
-
completed: Number(result.completed) || 0,
|
|
312732
|
-
failed: Number(result.failed) || 0,
|
|
312733
|
-
recurring: Number(result.recurring) || 0,
|
|
312734
|
-
oneTime: Number(result.one_time) || 0,
|
|
312735
|
-
};
|
|
312736
|
-
}
|
|
312737
|
-
async validateLimits(creatorId, isRecurring, limits) {
|
|
312738
|
-
const knex = this.getKnex();
|
|
312739
|
-
if (limits.maxGlobal) {
|
|
312740
|
-
const result = await knex('schedules').count('* as cnt').first();
|
|
312741
|
-
if (Number(result?.cnt) >= limits.maxGlobal) {
|
|
312742
|
-
throw new Error(`Global schedule limit reached (${limits.maxGlobal})`);
|
|
312743
|
-
}
|
|
312744
|
-
}
|
|
312745
|
-
if (limits.maxPerUser) {
|
|
312746
|
-
const result = await knex('schedules')
|
|
312747
|
-
.where('creator_id', creatorId)
|
|
312748
|
-
.count('* as cnt')
|
|
312749
|
-
.first();
|
|
312750
|
-
if (Number(result?.cnt) >= limits.maxPerUser) {
|
|
312751
|
-
throw new Error(`You have reached the maximum number of schedules (${limits.maxPerUser})`);
|
|
312752
|
-
}
|
|
312753
|
-
}
|
|
312754
|
-
if (isRecurring && limits.maxRecurringPerUser) {
|
|
312755
|
-
const bTrue = this.driver === 'mssql' ? 1 : true;
|
|
312756
|
-
const result = await knex('schedules')
|
|
312757
|
-
.where('creator_id', creatorId)
|
|
312758
|
-
.where('is_recurring', bTrue)
|
|
312759
|
-
.count('* as cnt')
|
|
312760
|
-
.first();
|
|
312761
|
-
if (Number(result?.cnt) >= limits.maxRecurringPerUser) {
|
|
312762
|
-
throw new Error(`You have reached the maximum number of recurring schedules (${limits.maxRecurringPerUser})`);
|
|
312763
|
-
}
|
|
312764
|
-
}
|
|
312765
|
-
}
|
|
312766
|
-
// --- HA Distributed Locking (via scheduler_locks table) ---
|
|
312767
|
-
async tryAcquireLock(lockId, nodeId, ttlSeconds) {
|
|
312768
|
-
const knex = this.getKnex();
|
|
312769
|
-
const now = Date.now();
|
|
312770
|
-
const expiresAt = now + ttlSeconds * 1000;
|
|
312771
|
-
const token = (0, uuid_1.v4)();
|
|
312772
|
-
// Step 1: Try to claim an existing expired lock
|
|
312773
|
-
const updated = await knex('scheduler_locks')
|
|
312774
|
-
.where('lock_id', lockId)
|
|
312775
|
-
.where('expires_at', '<', now)
|
|
312776
|
-
.update({
|
|
312777
|
-
node_id: nodeId,
|
|
312778
|
-
lock_token: token,
|
|
312779
|
-
acquired_at: now,
|
|
312780
|
-
expires_at: expiresAt,
|
|
312781
|
-
});
|
|
312782
|
-
if (updated > 0)
|
|
312783
|
-
return token;
|
|
312784
|
-
// Step 2: Try to INSERT a new lock row
|
|
312785
|
-
try {
|
|
312786
|
-
await knex('scheduler_locks').insert({
|
|
312787
|
-
lock_id: lockId,
|
|
312788
|
-
node_id: nodeId,
|
|
312789
|
-
lock_token: token,
|
|
312790
|
-
acquired_at: now,
|
|
312791
|
-
expires_at: expiresAt,
|
|
312792
|
-
});
|
|
312793
|
-
return token;
|
|
312794
|
-
}
|
|
312795
|
-
catch {
|
|
312796
|
-
// Unique constraint violation — another node holds the lock
|
|
312797
|
-
return null;
|
|
312798
|
-
}
|
|
312799
|
-
}
|
|
312800
|
-
async releaseLock(lockId, lockToken) {
|
|
312801
|
-
const knex = this.getKnex();
|
|
312802
|
-
await knex('scheduler_locks').where('lock_id', lockId).where('lock_token', lockToken).del();
|
|
312803
|
-
}
|
|
312804
|
-
async renewLock(lockId, lockToken, ttlSeconds) {
|
|
312805
|
-
const knex = this.getKnex();
|
|
312806
|
-
const now = Date.now();
|
|
312807
|
-
const expiresAt = now + ttlSeconds * 1000;
|
|
312808
|
-
const updated = await knex('scheduler_locks')
|
|
312809
|
-
.where('lock_id', lockId)
|
|
312810
|
-
.where('lock_token', lockToken)
|
|
312811
|
-
.update({ acquired_at: now, expires_at: expiresAt });
|
|
312812
|
-
return updated > 0;
|
|
312813
|
-
}
|
|
312814
|
-
async flush() {
|
|
312815
|
-
// No-op for server-based backends
|
|
312816
|
-
}
|
|
312817
|
-
// --- Message Trigger CRUD ---
|
|
312818
|
-
async createTrigger(trigger) {
|
|
312819
|
-
const knex = this.getKnex();
|
|
312820
|
-
const newTrigger = {
|
|
312821
|
-
...trigger,
|
|
312822
|
-
id: (0, uuid_1.v4)(),
|
|
312823
|
-
createdAt: Date.now(),
|
|
312824
|
-
};
|
|
312825
|
-
await knex('message_triggers').insert(toTriggerInsertRow(newTrigger));
|
|
312826
|
-
logger_1.logger.info(`[KnexStore] Created trigger ${newTrigger.id} for user ${newTrigger.creatorId}`);
|
|
312827
|
-
return newTrigger;
|
|
312828
|
-
}
|
|
312829
|
-
async getTrigger(id) {
|
|
312830
|
-
const knex = this.getKnex();
|
|
312831
|
-
const row = await knex('message_triggers').where('id', id).first();
|
|
312832
|
-
return row ? fromTriggerRow(row) : undefined;
|
|
312833
|
-
}
|
|
312834
|
-
async updateTrigger(id, patch) {
|
|
312835
|
-
const knex = this.getKnex();
|
|
312836
|
-
const existing = await knex('message_triggers').where('id', id).first();
|
|
312837
|
-
if (!existing)
|
|
312838
|
-
return undefined;
|
|
312839
|
-
const current = fromTriggerRow(existing);
|
|
312840
|
-
const updated = {
|
|
312841
|
-
...current,
|
|
312842
|
-
...patch,
|
|
312843
|
-
id: current.id,
|
|
312844
|
-
createdAt: current.createdAt,
|
|
312845
|
-
};
|
|
312846
|
-
const row = toTriggerInsertRow(updated);
|
|
312847
|
-
delete row.id;
|
|
312848
|
-
await knex('message_triggers').where('id', id).update(row);
|
|
312849
|
-
return updated;
|
|
312850
|
-
}
|
|
312851
|
-
async deleteTrigger(id) {
|
|
312852
|
-
const knex = this.getKnex();
|
|
312853
|
-
const deleted = await knex('message_triggers').where('id', id).del();
|
|
312854
|
-
if (deleted > 0) {
|
|
312855
|
-
logger_1.logger.info(`[KnexStore] Deleted trigger ${id}`);
|
|
312856
|
-
return true;
|
|
312857
|
-
}
|
|
312858
|
-
return false;
|
|
312859
|
-
}
|
|
312860
|
-
async getTriggersByCreator(creatorId) {
|
|
312861
|
-
const knex = this.getKnex();
|
|
312862
|
-
const rows = await knex('message_triggers').where('creator_id', creatorId);
|
|
312863
|
-
return rows.map((r) => fromTriggerRow(r));
|
|
312864
|
-
}
|
|
312865
|
-
async getActiveTriggers() {
|
|
312866
|
-
const knex = this.getKnex();
|
|
312867
|
-
const rows = await knex('message_triggers')
|
|
312868
|
-
.where('status', 'active')
|
|
312869
|
-
.where('enabled', this.driver === 'mssql' ? 1 : true);
|
|
312870
|
-
return rows.map((r) => fromTriggerRow(r));
|
|
312871
|
-
}
|
|
312872
|
-
}
|
|
312873
|
-
exports.KnexStoreBackend = KnexStoreBackend;
|
|
312874
|
-
|
|
312875
|
-
|
|
312876
311072
|
/***/ }),
|
|
312877
311073
|
|
|
312878
311074
|
/***/ 83864:
|
|
@@ -316414,6 +314610,10 @@ exports.configSchema = {
|
|
|
316414
314610
|
'^x-': {},
|
|
316415
314611
|
},
|
|
316416
314612
|
},
|
|
314613
|
+
rate_limit: {
|
|
314614
|
+
$ref: '#/definitions/RateLimitConfig',
|
|
314615
|
+
description: 'Rate limiting configuration for HTTP/API tools',
|
|
314616
|
+
},
|
|
316417
314617
|
workflow: {
|
|
316418
314618
|
type: 'string',
|
|
316419
314619
|
description: "Workflow ID (registry lookup) or file path (for type: 'workflow')",
|
|
@@ -316450,6 +314650,43 @@ exports.configSchema = {
|
|
|
316450
314650
|
type: 'string',
|
|
316451
314651
|
},
|
|
316452
314652
|
},
|
|
314653
|
+
RateLimitConfig: {
|
|
314654
|
+
type: 'object',
|
|
314655
|
+
properties: {
|
|
314656
|
+
key: {
|
|
314657
|
+
type: 'string',
|
|
314658
|
+
description: 'Shared bucket name; defaults to URL origin',
|
|
314659
|
+
},
|
|
314660
|
+
requests: {
|
|
314661
|
+
type: 'number',
|
|
314662
|
+
description: 'Max requests per window',
|
|
314663
|
+
},
|
|
314664
|
+
per: {
|
|
314665
|
+
type: 'string',
|
|
314666
|
+
enum: ['second', 'minute', 'hour'],
|
|
314667
|
+
description: 'Time window unit',
|
|
314668
|
+
},
|
|
314669
|
+
max_retries: {
|
|
314670
|
+
type: 'number',
|
|
314671
|
+
description: 'Max retries on 429 (default: 3)',
|
|
314672
|
+
},
|
|
314673
|
+
backoff: {
|
|
314674
|
+
type: 'string',
|
|
314675
|
+
enum: ['fixed', 'exponential'],
|
|
314676
|
+
description: 'Backoff strategy (default: exponential)',
|
|
314677
|
+
},
|
|
314678
|
+
initial_delay_ms: {
|
|
314679
|
+
type: 'number',
|
|
314680
|
+
description: 'Base delay for backoff in ms (default: 1000)',
|
|
314681
|
+
},
|
|
314682
|
+
},
|
|
314683
|
+
required: ['requests', 'per'],
|
|
314684
|
+
additionalProperties: false,
|
|
314685
|
+
description: 'Rate limit configuration for HTTP/API requests.',
|
|
314686
|
+
patternProperties: {
|
|
314687
|
+
'^x-': {},
|
|
314688
|
+
},
|
|
314689
|
+
},
|
|
316453
314690
|
WorkflowInput: {
|
|
316454
314691
|
type: 'object',
|
|
316455
314692
|
properties: {
|
|
@@ -316552,6 +314789,10 @@ exports.configSchema = {
|
|
|
316552
314789
|
$ref: '#/definitions/Record%3Cstring%2Cstring%3E',
|
|
316553
314790
|
description: 'HTTP headers',
|
|
316554
314791
|
},
|
|
314792
|
+
rate_limit: {
|
|
314793
|
+
$ref: '#/definitions/RateLimitConfig',
|
|
314794
|
+
description: 'Rate limiting configuration for http_client checks',
|
|
314795
|
+
},
|
|
316555
314796
|
endpoint: {
|
|
316556
314797
|
type: 'string',
|
|
316557
314798
|
description: 'HTTP endpoint path - required for http_input checks',
|
|
@@ -316953,7 +315194,7 @@ exports.configSchema = {
|
|
|
316953
315194
|
description: 'Arguments/inputs for the workflow',
|
|
316954
315195
|
},
|
|
316955
315196
|
overrides: {
|
|
316956
|
-
$ref: '#/definitions/Record%3Cstring%2CPartial%3Cinterface-src_types_config.ts-
|
|
315197
|
+
$ref: '#/definitions/Record%3Cstring%2CPartial%3Cinterface-src_types_config.ts-14532-29218-src_types_config.ts-0-57785%3E%3E',
|
|
316957
315198
|
description: 'Override specific step configurations in the workflow',
|
|
316958
315199
|
},
|
|
316959
315200
|
output_mapping: {
|
|
@@ -316969,7 +315210,7 @@ exports.configSchema = {
|
|
|
316969
315210
|
description: 'Config file path - alternative to workflow ID (loads a Visor config file as workflow)',
|
|
316970
315211
|
},
|
|
316971
315212
|
workflow_overrides: {
|
|
316972
|
-
$ref: '#/definitions/Record%3Cstring%2CPartial%3Cinterface-src_types_config.ts-
|
|
315213
|
+
$ref: '#/definitions/Record%3Cstring%2CPartial%3Cinterface-src_types_config.ts-14532-29218-src_types_config.ts-0-57785%3E%3E',
|
|
316973
315214
|
description: 'Alias for overrides - workflow step overrides (backward compatibility)',
|
|
316974
315215
|
},
|
|
316975
315216
|
ref: {
|
|
@@ -317671,7 +315912,7 @@ exports.configSchema = {
|
|
|
317671
315912
|
description: 'Custom output name (defaults to workflow name)',
|
|
317672
315913
|
},
|
|
317673
315914
|
overrides: {
|
|
317674
|
-
$ref: '#/definitions/Record%3Cstring%2CPartial%3Cinterface-src_types_config.ts-
|
|
315915
|
+
$ref: '#/definitions/Record%3Cstring%2CPartial%3Cinterface-src_types_config.ts-14532-29218-src_types_config.ts-0-57785%3E%3E',
|
|
317675
315916
|
description: 'Step overrides',
|
|
317676
315917
|
},
|
|
317677
315918
|
output_mapping: {
|
|
@@ -317686,13 +315927,13 @@ exports.configSchema = {
|
|
|
317686
315927
|
'^x-': {},
|
|
317687
315928
|
},
|
|
317688
315929
|
},
|
|
317689
|
-
'Record<string,Partial<interface-src_types_config.ts-
|
|
315930
|
+
'Record<string,Partial<interface-src_types_config.ts-14532-29218-src_types_config.ts-0-57785>>': {
|
|
317690
315931
|
type: 'object',
|
|
317691
315932
|
additionalProperties: {
|
|
317692
|
-
$ref: '#/definitions/Partial%3Cinterface-src_types_config.ts-
|
|
315933
|
+
$ref: '#/definitions/Partial%3Cinterface-src_types_config.ts-14532-29218-src_types_config.ts-0-57785%3E',
|
|
317693
315934
|
},
|
|
317694
315935
|
},
|
|
317695
|
-
'Partial<interface-src_types_config.ts-
|
|
315936
|
+
'Partial<interface-src_types_config.ts-14532-29218-src_types_config.ts-0-57785>': {
|
|
317696
315937
|
type: 'object',
|
|
317697
315938
|
additionalProperties: false,
|
|
317698
315939
|
},
|
|
@@ -320856,11 +319097,16 @@ const human_id_1 = __nccwpck_require__(30920);
|
|
|
320856
319097
|
const logger_1 = __nccwpck_require__(86999);
|
|
320857
319098
|
const footer_1 = __nccwpck_require__(6924);
|
|
320858
319099
|
/**
|
|
320859
|
-
* Manages GitHub PR comments with dynamic updating capabilities
|
|
319100
|
+
* Manages GitHub PR comments with dynamic updating capabilities.
|
|
319101
|
+
* All write operations are serialized through an internal queue to prevent
|
|
319102
|
+
* concurrent GitHub API calls from racing against each other.
|
|
320860
319103
|
*/
|
|
320861
319104
|
class CommentManager {
|
|
320862
319105
|
octokit;
|
|
320863
319106
|
retryConfig;
|
|
319107
|
+
// Serial write queue: chains all updateOrCreateComment calls so only one
|
|
319108
|
+
// GitHub comment write is in-flight at a time within a job.
|
|
319109
|
+
_writeQueue = Promise.resolve();
|
|
320864
319110
|
constructor(octokit, retryConfig) {
|
|
320865
319111
|
this.octokit = octokit;
|
|
320866
319112
|
this.retryConfig = {
|
|
@@ -320901,6 +319147,16 @@ class CommentManager {
|
|
|
320901
319147
|
* Update existing comment or create new one with collision detection
|
|
320902
319148
|
*/
|
|
320903
319149
|
async updateOrCreateComment(owner, repo, prNumber, content, options = {}) {
|
|
319150
|
+
// Serialize all comment writes through a single queue so only one
|
|
319151
|
+
// GitHub API write is in-flight at a time, preventing races between
|
|
319152
|
+
// concurrent checks updating the same or different comments.
|
|
319153
|
+
return new Promise((resolve, reject) => {
|
|
319154
|
+
this._writeQueue = this._writeQueue
|
|
319155
|
+
.then(() => this._doUpdateOrCreate(owner, repo, prNumber, content, options))
|
|
319156
|
+
.then(resolve, reject);
|
|
319157
|
+
});
|
|
319158
|
+
}
|
|
319159
|
+
async _doUpdateOrCreate(owner, repo, prNumber, content, options = {}) {
|
|
320904
319160
|
const { commentId = this.generateCommentId(), triggeredBy = 'unknown', allowConcurrentUpdates = false, commitSha, cachedGithubCommentId, } = options;
|
|
320905
319161
|
return this.withRetry(async () => {
|
|
320906
319162
|
// First try to find the comment via listComments API
|
|
@@ -325421,35 +323677,6 @@ class OutputFormatters {
|
|
|
325421
323677
|
exports.OutputFormatters = OutputFormatters;
|
|
325422
323678
|
|
|
325423
323679
|
|
|
325424
|
-
/***/ }),
|
|
325425
|
-
|
|
325426
|
-
/***/ 93866:
|
|
325427
|
-
/***/ ((__unused_webpack_module, exports) => {
|
|
325428
|
-
|
|
325429
|
-
"use strict";
|
|
325430
|
-
|
|
325431
|
-
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
325432
|
-
exports.DefaultPolicyEngine = void 0;
|
|
325433
|
-
/**
|
|
325434
|
-
* Default (no-op) policy engine — always allows everything.
|
|
325435
|
-
* Used when no enterprise license is present or policy is disabled.
|
|
325436
|
-
*/
|
|
325437
|
-
class DefaultPolicyEngine {
|
|
325438
|
-
async initialize(_config) { }
|
|
325439
|
-
async evaluateCheckExecution(_checkId, _checkConfig) {
|
|
325440
|
-
return { allowed: true };
|
|
325441
|
-
}
|
|
325442
|
-
async evaluateToolInvocation(_serverName, _methodName, _transport) {
|
|
325443
|
-
return { allowed: true };
|
|
325444
|
-
}
|
|
325445
|
-
async evaluateCapabilities(_checkId, _capabilities) {
|
|
325446
|
-
return { allowed: true };
|
|
325447
|
-
}
|
|
325448
|
-
async shutdown() { }
|
|
325449
|
-
}
|
|
325450
|
-
exports.DefaultPolicyEngine = DefaultPolicyEngine;
|
|
325451
|
-
|
|
325452
|
-
|
|
325453
323680
|
/***/ }),
|
|
325454
323681
|
|
|
325455
323682
|
/***/ 96611:
|
|
@@ -328686,6 +326913,7 @@ const deepmerge_1 = __importDefault(__nccwpck_require__(2569));
|
|
|
328686
326913
|
const jsonpath_plus_1 = __nccwpck_require__(55464);
|
|
328687
326914
|
const minimatch_1 = __nccwpck_require__(46507);
|
|
328688
326915
|
const logger_1 = __nccwpck_require__(86999);
|
|
326916
|
+
const rate_limiter_1 = __nccwpck_require__(56898);
|
|
328689
326917
|
const HTTP_METHODS = new Set(['get', 'put', 'post', 'delete', 'options', 'head', 'patch', 'trace']);
|
|
328690
326918
|
function isHttpUrl(value) {
|
|
328691
326919
|
return value.startsWith('http://') || value.startsWith('https://');
|
|
@@ -328951,6 +327179,7 @@ function getApiToolConfig(tool) {
|
|
|
328951
327179
|
securitySchemeName: tool.securitySchemeName ?? tool.security_scheme_name,
|
|
328952
327180
|
securityCredentials: tool.securityCredentials || tool.security_credentials || {},
|
|
328953
327181
|
requestTimeoutMs: tool.requestTimeoutMs ?? tool.request_timeout_ms ?? tool.timeout ?? 30000,
|
|
327182
|
+
rateLimitConfig: tool.rate_limit,
|
|
328954
327183
|
};
|
|
328955
327184
|
}
|
|
328956
327185
|
function buildOutputSchema(operation) {
|
|
@@ -329425,7 +327654,7 @@ async function executeMappedApiTool(mappedTool, args) {
|
|
|
329425
327654
|
const controller = new AbortController();
|
|
329426
327655
|
const timeout = setTimeout(() => controller.abort(), apiToolConfig.requestTimeoutMs);
|
|
329427
327656
|
try {
|
|
329428
|
-
const response = await
|
|
327657
|
+
const response = await (0, rate_limiter_1.rateLimitedFetch)(endpoint.toString(), {
|
|
329429
327658
|
method,
|
|
329430
327659
|
headers,
|
|
329431
327660
|
body: requestBodyValue === undefined
|
|
@@ -329434,7 +327663,7 @@ async function executeMappedApiTool(mappedTool, args) {
|
|
|
329434
327663
|
? JSON.stringify(requestBodyValue)
|
|
329435
327664
|
: String(requestBodyValue),
|
|
329436
327665
|
signal: controller.signal,
|
|
329437
|
-
});
|
|
327666
|
+
}, apiToolConfig.rateLimitConfig);
|
|
329438
327667
|
const raw = await response.text();
|
|
329439
327668
|
let body = raw;
|
|
329440
327669
|
const contentType = response.headers.get('content-type') || '';
|
|
@@ -333414,6 +331643,7 @@ const sandbox_1 = __nccwpck_require__(12630);
|
|
|
333414
331643
|
const template_context_1 = __nccwpck_require__(1581);
|
|
333415
331644
|
const oauth2_token_cache_1 = __nccwpck_require__(34713);
|
|
333416
331645
|
const logger_1 = __nccwpck_require__(86999);
|
|
331646
|
+
const rate_limiter_1 = __nccwpck_require__(56898);
|
|
333417
331647
|
const fs = __importStar(__nccwpck_require__(79896));
|
|
333418
331648
|
const path = __importStar(__nccwpck_require__(16928));
|
|
333419
331649
|
/**
|
|
@@ -333591,12 +331821,13 @@ class HttpClientProvider extends check_provider_interface_1.CheckProvider {
|
|
|
333591
331821
|
if (requestBody) {
|
|
333592
331822
|
logger_1.logger.verbose(`[http_client] Body: ${requestBody.substring(0, 500)}${requestBody.length > 500 ? '...' : ''}`);
|
|
333593
331823
|
}
|
|
331824
|
+
const rateLimitConfig = config.rate_limit;
|
|
333594
331825
|
// If output_file is specified, download to file instead of returning data
|
|
333595
331826
|
if (resolvedOutputFile) {
|
|
333596
|
-
const fileResult = await this.downloadToFile(renderedUrl, method, resolvedHeaders, requestBody, timeout, resolvedOutputFile);
|
|
331827
|
+
const fileResult = await this.downloadToFile(renderedUrl, method, resolvedHeaders, requestBody, timeout, resolvedOutputFile, rateLimitConfig);
|
|
333597
331828
|
return fileResult;
|
|
333598
331829
|
}
|
|
333599
|
-
const data = await this.fetchData(renderedUrl, method, resolvedHeaders, requestBody, timeout);
|
|
331830
|
+
const data = await this.fetchData(renderedUrl, method, resolvedHeaders, requestBody, timeout, rateLimitConfig);
|
|
333600
331831
|
// Apply Liquid transformation if specified
|
|
333601
331832
|
let processedData = data;
|
|
333602
331833
|
if (transform) {
|
|
@@ -333687,7 +331918,7 @@ class HttpClientProvider extends check_provider_interface_1.CheckProvider {
|
|
|
333687
331918
|
};
|
|
333688
331919
|
}
|
|
333689
331920
|
}
|
|
333690
|
-
async fetchData(url, method, headers, body, timeout = 30000) {
|
|
331921
|
+
async fetchData(url, method, headers, body, timeout = 30000, rateLimitConfig) {
|
|
333691
331922
|
// Check if fetch is available (Node 18+)
|
|
333692
331923
|
if (typeof fetch === 'undefined') {
|
|
333693
331924
|
throw new Error('HTTP client provider requires Node.js 18+ or node-fetch package');
|
|
@@ -333713,7 +331944,7 @@ class HttpClientProvider extends check_provider_interface_1.CheckProvider {
|
|
|
333713
331944
|
};
|
|
333714
331945
|
}
|
|
333715
331946
|
}
|
|
333716
|
-
const response = await
|
|
331947
|
+
const response = await (0, rate_limiter_1.rateLimitedFetch)(url, requestOptions, rateLimitConfig);
|
|
333717
331948
|
clearTimeout(timeoutId);
|
|
333718
331949
|
logger_1.logger.verbose(`[http_client] Response: ${response.status} ${response.statusText}`);
|
|
333719
331950
|
if (!response.ok) {
|
|
@@ -333752,7 +331983,7 @@ class HttpClientProvider extends check_provider_interface_1.CheckProvider {
|
|
|
333752
331983
|
throw error;
|
|
333753
331984
|
}
|
|
333754
331985
|
}
|
|
333755
|
-
async downloadToFile(url, method, headers, body, timeout, outputFile) {
|
|
331986
|
+
async downloadToFile(url, method, headers, body, timeout, outputFile, rateLimitConfig) {
|
|
333756
331987
|
// Check if fetch is available (Node 18+)
|
|
333757
331988
|
if (typeof fetch === 'undefined') {
|
|
333758
331989
|
throw new Error('HTTP client provider requires Node.js 18+ or node-fetch package');
|
|
@@ -333775,7 +332006,7 @@ class HttpClientProvider extends check_provider_interface_1.CheckProvider {
|
|
|
333775
332006
|
};
|
|
333776
332007
|
}
|
|
333777
332008
|
}
|
|
333778
|
-
const response = await
|
|
332009
|
+
const response = await (0, rate_limiter_1.rateLimitedFetch)(url, requestOptions, rateLimitConfig);
|
|
333779
332010
|
clearTimeout(timeoutId);
|
|
333780
332011
|
if (!response.ok) {
|
|
333781
332012
|
return {
|
|
@@ -335716,6 +333947,7 @@ const schedule_tool_1 = __nccwpck_require__(13395);
|
|
|
335716
333947
|
// Legacy Slack-specific imports for backwards compatibility
|
|
335717
333948
|
const schedule_tool_handler_1 = __nccwpck_require__(28883);
|
|
335718
333949
|
const env_resolver_1 = __nccwpck_require__(58749);
|
|
333950
|
+
const rate_limiter_1 = __nccwpck_require__(56898);
|
|
335719
333951
|
/**
|
|
335720
333952
|
* Check if a tool definition is an http_client tool
|
|
335721
333953
|
*/
|
|
@@ -336488,7 +334720,8 @@ class CustomToolsSSEServer {
|
|
|
336488
334720
|
resolvedHeaders['Content-Type'] = 'application/json';
|
|
336489
334721
|
}
|
|
336490
334722
|
}
|
|
336491
|
-
const
|
|
334723
|
+
const rateLimitConfig = tool.rate_limit;
|
|
334724
|
+
const response = await (0, rate_limiter_1.rateLimitedFetch)(url, requestOptions, rateLimitConfig);
|
|
336492
334725
|
clearTimeout(timeoutId);
|
|
336493
334726
|
if (!response.ok) {
|
|
336494
334727
|
let errorBody = '';
|
|
@@ -338008,6 +336241,17 @@ class WorkflowCheckProvider extends check_provider_interface_1.CheckProvider {
|
|
|
338008
336241
|
validateWorkflowDepth(currentDepth, maxDepth, workflow.id);
|
|
338009
336242
|
// Project workflow to dependency graph
|
|
338010
336243
|
const { config: workflowConfig, checks: checksMetadata } = projectWorkflowToGraph(workflow, inputs, config.checkName || workflow.id);
|
|
336244
|
+
// Propagate parent check's timeout to nested workflow steps that don't define their own.
|
|
336245
|
+
// This ensures that a parent `timeout: 120000` caps nested AI steps instead of them
|
|
336246
|
+
// falling back to the 30-minute default.
|
|
336247
|
+
const parentTimeout = config.timeout || config.ai?.timeout;
|
|
336248
|
+
if (parentTimeout && workflowConfig.checks) {
|
|
336249
|
+
for (const stepCfg of Object.values(workflowConfig.checks)) {
|
|
336250
|
+
if (!stepCfg.timeout && !stepCfg.ai?.timeout) {
|
|
336251
|
+
stepCfg.timeout = parentTimeout;
|
|
336252
|
+
}
|
|
336253
|
+
}
|
|
336254
|
+
}
|
|
338011
336255
|
// Build isolated child engine context (separate journal/memory to avoid state contamination)
|
|
338012
336256
|
// Reuse parent's memory config if available, but never the instance
|
|
338013
336257
|
const parentMemoryCfg = (parentContext?.memory &&
|
|
@@ -348602,7 +346846,7 @@ class StateMachineExecutionEngine {
|
|
|
348602
346846
|
try {
|
|
348603
346847
|
logger_1.logger.debug(`[PolicyEngine] Loading enterprise policy engine (engine=${configWithTagFilter.policy.engine})`);
|
|
348604
346848
|
// @ts-ignore — enterprise/ may not exist in OSS builds (caught at runtime)
|
|
348605
|
-
const { loadEnterprisePolicyEngine } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(
|
|
346849
|
+
const { loadEnterprisePolicyEngine } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(7065)));
|
|
348606
346850
|
context.policyEngine = await loadEnterprisePolicyEngine(configWithTagFilter.policy);
|
|
348607
346851
|
logger_1.logger.debug(`[PolicyEngine] Initialized: ${context.policyEngine?.constructor?.name || 'unknown'}`);
|
|
348608
346852
|
}
|
|
@@ -349636,7 +347880,12 @@ function buildEngineContextForRun(workingDirectory, config, prInfo, debug, maxPa
|
|
|
349636
347880
|
async acquire(parentSessionId, _dbg, queueTimeout) {
|
|
349637
347881
|
// Use visor session ID if probe didn't provide one
|
|
349638
347882
|
const sid = parentSessionId || sessionId;
|
|
349639
|
-
|
|
347883
|
+
// ProbeAgent calls acquire(null) without queueTimeout, which defaults
|
|
347884
|
+
// to 120s in FairConcurrencyLimiter — too short when AI checks take
|
|
347885
|
+
// 5-30+ min and slots are occupied. Override to 0 (disabled) so the
|
|
347886
|
+
// step/AI timeout governs cancellation instead.
|
|
347887
|
+
const effectiveQueueTimeout = queueTimeout ?? 0;
|
|
347888
|
+
return fairLimiter.acquire(sid, _dbg, effectiveQueueTimeout);
|
|
349640
347889
|
},
|
|
349641
347890
|
release(parentSessionId, _dbg) {
|
|
349642
347891
|
const sid = parentSessionId || sessionId;
|
|
@@ -353504,11 +351753,14 @@ async function executeCheckWithForEachItems(checkId, forEachParent, forEachItems
|
|
|
353504
351753
|
// Evaluate assume contract for this iteration (design-by-contract)
|
|
353505
351754
|
{
|
|
353506
351755
|
const assumeExpr = checkConfig?.assume;
|
|
353507
|
-
if (assumeExpr) {
|
|
351756
|
+
if (assumeExpr !== undefined && assumeExpr !== null) {
|
|
353508
351757
|
let ok = true;
|
|
353509
351758
|
try {
|
|
353510
351759
|
const evaluator = new failure_condition_evaluator_1.FailureConditionEvaluator();
|
|
353511
|
-
const
|
|
351760
|
+
const rawExprs = Array.isArray(assumeExpr) ? assumeExpr : [assumeExpr];
|
|
351761
|
+
// Coerce non-string values (e.g., YAML boolean `true`) to strings
|
|
351762
|
+
// so they can be safely evaluated as JavaScript expressions.
|
|
351763
|
+
const exprs = rawExprs.map((e) => (typeof e === 'string' ? e : String(e)));
|
|
353512
351764
|
// Get conversation from execution context (TUI/CLI) or provider event context (Slack)
|
|
353513
351765
|
const conversation = context.executionContext?.conversation ||
|
|
353514
351766
|
providerConfig?.eventContext?.conversation;
|
|
@@ -354676,11 +352928,14 @@ async function executeSingleCheck(checkId, context, state, emitEvent, transition
|
|
|
354676
352928
|
// Evaluate assume contract (design-by-contract) before executing
|
|
354677
352929
|
{
|
|
354678
352930
|
const assumeExpr = checkConfig?.assume;
|
|
354679
|
-
if (assumeExpr) {
|
|
352931
|
+
if (assumeExpr !== undefined && assumeExpr !== null) {
|
|
354680
352932
|
let ok = true;
|
|
354681
352933
|
try {
|
|
354682
352934
|
const evaluator = new failure_condition_evaluator_1.FailureConditionEvaluator();
|
|
354683
|
-
const
|
|
352935
|
+
const rawExprs = Array.isArray(assumeExpr) ? assumeExpr : [assumeExpr];
|
|
352936
|
+
// Coerce non-string values (e.g., YAML boolean `true`) to strings
|
|
352937
|
+
// so they can be safely evaluated as JavaScript expressions.
|
|
352938
|
+
const exprs = rawExprs.map((e) => (typeof e === 'string' ? e : String(e)));
|
|
354684
352939
|
// Get conversation from execution context (TUI/CLI) or provider event context (Slack)
|
|
354685
352940
|
const conversation = context.executionContext?.conversation ||
|
|
354686
352941
|
providerConfig?.eventContext?.conversation;
|
|
@@ -360346,7 +358601,7 @@ async function initTelemetry(opts = {}) {
|
|
|
360346
358601
|
const path = __nccwpck_require__(16928);
|
|
360347
358602
|
const outDir = opts.file?.dir ||
|
|
360348
358603
|
process.env.VISOR_TRACE_DIR ||
|
|
360349
|
-
|
|
358604
|
+
__nccwpck_require__.ab + "traces";
|
|
360350
358605
|
fs.mkdirSync(outDir, { recursive: true });
|
|
360351
358606
|
const ts = new Date().toISOString().replace(/[:.]/g, '-');
|
|
360352
358607
|
process.env.VISOR_FALLBACK_TRACE_FILE = path.join(outDir, `run-${ts}.ndjson`);
|
|
@@ -360596,7 +358851,7 @@ async function shutdownTelemetry() {
|
|
|
360596
358851
|
if (process.env.VISOR_TRACE_REPORT === 'true') {
|
|
360597
358852
|
const fs = __nccwpck_require__(79896);
|
|
360598
358853
|
const path = __nccwpck_require__(16928);
|
|
360599
|
-
const outDir = process.env.VISOR_TRACE_DIR ||
|
|
358854
|
+
const outDir = process.env.VISOR_TRACE_DIR || __nccwpck_require__.ab + "traces";
|
|
360600
358855
|
if (!fs.existsSync(outDir))
|
|
360601
358856
|
fs.mkdirSync(outDir, { recursive: true });
|
|
360602
358857
|
const ts = new Date().toISOString().replace(/[:.]/g, '-');
|
|
@@ -361147,7 +359402,7 @@ function __getOrCreateNdjsonPath() {
|
|
|
361147
359402
|
fs.mkdirSync(dir, { recursive: true });
|
|
361148
359403
|
return __ndjsonPath;
|
|
361149
359404
|
}
|
|
361150
|
-
const outDir = process.env.VISOR_TRACE_DIR ||
|
|
359405
|
+
const outDir = process.env.VISOR_TRACE_DIR || __nccwpck_require__.ab + "traces";
|
|
361151
359406
|
if (!fs.existsSync(outDir))
|
|
361152
359407
|
fs.mkdirSync(outDir, { recursive: true });
|
|
361153
359408
|
if (!__ndjsonPath) {
|
|
@@ -361627,7 +359882,7 @@ function expandConversationToFlow(testCase) {
|
|
|
361627
359882
|
transport,
|
|
361628
359883
|
thread: { id: threadId },
|
|
361629
359884
|
messages: [...currentMessages],
|
|
361630
|
-
current: { role: 'user', text: turn.text },
|
|
359885
|
+
current: { role: 'user', text: turn.text, ...(turn.user ? { user: turn.user } : {}) },
|
|
361631
359886
|
},
|
|
361632
359887
|
},
|
|
361633
359888
|
...(turn.mocks ? { mocks: turn.mocks } : {}),
|
|
@@ -366093,6 +364348,7 @@ const schema = {
|
|
|
366093
364348
|
properties: {
|
|
366094
364349
|
role: { type: 'string', enum: ['user', 'assistant'] },
|
|
366095
364350
|
text: { type: 'string' },
|
|
364351
|
+
user: { type: 'string' },
|
|
366096
364352
|
mocks: {
|
|
366097
364353
|
type: 'object',
|
|
366098
364354
|
additionalProperties: {
|
|
@@ -372440,6 +370696,193 @@ class OAuth2TokenCache {
|
|
|
372440
370696
|
exports.OAuth2TokenCache = OAuth2TokenCache;
|
|
372441
370697
|
|
|
372442
370698
|
|
|
370699
|
+
/***/ }),
|
|
370700
|
+
|
|
370701
|
+
/***/ 56898:
|
|
370702
|
+
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
370703
|
+
|
|
370704
|
+
"use strict";
|
|
370705
|
+
|
|
370706
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
370707
|
+
exports.RateLimiterRegistry = exports.TokenBucket = void 0;
|
|
370708
|
+
exports.resolveRateLimitKey = resolveRateLimitKey;
|
|
370709
|
+
exports.rateLimitedFetch = rateLimitedFetch;
|
|
370710
|
+
const logger_1 = __nccwpck_require__(86999);
|
|
370711
|
+
/**
|
|
370712
|
+
* Token bucket rate limiter with FIFO wait queue.
|
|
370713
|
+
*/
|
|
370714
|
+
class TokenBucket {
|
|
370715
|
+
tokens;
|
|
370716
|
+
capacity;
|
|
370717
|
+
refillRate; // tokens per ms
|
|
370718
|
+
lastRefill;
|
|
370719
|
+
waitQueue = [];
|
|
370720
|
+
constructor(capacity, windowMs) {
|
|
370721
|
+
this.capacity = capacity;
|
|
370722
|
+
this.tokens = capacity;
|
|
370723
|
+
this.refillRate = capacity / windowMs;
|
|
370724
|
+
this.lastRefill = Date.now();
|
|
370725
|
+
}
|
|
370726
|
+
refill() {
|
|
370727
|
+
const now = Date.now();
|
|
370728
|
+
const elapsed = now - this.lastRefill;
|
|
370729
|
+
const newTokens = elapsed * this.refillRate;
|
|
370730
|
+
this.tokens = Math.min(this.capacity, this.tokens + newTokens);
|
|
370731
|
+
this.lastRefill = now;
|
|
370732
|
+
}
|
|
370733
|
+
/**
|
|
370734
|
+
* Non-blocking: try to consume one token.
|
|
370735
|
+
*/
|
|
370736
|
+
tryConsume() {
|
|
370737
|
+
this.refill();
|
|
370738
|
+
if (this.tokens >= 1) {
|
|
370739
|
+
this.tokens -= 1;
|
|
370740
|
+
return true;
|
|
370741
|
+
}
|
|
370742
|
+
return false;
|
|
370743
|
+
}
|
|
370744
|
+
/**
|
|
370745
|
+
* Blocking: wait until a token is available, then consume it.
|
|
370746
|
+
* Requests are served FIFO.
|
|
370747
|
+
*/
|
|
370748
|
+
async acquire() {
|
|
370749
|
+
if (this.tryConsume()) {
|
|
370750
|
+
return;
|
|
370751
|
+
}
|
|
370752
|
+
// Calculate wait time for next token
|
|
370753
|
+
const waitMs = Math.ceil((1 - this.tokens) / this.refillRate);
|
|
370754
|
+
return new Promise(resolve => {
|
|
370755
|
+
const entry = { resolve };
|
|
370756
|
+
this.waitQueue.push(entry);
|
|
370757
|
+
setTimeout(() => {
|
|
370758
|
+
// Remove from queue
|
|
370759
|
+
const idx = this.waitQueue.indexOf(entry);
|
|
370760
|
+
if (idx >= 0) {
|
|
370761
|
+
this.waitQueue.splice(idx, 1);
|
|
370762
|
+
}
|
|
370763
|
+
this.refill();
|
|
370764
|
+
if (this.tokens >= 1) {
|
|
370765
|
+
this.tokens -= 1;
|
|
370766
|
+
}
|
|
370767
|
+
resolve();
|
|
370768
|
+
}, waitMs);
|
|
370769
|
+
});
|
|
370770
|
+
}
|
|
370771
|
+
}
|
|
370772
|
+
exports.TokenBucket = TokenBucket;
|
|
370773
|
+
function windowToMs(per) {
|
|
370774
|
+
switch (per) {
|
|
370775
|
+
case 'second':
|
|
370776
|
+
return 1000;
|
|
370777
|
+
case 'minute':
|
|
370778
|
+
return 60_000;
|
|
370779
|
+
case 'hour':
|
|
370780
|
+
return 3_600_000;
|
|
370781
|
+
}
|
|
370782
|
+
}
|
|
370783
|
+
const REGISTRY_KEY = Symbol.for('visor.rateLimiterRegistry');
|
|
370784
|
+
/**
|
|
370785
|
+
* Global singleton registry of named token buckets.
|
|
370786
|
+
*/
|
|
370787
|
+
class RateLimiterRegistry {
|
|
370788
|
+
buckets = new Map();
|
|
370789
|
+
static getInstance() {
|
|
370790
|
+
const g = globalThis;
|
|
370791
|
+
if (!g[REGISTRY_KEY]) {
|
|
370792
|
+
g[REGISTRY_KEY] = new RateLimiterRegistry();
|
|
370793
|
+
}
|
|
370794
|
+
return g[REGISTRY_KEY];
|
|
370795
|
+
}
|
|
370796
|
+
getOrCreate(key, config) {
|
|
370797
|
+
let bucket = this.buckets.get(key);
|
|
370798
|
+
if (!bucket) {
|
|
370799
|
+
const windowMs = windowToMs(config.per);
|
|
370800
|
+
bucket = new TokenBucket(config.requests, windowMs);
|
|
370801
|
+
this.buckets.set(key, bucket);
|
|
370802
|
+
logger_1.logger.verbose(`[rate-limiter] Created bucket "${key}": ${config.requests} req/${config.per}`);
|
|
370803
|
+
}
|
|
370804
|
+
return bucket;
|
|
370805
|
+
}
|
|
370806
|
+
cleanup() {
|
|
370807
|
+
this.buckets.clear();
|
|
370808
|
+
}
|
|
370809
|
+
}
|
|
370810
|
+
exports.RateLimiterRegistry = RateLimiterRegistry;
|
|
370811
|
+
/**
|
|
370812
|
+
* Resolve the rate limit key from config and optional fallback URL.
|
|
370813
|
+
*/
|
|
370814
|
+
function resolveRateLimitKey(config, fallbackUrl) {
|
|
370815
|
+
if (config.key) {
|
|
370816
|
+
return config.key;
|
|
370817
|
+
}
|
|
370818
|
+
if (fallbackUrl) {
|
|
370819
|
+
try {
|
|
370820
|
+
const url = new URL(fallbackUrl);
|
|
370821
|
+
return url.origin;
|
|
370822
|
+
}
|
|
370823
|
+
catch {
|
|
370824
|
+
// not a valid URL, use as-is
|
|
370825
|
+
return fallbackUrl;
|
|
370826
|
+
}
|
|
370827
|
+
}
|
|
370828
|
+
return '__default__';
|
|
370829
|
+
}
|
|
370830
|
+
/**
|
|
370831
|
+
* Rate-limited fetch wrapper.
|
|
370832
|
+
*
|
|
370833
|
+
* If rateLimitConfig is provided, acquires a token before making the request
|
|
370834
|
+
* and retries on 429 responses with backoff.
|
|
370835
|
+
*
|
|
370836
|
+
* If no config is provided, behaves exactly like native fetch().
|
|
370837
|
+
*/
|
|
370838
|
+
async function rateLimitedFetch(url, options, rateLimitConfig) {
|
|
370839
|
+
if (!rateLimitConfig) {
|
|
370840
|
+
return fetch(url, options);
|
|
370841
|
+
}
|
|
370842
|
+
const key = resolveRateLimitKey(rateLimitConfig, url);
|
|
370843
|
+
const registry = RateLimiterRegistry.getInstance();
|
|
370844
|
+
const bucket = registry.getOrCreate(key, rateLimitConfig);
|
|
370845
|
+
const maxRetries = rateLimitConfig.max_retries ?? 3;
|
|
370846
|
+
const backoff = rateLimitConfig.backoff ?? 'exponential';
|
|
370847
|
+
const initialDelay = rateLimitConfig.initial_delay_ms ?? 1000;
|
|
370848
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
370849
|
+
// Acquire a token (waits if bucket is empty)
|
|
370850
|
+
await bucket.acquire();
|
|
370851
|
+
const response = await fetch(url, options);
|
|
370852
|
+
if (response.status !== 429) {
|
|
370853
|
+
return response;
|
|
370854
|
+
}
|
|
370855
|
+
// 429 — rate limited by server
|
|
370856
|
+
if (attempt === maxRetries) {
|
|
370857
|
+
logger_1.logger.warn(`[rate-limiter] Exhausted ${maxRetries} retries for ${url} (bucket: ${key})`);
|
|
370858
|
+
return response;
|
|
370859
|
+
}
|
|
370860
|
+
// Calculate delay: respect Retry-After header if present
|
|
370861
|
+
let delayMs;
|
|
370862
|
+
const retryAfter = response.headers.get('retry-after');
|
|
370863
|
+
if (retryAfter) {
|
|
370864
|
+
const parsed = Number(retryAfter);
|
|
370865
|
+
if (!isNaN(parsed)) {
|
|
370866
|
+
// Retry-After in seconds
|
|
370867
|
+
delayMs = parsed * 1000;
|
|
370868
|
+
}
|
|
370869
|
+
else {
|
|
370870
|
+
// Retry-After as HTTP date
|
|
370871
|
+
const date = new Date(retryAfter).getTime();
|
|
370872
|
+
delayMs = Math.max(0, date - Date.now());
|
|
370873
|
+
}
|
|
370874
|
+
}
|
|
370875
|
+
else {
|
|
370876
|
+
delayMs = backoff === 'exponential' ? initialDelay * Math.pow(2, attempt) : initialDelay;
|
|
370877
|
+
}
|
|
370878
|
+
logger_1.logger.verbose(`[rate-limiter] 429 on ${url} (bucket: ${key}), retry ${attempt + 1}/${maxRetries} in ${delayMs}ms`);
|
|
370879
|
+
await new Promise(resolve => setTimeout(resolve, delayMs));
|
|
370880
|
+
}
|
|
370881
|
+
// Should not reach here, but satisfy TypeScript
|
|
370882
|
+
return fetch(url, options);
|
|
370883
|
+
}
|
|
370884
|
+
|
|
370885
|
+
|
|
372443
370886
|
/***/ }),
|
|
372444
370887
|
|
|
372445
370888
|
/***/ 12630:
|
|
@@ -377267,6 +375710,22 @@ class WorkflowRegistry {
|
|
|
377267
375710
|
exports.WorkflowRegistry = WorkflowRegistry;
|
|
377268
375711
|
|
|
377269
375712
|
|
|
375713
|
+
/***/ }),
|
|
375714
|
+
|
|
375715
|
+
/***/ 7065:
|
|
375716
|
+
/***/ ((module) => {
|
|
375717
|
+
|
|
375718
|
+
module.exports = eval("require")("./enterprise/loader");
|
|
375719
|
+
|
|
375720
|
+
|
|
375721
|
+
/***/ }),
|
|
375722
|
+
|
|
375723
|
+
/***/ 71370:
|
|
375724
|
+
/***/ ((module) => {
|
|
375725
|
+
|
|
375726
|
+
module.exports = eval("require")("./enterprise/policy/policy-input-builder");
|
|
375727
|
+
|
|
375728
|
+
|
|
377270
375729
|
/***/ }),
|
|
377271
375730
|
|
|
377272
375731
|
/***/ 18327:
|
|
@@ -477163,6 +475622,10 @@ var init_symbolEdit = __esm({
|
|
|
477163
475622
|
});
|
|
477164
475623
|
|
|
477165
475624
|
// src/tools/fileTracker.js
|
|
475625
|
+
function normalizePath(filePath) {
|
|
475626
|
+
if (!filePath) return filePath;
|
|
475627
|
+
return (0, import_path6.resolve)(filePath);
|
|
475628
|
+
}
|
|
477166
475629
|
function computeContentHash(content) {
|
|
477167
475630
|
const normalized = (content || "").split("\n").map((l) => l.trimEnd()).join("\n");
|
|
477168
475631
|
return (0, import_crypto2.createHash)("sha256").update(normalized).digest("hex").slice(0, 16);
|
|
@@ -477225,10 +475688,11 @@ var init_fileTracker = __esm({
|
|
|
477225
475688
|
* @param {string} resolvedPath - Absolute path to the file
|
|
477226
475689
|
*/
|
|
477227
475690
|
markFileSeen(resolvedPath) {
|
|
477228
|
-
|
|
477229
|
-
this.
|
|
475691
|
+
const normalized = normalizePath(resolvedPath);
|
|
475692
|
+
this._seenFiles.add(normalized);
|
|
475693
|
+
this._textEditCounts.set(normalized, 0);
|
|
477230
475694
|
if (this.debug) {
|
|
477231
|
-
console.error(`[FileTracker] Marked as seen: ${
|
|
475695
|
+
console.error(`[FileTracker] Marked as seen: ${normalized}`);
|
|
477232
475696
|
}
|
|
477233
475697
|
}
|
|
477234
475698
|
/**
|
|
@@ -477237,7 +475701,7 @@ var init_fileTracker = __esm({
|
|
|
477237
475701
|
* @returns {boolean}
|
|
477238
475702
|
*/
|
|
477239
475703
|
isFileSeen(resolvedPath) {
|
|
477240
|
-
return this._seenFiles.has(resolvedPath);
|
|
475704
|
+
return this._seenFiles.has(normalizePath(resolvedPath));
|
|
477241
475705
|
}
|
|
477242
475706
|
/**
|
|
477243
475707
|
* Store a content hash for a symbol in a file.
|
|
@@ -477249,7 +475713,7 @@ var init_fileTracker = __esm({
|
|
|
477249
475713
|
* @param {string} [source='extract'] - How the content was obtained
|
|
477250
475714
|
*/
|
|
477251
475715
|
trackSymbolContent(resolvedPath, symbolName, code, startLine, endLine, source = "extract") {
|
|
477252
|
-
const key = `${resolvedPath}#${symbolName}`;
|
|
475716
|
+
const key = `${normalizePath(resolvedPath)}#${symbolName}`;
|
|
477253
475717
|
const contentHash = computeContentHash(code);
|
|
477254
475718
|
this._contentRecords.set(key, {
|
|
477255
475719
|
contentHash,
|
|
@@ -477270,7 +475734,7 @@ var init_fileTracker = __esm({
|
|
|
477270
475734
|
* @returns {Object|null} The stored record or null
|
|
477271
475735
|
*/
|
|
477272
475736
|
getSymbolRecord(resolvedPath, symbolName) {
|
|
477273
|
-
return this._contentRecords.get(`${resolvedPath}#${symbolName}`) || null;
|
|
475737
|
+
return this._contentRecords.get(`${normalizePath(resolvedPath)}#${symbolName}`) || null;
|
|
477274
475738
|
}
|
|
477275
475739
|
/**
|
|
477276
475740
|
* Check if a symbol's current content matches what was stored.
|
|
@@ -477280,7 +475744,7 @@ var init_fileTracker = __esm({
|
|
|
477280
475744
|
* @returns {{ok: boolean, reason?: string, message?: string}}
|
|
477281
475745
|
*/
|
|
477282
475746
|
checkSymbolContent(resolvedPath, symbolName, currentCode) {
|
|
477283
|
-
const key = `${resolvedPath}#${symbolName}`;
|
|
475747
|
+
const key = `${normalizePath(resolvedPath)}#${symbolName}`;
|
|
477284
475748
|
const record2 = this._contentRecords.get(key);
|
|
477285
475749
|
if (!record2) {
|
|
477286
475750
|
return { ok: true };
|
|
@@ -477357,7 +475821,7 @@ var init_fileTracker = __esm({
|
|
|
477357
475821
|
* @returns {{ok: boolean, reason?: string, message?: string}}
|
|
477358
475822
|
*/
|
|
477359
475823
|
checkBeforeEdit(resolvedPath) {
|
|
477360
|
-
if (!this._seenFiles.has(resolvedPath)) {
|
|
475824
|
+
if (!this._seenFiles.has(normalizePath(resolvedPath))) {
|
|
477361
475825
|
return {
|
|
477362
475826
|
ok: false,
|
|
477363
475827
|
reason: "untracked",
|
|
@@ -477372,8 +475836,9 @@ var init_fileTracker = __esm({
|
|
|
477372
475836
|
* @param {string} resolvedPath - Absolute path to the file
|
|
477373
475837
|
*/
|
|
477374
475838
|
async trackFileAfterWrite(resolvedPath) {
|
|
477375
|
-
|
|
477376
|
-
this.
|
|
475839
|
+
const normalized = normalizePath(resolvedPath);
|
|
475840
|
+
this._seenFiles.add(normalized);
|
|
475841
|
+
this.invalidateFileRecords(normalized);
|
|
477377
475842
|
}
|
|
477378
475843
|
/**
|
|
477379
475844
|
* Record a text-mode edit (old_string/new_string) to a file.
|
|
@@ -477381,10 +475846,11 @@ var init_fileTracker = __esm({
|
|
|
477381
475846
|
* @param {string} resolvedPath - Absolute path to the file
|
|
477382
475847
|
*/
|
|
477383
475848
|
recordTextEdit(resolvedPath) {
|
|
477384
|
-
const
|
|
477385
|
-
this._textEditCounts.
|
|
475849
|
+
const normalized = normalizePath(resolvedPath);
|
|
475850
|
+
const count = (this._textEditCounts.get(normalized) || 0) + 1;
|
|
475851
|
+
this._textEditCounts.set(normalized, count);
|
|
477386
475852
|
if (this.debug) {
|
|
477387
|
-
console.error(`[FileTracker] Text edit #${count} for ${
|
|
475853
|
+
console.error(`[FileTracker] Text edit #${count} for ${normalized}`);
|
|
477388
475854
|
}
|
|
477389
475855
|
}
|
|
477390
475856
|
/**
|
|
@@ -477393,7 +475859,7 @@ var init_fileTracker = __esm({
|
|
|
477393
475859
|
* @returns {{ok: boolean, editCount?: number, message?: string}}
|
|
477394
475860
|
*/
|
|
477395
475861
|
checkTextEditStaleness(resolvedPath) {
|
|
477396
|
-
const count = this._textEditCounts.get(resolvedPath) || 0;
|
|
475862
|
+
const count = this._textEditCounts.get(normalizePath(resolvedPath)) || 0;
|
|
477397
475863
|
if (count >= this.maxConsecutiveTextEdits) {
|
|
477398
475864
|
return {
|
|
477399
475865
|
ok: false,
|
|
@@ -477422,7 +475888,7 @@ var init_fileTracker = __esm({
|
|
|
477422
475888
|
* @param {string} resolvedPath - Absolute path to the file
|
|
477423
475889
|
*/
|
|
477424
475890
|
invalidateFileRecords(resolvedPath) {
|
|
477425
|
-
const prefix = resolvedPath + "#";
|
|
475891
|
+
const prefix = normalizePath(resolvedPath) + "#";
|
|
477426
475892
|
for (const key of this._contentRecords.keys()) {
|
|
477427
475893
|
if (key.startsWith(prefix)) {
|
|
477428
475894
|
this._contentRecords.delete(key);
|
|
@@ -477438,7 +475904,7 @@ var init_fileTracker = __esm({
|
|
|
477438
475904
|
* @returns {boolean}
|
|
477439
475905
|
*/
|
|
477440
475906
|
isTracked(resolvedPath) {
|
|
477441
|
-
return this.isFileSeen(resolvedPath);
|
|
475907
|
+
return this.isFileSeen(normalizePath(resolvedPath));
|
|
477442
475908
|
}
|
|
477443
475909
|
/**
|
|
477444
475910
|
* Clear all tracking state.
|
|
@@ -481491,7 +479957,7 @@ var init_esm3 = __esm({
|
|
|
481491
479957
|
});
|
|
481492
479958
|
|
|
481493
479959
|
// node_modules/path-scurry/dist/esm/index.js
|
|
481494
|
-
var import_node_path, import_node_url, import_fs4, actualFS, import_promises, realpathSync2, defaultFS, fsFromOption, uncDriveRegexp, uncToDrive, eitherSep, UNKNOWN, IFIFO, IFCHR, IFDIR, IFBLK, IFREG, IFLNK, IFSOCK, IFMT, IFMT_UNKNOWN, READDIR_CALLED, LSTAT_CALLED, ENOTDIR, ENOENT, ENOREADLINK, ENOREALPATH, ENOCHILD, TYPEMASK, entToType, normalizeCache,
|
|
479960
|
+
var import_node_path, import_node_url, import_fs4, actualFS, import_promises, realpathSync2, defaultFS, fsFromOption, uncDriveRegexp, uncToDrive, eitherSep, UNKNOWN, IFIFO, IFCHR, IFDIR, IFBLK, IFREG, IFLNK, IFSOCK, IFMT, IFMT_UNKNOWN, READDIR_CALLED, LSTAT_CALLED, ENOTDIR, ENOENT, ENOREADLINK, ENOREALPATH, ENOCHILD, TYPEMASK, entToType, normalizeCache, normalize2, normalizeNocaseCache, normalizeNocase, ResolveCache, ChildrenCache, setAsCwd, PathBase, PathWin32, PathPosix, PathScurryBase, PathScurryWin32, PathScurryPosix, PathScurryDarwin, Path, PathScurry;
|
|
481495
479961
|
var init_esm4 = __esm({
|
|
481496
479962
|
"node_modules/path-scurry/dist/esm/index.js"() {
|
|
481497
479963
|
init_esm2();
|
|
@@ -481546,7 +480012,7 @@ var init_esm4 = __esm({
|
|
|
481546
480012
|
TYPEMASK = 1023;
|
|
481547
480013
|
entToType = (s) => s.isFile() ? IFREG : s.isDirectory() ? IFDIR : s.isSymbolicLink() ? IFLNK : s.isCharacterDevice() ? IFCHR : s.isBlockDevice() ? IFBLK : s.isSocket() ? IFSOCK : s.isFIFO() ? IFIFO : UNKNOWN;
|
|
481548
480014
|
normalizeCache = /* @__PURE__ */ new Map();
|
|
481549
|
-
|
|
480015
|
+
normalize2 = (s) => {
|
|
481550
480016
|
const c = normalizeCache.get(s);
|
|
481551
480017
|
if (c)
|
|
481552
480018
|
return c;
|
|
@@ -481559,7 +480025,7 @@ var init_esm4 = __esm({
|
|
|
481559
480025
|
const c = normalizeNocaseCache.get(s);
|
|
481560
480026
|
if (c)
|
|
481561
480027
|
return c;
|
|
481562
|
-
const n =
|
|
480028
|
+
const n = normalize2(s.toLowerCase());
|
|
481563
480029
|
normalizeNocaseCache.set(s, n);
|
|
481564
480030
|
return n;
|
|
481565
480031
|
};
|
|
@@ -481726,7 +480192,7 @@ var init_esm4 = __esm({
|
|
|
481726
480192
|
*/
|
|
481727
480193
|
constructor(name15, type = UNKNOWN, root2, roots, nocase, children, opts) {
|
|
481728
480194
|
this.name = name15;
|
|
481729
|
-
this.#matchName = nocase ? normalizeNocase(name15) :
|
|
480195
|
+
this.#matchName = nocase ? normalizeNocase(name15) : normalize2(name15);
|
|
481730
480196
|
this.#type = type & TYPEMASK;
|
|
481731
480197
|
this.nocase = nocase;
|
|
481732
480198
|
this.roots = roots;
|
|
@@ -481819,7 +480285,7 @@ var init_esm4 = __esm({
|
|
|
481819
480285
|
return this.parent || this;
|
|
481820
480286
|
}
|
|
481821
480287
|
const children = this.children();
|
|
481822
|
-
const name15 = this.nocase ? normalizeNocase(pathPart) :
|
|
480288
|
+
const name15 = this.nocase ? normalizeNocase(pathPart) : normalize2(pathPart);
|
|
481823
480289
|
for (const p of children) {
|
|
481824
480290
|
if (p.#matchName === name15) {
|
|
481825
480291
|
return p;
|
|
@@ -482064,7 +480530,7 @@ var init_esm4 = __esm({
|
|
|
482064
480530
|
* directly.
|
|
482065
480531
|
*/
|
|
482066
480532
|
isNamed(n) {
|
|
482067
|
-
return !this.nocase ? this.#matchName ===
|
|
480533
|
+
return !this.nocase ? this.#matchName === normalize2(n) : this.#matchName === normalizeNocase(n);
|
|
482068
480534
|
}
|
|
482069
480535
|
/**
|
|
482070
480536
|
* Return the Path object corresponding to the target of a symbolic link.
|
|
@@ -482203,7 +480669,7 @@ var init_esm4 = __esm({
|
|
|
482203
480669
|
#readdirMaybePromoteChild(e, c) {
|
|
482204
480670
|
for (let p = c.provisional; p < c.length; p++) {
|
|
482205
480671
|
const pchild = c[p];
|
|
482206
|
-
const name15 = this.nocase ? normalizeNocase(e.name) :
|
|
480672
|
+
const name15 = this.nocase ? normalizeNocase(e.name) : normalize2(e.name);
|
|
482207
480673
|
if (name15 !== pchild.#matchName) {
|
|
482208
480674
|
continue;
|
|
482209
480675
|
}
|
|
@@ -503520,7 +501986,7 @@ var init_graph_builder = __esm({
|
|
|
503520
501986
|
applyLinkStyles() {
|
|
503521
501987
|
if (!this.pendingLinkStyles.length || !this.edges.length)
|
|
503522
501988
|
return;
|
|
503523
|
-
const
|
|
501989
|
+
const normalize4 = (s) => {
|
|
503524
501990
|
const out = {};
|
|
503525
501991
|
for (const [kRaw, vRaw] of Object.entries(s)) {
|
|
503526
501992
|
const k = kRaw.trim().toLowerCase();
|
|
@@ -503541,7 +502007,7 @@ var init_graph_builder = __esm({
|
|
|
503541
502007
|
return out;
|
|
503542
502008
|
};
|
|
503543
502009
|
for (const cmd of this.pendingLinkStyles) {
|
|
503544
|
-
const style =
|
|
502010
|
+
const style = normalize4(cmd.props);
|
|
503545
502011
|
for (const idx of cmd.indices) {
|
|
503546
502012
|
if (idx >= 0 && idx < this.edges.length) {
|
|
503547
502013
|
const e = this.edges[idx];
|
|
@@ -510808,7 +509274,7 @@ var require_layout = __commonJS({
|
|
|
510808
509274
|
"use strict";
|
|
510809
509275
|
var _ = require_lodash2();
|
|
510810
509276
|
var acyclic = require_acyclic();
|
|
510811
|
-
var
|
|
509277
|
+
var normalize4 = require_normalize();
|
|
510812
509278
|
var rank = require_rank();
|
|
510813
509279
|
var normalizeRanks = require_util().normalizeRanks;
|
|
510814
509280
|
var parentDummyChains = require_parent_dummy_chains();
|
|
@@ -510870,7 +509336,7 @@ var require_layout = __commonJS({
|
|
|
510870
509336
|
removeEdgeLabelProxies(g);
|
|
510871
509337
|
});
|
|
510872
509338
|
time3(" normalize.run", function() {
|
|
510873
|
-
|
|
509339
|
+
normalize4.run(g);
|
|
510874
509340
|
});
|
|
510875
509341
|
time3(" parentDummyChains", function() {
|
|
510876
509342
|
parentDummyChains(g);
|
|
@@ -510897,7 +509363,7 @@ var require_layout = __commonJS({
|
|
|
510897
509363
|
removeBorderNodes(g);
|
|
510898
509364
|
});
|
|
510899
509365
|
time3(" normalize.undo", function() {
|
|
510900
|
-
|
|
509366
|
+
normalize4.undo(g);
|
|
510901
509367
|
});
|
|
510902
509368
|
time3(" fixupEdgeLabelCoords", function() {
|
|
510903
509369
|
fixupEdgeLabelCoords(g);
|
|
@@ -517268,8 +515734,8 @@ var require_resolve = __commonJS({
|
|
|
517268
515734
|
}
|
|
517269
515735
|
return count;
|
|
517270
515736
|
}
|
|
517271
|
-
function getFullPath(resolver, id = "",
|
|
517272
|
-
if (
|
|
515737
|
+
function getFullPath(resolver, id = "", normalize4) {
|
|
515738
|
+
if (normalize4 !== false)
|
|
517273
515739
|
id = normalizeId(id);
|
|
517274
515740
|
const p = resolver.parse(id);
|
|
517275
515741
|
return _getFullPath(resolver, p);
|
|
@@ -518609,7 +517075,7 @@ var require_fast_uri = __commonJS({
|
|
|
518609
517075
|
"use strict";
|
|
518610
517076
|
var { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizeComponentEncoding, isIPv4, nonSimpleDomain } = require_utils();
|
|
518611
517077
|
var { SCHEMES, getSchemeHandler } = require_schemes();
|
|
518612
|
-
function
|
|
517078
|
+
function normalize4(uri, options) {
|
|
518613
517079
|
if (typeof uri === "string") {
|
|
518614
517080
|
uri = /** @type {T} */
|
|
518615
517081
|
serialize(parse11(uri, options), options);
|
|
@@ -518845,7 +517311,7 @@ var require_fast_uri = __commonJS({
|
|
|
518845
517311
|
}
|
|
518846
517312
|
var fastUri = {
|
|
518847
517313
|
SCHEMES,
|
|
518848
|
-
normalize:
|
|
517314
|
+
normalize: normalize4,
|
|
518849
517315
|
resolve: resolve9,
|
|
518850
517316
|
resolveComponent,
|
|
518851
517317
|
equal,
|
|
@@ -523052,9 +521518,9 @@ If the solution is clear, you can jump to implementation right away. If not, ask
|
|
|
523052
521518
|
- Do not add code comments unless the logic is genuinely complex and non-obvious.
|
|
523053
521519
|
|
|
523054
521520
|
# Before Implementation
|
|
523055
|
-
-
|
|
523056
|
-
-
|
|
523057
|
-
-
|
|
521521
|
+
- Read tests first \u2014 find existing test files for the module you're changing. They reveal expected behavior, edge cases, and the project's testing patterns.
|
|
521522
|
+
- Read neighboring files \u2014 understand naming conventions, error handling patterns, import style, and existing utilities before creating new ones.
|
|
521523
|
+
- Trace the call chain \u2014 follow how the code you're changing is called and what depends on it. Check interfaces, types, and consumers.
|
|
523058
521524
|
- Focus on backward compatibility
|
|
523059
521525
|
- Consider scalability, maintainability, and extensibility in your analysis
|
|
523060
521526
|
|
|
@@ -523079,6 +521545,20 @@ Before building or testing, determine the project's toolchain:
|
|
|
523079
521545
|
- Read README for build/test instructions if the above are unclear
|
|
523080
521546
|
- Common patterns: \`make build\`/\`make test\`, \`npm run build\`/\`npm test\`, \`cargo build\`/\`cargo test\`, \`go build ./...\`/\`go test ./...\`, \`python -m pytest\`
|
|
523081
521547
|
|
|
521548
|
+
# File Editing Rules
|
|
521549
|
+
You have access to the \`edit\`, \`create\`, and \`multi_edit\` tools for modifying files. You MUST use these tools for ALL code changes. They are purpose-built, atomic, and safe.
|
|
521550
|
+
|
|
521551
|
+
DO NOT use sed, awk, echo/cat redirection, or heredocs to modify source code. These commands cause real damage in practice: truncated lines, duplicate code blocks, broken syntax. Every bad edit wastes iterations on fix-up commits.
|
|
521552
|
+
|
|
521553
|
+
Use the right tool:
|
|
521554
|
+
1. To MODIFY existing code \u2192 \`edit\` tool (old_string \u2192 new_string, or start_line/end_line)
|
|
521555
|
+
2. To CREATE a new file \u2192 \`create\` tool
|
|
521556
|
+
3. To CHANGE multiple files at once \u2192 \`multi_edit\` tool
|
|
521557
|
+
4. To READ code \u2192 \`extract\` or \`search\` tools
|
|
521558
|
+
5. If \`edit\` fails with "file has not been read yet" \u2192 use \`extract\` with the EXACT same file path you will pass to \`edit\`. Relative vs absolute path mismatch causes this error. Use the same path format consistently. If it still fails, use bash \`cat\` to read the file, then use \`create\` to write the entire modified file. Do NOT fall back to sed.
|
|
521559
|
+
|
|
521560
|
+
Bash is fine for: formatters (gofmt, prettier, black), build/test/lint commands, git operations, and read-only file inspection (cat, head, tail). sed/awk should ONLY be used for trivial non-code tasks (e.g., config file tweaks) where the replacement is a simple literal string swap.
|
|
521561
|
+
|
|
523082
521562
|
# During Implementation
|
|
523083
521563
|
- Always create a new branch before making changes to the codebase.
|
|
523084
521564
|
- Fix problems at the root cause, not with surface-level patches. Prefer general solutions over special cases.
|
|
@@ -523105,6 +521585,22 @@ Before committing or creating a PR, run through this checklist:
|
|
|
523105
521585
|
|
|
523106
521586
|
Do NOT skip verification. Do NOT proceed to PR creation with a broken build or failing tests.
|
|
523107
521587
|
|
|
521588
|
+
# Output Integrity
|
|
521589
|
+
Your final output MUST accurately reflect what ACTUALLY happened. Do NOT fabricate, hallucinate, or report aspirational results.
|
|
521590
|
+
|
|
521591
|
+
- Only report PR URLs you actually created or updated with \`gh pr create\` or \`git push\`. If you checked out an existing PR but did NOT push changes to it, do NOT claim you updated it.
|
|
521592
|
+
- Describe what you ACTUALLY DID, not what you planned or intended to do. If you ran out of iterations, say so. If tests failed, say so.
|
|
521593
|
+
- Only list files you actually modified AND committed.
|
|
521594
|
+
- If you could not complete the task \u2014 ran out of iterations, tests failed, build broken, push rejected \u2014 report the real reason honestly.
|
|
521595
|
+
|
|
521596
|
+
NEVER claim success when:
|
|
521597
|
+
- You did not run \`git push\` successfully
|
|
521598
|
+
- Tests failed and you did not fix them
|
|
521599
|
+
- You hit the iteration limit before completing the work
|
|
521600
|
+
- You only analyzed/investigated but did not implement changes
|
|
521601
|
+
|
|
521602
|
+
A false success report is WORSE than an honest failure \u2014 it misleads the user into thinking work is done when it is not.
|
|
521603
|
+
|
|
523108
521604
|
# GitHub Integration
|
|
523109
521605
|
- Use the \`gh\` CLI for all GitHub operations: issues, pull requests, checks, releases.
|
|
523110
521606
|
- To view issues or PRs: \`gh issue view <number>\`, \`gh pr view <number>\`.
|
|
@@ -551307,7 +549803,7 @@ var init_vercel = __esm({
|
|
|
551307
549803
|
name: "search",
|
|
551308
549804
|
description: searchDelegate ? searchDelegateDescription : searchDescription,
|
|
551309
549805
|
inputSchema: searchSchema,
|
|
551310
|
-
execute: async ({ query: searchQuery, path: path9, allow_tests, exact, maxTokens: paramMaxTokens, language, session, nextPage }) => {
|
|
549806
|
+
execute: async ({ query: searchQuery, path: path9, allow_tests, exact, maxTokens: paramMaxTokens, language, session, nextPage, workingDirectory }) => {
|
|
551311
549807
|
if (!exact && searchQuery) {
|
|
551312
549808
|
const originalQuery = searchQuery;
|
|
551313
549809
|
searchQuery = autoQuoteSearchTerms(searchQuery);
|
|
@@ -551316,18 +549812,19 @@ var init_vercel = __esm({
|
|
|
551316
549812
|
}
|
|
551317
549813
|
}
|
|
551318
549814
|
const effectiveMaxTokens = paramMaxTokens || maxTokens;
|
|
549815
|
+
const effectiveSearchCwd = workingDirectory || options.cwd || ".";
|
|
551319
549816
|
let searchPaths;
|
|
551320
549817
|
if (path9) {
|
|
551321
|
-
searchPaths = parseAndResolvePaths(path9,
|
|
549818
|
+
searchPaths = parseAndResolvePaths(path9, effectiveSearchCwd);
|
|
551322
549819
|
}
|
|
551323
549820
|
if (!searchPaths || searchPaths.length === 0) {
|
|
551324
|
-
searchPaths = [
|
|
549821
|
+
searchPaths = [effectiveSearchCwd];
|
|
551325
549822
|
}
|
|
551326
549823
|
const searchPath = searchPaths.join(" ");
|
|
551327
549824
|
const searchOptions = {
|
|
551328
549825
|
query: searchQuery,
|
|
551329
549826
|
path: searchPath,
|
|
551330
|
-
cwd:
|
|
549827
|
+
cwd: effectiveSearchCwd,
|
|
551331
549828
|
// Working directory for resolving relative paths
|
|
551332
549829
|
allowTests: allow_tests ?? true,
|
|
551333
549830
|
exact,
|
|
@@ -551378,7 +549875,7 @@ var init_vercel = __esm({
|
|
|
551378
549875
|
try {
|
|
551379
549876
|
const result = maybeAnnotate(await runRawSearch());
|
|
551380
549877
|
if (options.fileTracker && typeof result === "string") {
|
|
551381
|
-
options.fileTracker.trackFilesFromOutput(result,
|
|
549878
|
+
options.fileTracker.trackFilesFromOutput(result, effectiveSearchCwd).catch(() => {
|
|
551382
549879
|
});
|
|
551383
549880
|
}
|
|
551384
549881
|
return result;
|
|
@@ -551431,7 +549928,7 @@ var init_vercel = __esm({
|
|
|
551431
549928
|
}
|
|
551432
549929
|
const fallbackResult = maybeAnnotate(await runRawSearch());
|
|
551433
549930
|
if (options.fileTracker && typeof fallbackResult === "string") {
|
|
551434
|
-
options.fileTracker.trackFilesFromOutput(fallbackResult,
|
|
549931
|
+
options.fileTracker.trackFilesFromOutput(fallbackResult, effectiveSearchCwd).catch(() => {
|
|
551435
549932
|
});
|
|
551436
549933
|
}
|
|
551437
549934
|
return fallbackResult;
|
|
@@ -551494,7 +549991,7 @@ var init_vercel = __esm({
|
|
|
551494
549991
|
try {
|
|
551495
549992
|
const fallbackResult2 = maybeAnnotate(await runRawSearch());
|
|
551496
549993
|
if (options.fileTracker && typeof fallbackResult2 === "string") {
|
|
551497
|
-
options.fileTracker.trackFilesFromOutput(fallbackResult2,
|
|
549994
|
+
options.fileTracker.trackFilesFromOutput(fallbackResult2, effectiveSearchCwd).catch(() => {
|
|
551498
549995
|
});
|
|
551499
549996
|
}
|
|
551500
549997
|
return fallbackResult2;
|
|
@@ -551548,9 +550045,9 @@ var init_vercel = __esm({
|
|
|
551548
550045
|
name: "extract",
|
|
551549
550046
|
description: extractDescription,
|
|
551550
550047
|
inputSchema: extractSchema,
|
|
551551
|
-
execute: async ({ targets, input_content, line, end_line, allow_tests, context_lines, format }) => {
|
|
550048
|
+
execute: async ({ targets, input_content, line, end_line, allow_tests, context_lines, format, workingDirectory }) => {
|
|
551552
550049
|
try {
|
|
551553
|
-
const effectiveCwd = options.cwd || ".";
|
|
550050
|
+
const effectiveCwd = workingDirectory || options.cwd || ".";
|
|
551554
550051
|
if (debug) {
|
|
551555
550052
|
if (targets) {
|
|
551556
550053
|
console.error(`Executing extract with targets: "${targets}", cwd: "${effectiveCwd}", context lines: ${context_lines || 10}`);
|
|
@@ -610680,7 +609177,7 @@ module.exports = /*#__PURE__*/JSON.parse('["aaa","aarp","abb","abbott","abbvie",
|
|
|
610680
609177
|
/***/ ((module) => {
|
|
610681
609178
|
|
|
610682
609179
|
"use strict";
|
|
610683
|
-
module.exports = /*#__PURE__*/JSON.parse('{"name":"@probelabs/visor","version":"0.1.
|
|
609180
|
+
module.exports = /*#__PURE__*/JSON.parse('{"name":"@probelabs/visor","version":"0.1.178","main":"dist/index.js","bin":{"visor":"./dist/index.js"},"exports":{".":{"require":"./dist/index.js","import":"./dist/index.js"},"./sdk":{"types":"./dist/sdk/sdk.d.ts","import":"./dist/sdk/sdk.mjs","require":"./dist/sdk/sdk.js"},"./cli":{"require":"./dist/index.js"}},"files":["dist/","defaults/","action.yml","README.md","LICENSE"],"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"scripts":{"build:cli":"ncc build src/index.ts -o dist && cp -r defaults dist/ && cp -r output dist/ && cp -r docs dist/ && cp -r examples dist/ && cp -r src/debug-visualizer/ui dist/debug-visualizer/ && node scripts/inject-version.js && echo \'#!/usr/bin/env node\' | cat - dist/index.js > temp && mv temp dist/index.js && chmod +x dist/index.js","build:sdk":"tsup src/sdk.ts --dts --sourcemap --format esm,cjs --out-dir dist/sdk","build":"./scripts/build-oss.sh","build:ee":"npm run build:cli && npm run build:sdk","test":"jest && npm run test:yaml","test:unit":"jest","prepublishOnly":"npm run build","test:watch":"jest --watch","test:coverage":"jest --coverage","test:ee":"jest --testPathPatterns=\'tests/ee\' --testPathIgnorePatterns=\'/node_modules/\' --no-coverage","test:manual:bash":"RUN_MANUAL_TESTS=true jest tests/manual/bash-config-manual.test.ts","lint":"eslint src tests --ext .ts","lint:fix":"eslint src tests --ext .ts --fix","format":"prettier --write src tests","format:check":"prettier --check src tests","clean":"","clean:traces":"node scripts/clean-traces.js","prebuild":"npm run clean && node scripts/generate-config-schema.js","pretest":"npm run clean:traces && node scripts/generate-config-schema.js && npm run build:cli","pretest:unit":"npm run clean:traces && node scripts/generate-config-schema.js && npm run build:cli","test:with-build":"npm run build:cli && jest","test:yaml":"node dist/index.js test --progress compact","test:yaml:parallel":"node dist/index.js test --progress compact --max-parallel 4","prepare":"husky","pre-commit":"lint-staged","deploy:site":"cd site && npx wrangler pages deploy . --project-name=visor-site --commit-dirty=true","deploy:worker":"npx wrangler deploy","deploy":"npm run deploy:site && npm run deploy:worker","publish:ee":"./scripts/publish-ee.sh","release":"./scripts/release.sh","release:patch":"./scripts/release.sh patch","release:minor":"./scripts/release.sh minor","release:major":"./scripts/release.sh major","release:prerelease":"./scripts/release.sh prerelease","docs:validate":"node scripts/validate-readme-links.js","workshop:setup":"npm install -D reveal-md@6.1.2","workshop:serve":"cd workshop && reveal-md slides.md -w","workshop:export":"reveal-md workshop/slides.md --static workshop/build","workshop:pdf":"reveal-md workshop/slides.md --print workshop/Visor-Workshop.pdf --print-size letter","workshop:pdf:ci":"reveal-md workshop/slides.md --print workshop/Visor-Workshop.pdf --print-size letter --puppeteer-launch-args=\\"--no-sandbox --disable-dev-shm-usage\\"","workshop:pdf:a4":"reveal-md workshop/slides.md --print workshop/Visor-Workshop-A4.pdf --print-size A4","workshop:build":"npm run workshop:export && npm run workshop:pdf","simulate:issue":"TS_NODE_TRANSPILE_ONLY=1 ts-node scripts/simulate-gh-run.ts --event issues --action opened --debug","simulate:comment":"TS_NODE_TRANSPILE_ONLY=1 ts-node scripts/simulate-gh-run.ts --event issue_comment --action created --debug"},"keywords":["code-review","ai","github-action","cli","pr-review","visor"],"author":"Probe Labs","license":"MIT","description":"AI workflow engine for code review, assistants, and automation — orchestrate checks, MCP tools, and AI providers with YAML-driven pipelines","repository":{"type":"git","url":"git+https://github.com/probelabs/visor.git"},"bugs":{"url":"https://github.com/probelabs/visor/issues"},"homepage":"https://github.com/probelabs/visor#readme","dependencies":{"@actions/core":"^1.11.1","@apidevtools/swagger-parser":"^12.1.0","@grammyjs/runner":"^2.0.3","@modelcontextprotocol/sdk":"^1.25.3","@nyariv/sandboxjs":"github:probelabs/SandboxJS#23c4bb611f7d05f3cb8c523917b5f57103e48108","@octokit/action":"^8.0.2","@octokit/auth-app":"^8.1.0","@octokit/core":"^7.0.3","@octokit/rest":"^22.0.0","@opentelemetry/api":"^1.9.0","@opentelemetry/api-logs":"^0.203.0","@opentelemetry/core":"^1.30.1","@opentelemetry/exporter-logs-otlp-http":"^0.203.0","@opentelemetry/exporter-metrics-otlp-http":"^0.203.0","@opentelemetry/exporter-trace-otlp-grpc":"^0.203.0","@opentelemetry/exporter-trace-otlp-http":"^0.203.0","@opentelemetry/instrumentation":"^0.203.0","@opentelemetry/resources":"^1.30.1","@opentelemetry/sdk-logs":"^0.203.0","@opentelemetry/sdk-metrics":"^1.30.1","@opentelemetry/sdk-node":"^0.203.0","@opentelemetry/sdk-trace-base":"^1.30.1","@opentelemetry/semantic-conventions":"^1.30.1","@probelabs/probe":"^0.6.0-rc293","@types/commander":"^2.12.0","@types/uuid":"^10.0.0","acorn":"^8.16.0","acorn-walk":"^8.3.5","ajv":"^8.17.1","ajv-formats":"^3.0.1","better-sqlite3":"^11.0.0","blessed":"^0.1.81","botbuilder":"^4.23.3","botframework-connector":"^4.23.3","cli-table3":"^0.6.5","commander":"^14.0.0","deepmerge":"^4.3.1","dotenv":"^17.2.3","grammy":"^1.41.1","ignore":"^7.0.5","imapflow":"^1.2.12","js-yaml":"^4.1.0","jsonpath-plus":"^10.4.0","liquidjs":"^10.21.1","mailparser":"^3.9.3","minimatch":"^10.2.2","node-cron":"^3.0.3","nodemailer":"^8.0.1","open":"^9.1.0","resend":"^6.9.3","simple-git":"^3.28.0","uuid":"^11.1.0","ws":"^8.18.3"},"optionalDependencies":{"@anthropic/claude-code-sdk":"npm:null@*","@open-policy-agent/opa-wasm":"^1.10.0","knex":"^3.1.0","mysql2":"^3.11.0","pg":"^8.13.0","tedious":"^19.0.0"},"devDependencies":{"@eslint/js":"^9.34.0","@kie/act-js":"^2.6.2","@kie/mock-github":"^2.0.1","@swc/core":"^1.13.2","@swc/jest":"^0.2.37","@types/better-sqlite3":"^7.6.0","@types/blessed":"^0.1.27","@types/jest":"^30.0.0","@types/js-yaml":"^4.0.9","@types/mailparser":"^3.4.6","@types/node":"^24.3.0","@types/node-cron":"^3.0.11","@types/nodemailer":"^7.0.11","@types/ws":"^8.18.1","@typescript-eslint/eslint-plugin":"^8.42.0","@typescript-eslint/parser":"^8.42.0","@vercel/ncc":"^0.38.4","eslint":"^9.34.0","eslint-config-prettier":"^10.1.8","eslint-plugin-prettier":"^5.5.4","husky":"^9.1.7","jest":"^30.1.3","lint-staged":"^16.1.6","prettier":"^3.6.2","reveal-md":"^6.1.2","ts-json-schema-generator":"^1.5.1","ts-node":"^10.9.2","tsup":"^8.5.0","typescript":"^5.9.2","wrangler":"^3.0.0"},"peerDependenciesMeta":{"@anthropic/claude-code-sdk":{"optional":true}},"directories":{"test":"tests"},"lint-staged":{"src/**/*.{ts,js}":["eslint --fix","prettier --write"],"tests/**/*.{ts,js}":["eslint --fix","prettier --write"],"*.{json,md,yml,yaml}":["prettier --write"]}}');
|
|
610684
609181
|
|
|
610685
609182
|
/***/ })
|
|
610686
609183
|
|