@probelabs/visor 0.1.165-ee → 0.1.166-ee
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +525 -120
- package/dist/pr-analyzer.d.ts +2 -1
- package/dist/pr-analyzer.d.ts.map +1 -1
- package/dist/providers/http-client-provider.d.ts.map +1 -1
- package/dist/sdk/{check-provider-registry-5ZE2KMA2.mjs → check-provider-registry-PU67PWTU.mjs} +5 -5
- package/dist/sdk/{check-provider-registry-TTVN3V2O.mjs → check-provider-registry-TGPICTHD.mjs} +5 -5
- package/dist/sdk/{chunk-XDIBL7QB.mjs → chunk-E7NRUDWL.mjs} +2 -2
- package/dist/sdk/{chunk-ODEDLFSQ.mjs → chunk-P5P6BOO7.mjs} +160 -20
- package/dist/sdk/chunk-P5P6BOO7.mjs.map +1 -0
- package/dist/sdk/{chunk-J236ZVYX.mjs → chunk-RV5SK4FZ.mjs} +3 -3
- package/dist/sdk/{chunk-S47KBQQK.mjs → chunk-T5USZCCM.mjs} +2 -2
- package/dist/sdk/{chunk-S47KBQQK.mjs.map → chunk-T5USZCCM.mjs.map} +1 -1
- package/dist/sdk/{chunk-GOJRNYTV.mjs → chunk-WSYVK6ML.mjs} +188 -22
- package/dist/sdk/chunk-WSYVK6ML.mjs.map +1 -0
- package/dist/sdk/{failure-condition-evaluator-N3VNLWZD.mjs → failure-condition-evaluator-GPANOHP2.mjs} +3 -3
- package/dist/sdk/{github-frontend-ATORHHF6.mjs → github-frontend-P274ISBJ.mjs} +3 -3
- package/dist/sdk/{host-OBXKDFT7.mjs → host-AIMRV5YL.mjs} +2 -2
- package/dist/sdk/{host-QFABFVSJ.mjs → host-QYPOS4R6.mjs} +2 -2
- package/dist/sdk/{routing-TGJD66Q5.mjs → routing-BXHP2E62.mjs} +4 -4
- package/dist/sdk/{schedule-tool-D5TSTGP2.mjs → schedule-tool-5FVFYH2A.mjs} +5 -5
- package/dist/sdk/{schedule-tool-SBBVNRBS.mjs → schedule-tool-MQHISNJ6.mjs} +5 -5
- package/dist/sdk/{schedule-tool-handler-DKHHPZAG.mjs → schedule-tool-handler-4TCT2P7A.mjs} +5 -5
- package/dist/sdk/{schedule-tool-handler-DPZEXA25.mjs → schedule-tool-handler-TZYXM664.mjs} +5 -5
- package/dist/sdk/sdk.js +146 -6
- package/dist/sdk/sdk.js.map +1 -1
- package/dist/sdk/sdk.mjs +4 -4
- package/dist/sdk/{trace-helpers-J5CJ4PUN.mjs → trace-helpers-UG6FOWVV.mjs} +2 -2
- package/dist/sdk/{workflow-check-provider-HGHSY5QF.mjs → workflow-check-provider-BE2SVYWW.mjs} +5 -5
- package/dist/sdk/{workflow-check-provider-T6WFK4RB.mjs → workflow-check-provider-QKHL6AFT.mjs} +5 -5
- package/dist/slack/socket-runner.d.ts +14 -0
- package/dist/slack/socket-runner.d.ts.map +1 -1
- package/dist/utils/oauth2-token-cache.d.ts +44 -0
- package/dist/utils/oauth2-token-cache.d.ts.map +1 -0
- package/package.json +2 -2
- package/dist/sdk/chunk-GOJRNYTV.mjs.map +0 -1
- package/dist/sdk/chunk-ODEDLFSQ.mjs.map +0 -1
- /package/dist/sdk/{check-provider-registry-5ZE2KMA2.mjs.map → check-provider-registry-PU67PWTU.mjs.map} +0 -0
- /package/dist/sdk/{check-provider-registry-TTVN3V2O.mjs.map → check-provider-registry-TGPICTHD.mjs.map} +0 -0
- /package/dist/sdk/{chunk-XDIBL7QB.mjs.map → chunk-E7NRUDWL.mjs.map} +0 -0
- /package/dist/sdk/{chunk-J236ZVYX.mjs.map → chunk-RV5SK4FZ.mjs.map} +0 -0
- /package/dist/sdk/{failure-condition-evaluator-N3VNLWZD.mjs.map → failure-condition-evaluator-GPANOHP2.mjs.map} +0 -0
- /package/dist/sdk/{github-frontend-ATORHHF6.mjs.map → github-frontend-P274ISBJ.mjs.map} +0 -0
- /package/dist/sdk/{host-OBXKDFT7.mjs.map → host-AIMRV5YL.mjs.map} +0 -0
- /package/dist/sdk/{host-QFABFVSJ.mjs.map → host-QYPOS4R6.mjs.map} +0 -0
- /package/dist/sdk/{routing-TGJD66Q5.mjs.map → routing-BXHP2E62.mjs.map} +0 -0
- /package/dist/sdk/{schedule-tool-D5TSTGP2.mjs.map → schedule-tool-5FVFYH2A.mjs.map} +0 -0
- /package/dist/sdk/{schedule-tool-SBBVNRBS.mjs.map → schedule-tool-MQHISNJ6.mjs.map} +0 -0
- /package/dist/sdk/{schedule-tool-handler-DKHHPZAG.mjs.map → schedule-tool-handler-4TCT2P7A.mjs.map} +0 -0
- /package/dist/sdk/{schedule-tool-handler-DPZEXA25.mjs.map → schedule-tool-handler-TZYXM664.mjs.map} +0 -0
- /package/dist/sdk/{trace-helpers-J5CJ4PUN.mjs.map → trace-helpers-UG6FOWVV.mjs.map} +0 -0
- /package/dist/sdk/{workflow-check-provider-HGHSY5QF.mjs.map → workflow-check-provider-BE2SVYWW.mjs.map} +0 -0
- /package/dist/sdk/{workflow-check-provider-T6WFK4RB.mjs.map → workflow-check-provider-QKHL6AFT.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.166';
|
|
3
|
+
process.env.PROBE_VERSION = '0.6.0-rc280';
|
|
4
|
+
process.env.VISOR_COMMIT_SHA = 'eff5ed2df07d89e22e1c88d7d96b97572b0fd908';
|
|
5
|
+
process.env.VISOR_COMMIT_SHORT = 'eff5ed2';
|
|
6
6
|
/******/ (() => { // webpackBootstrap
|
|
7
7
|
/******/ var __webpack_modules__ = ({
|
|
8
8
|
|
|
@@ -180418,10 +180418,12 @@ const file_exclusion_1 = __nccwpck_require__(69342);
|
|
|
180418
180418
|
class PRAnalyzer {
|
|
180419
180419
|
octokit;
|
|
180420
180420
|
maxRetries;
|
|
180421
|
+
baseDelay;
|
|
180421
180422
|
fileExclusionHelper;
|
|
180422
|
-
constructor(octokit, maxRetries = 3, workingDirectory = path.resolve(process.cwd())) {
|
|
180423
|
+
constructor(octokit, maxRetries = 3, workingDirectory = path.resolve(process.cwd()), baseDelay = 1000) {
|
|
180423
180424
|
this.octokit = octokit;
|
|
180424
180425
|
this.maxRetries = maxRetries;
|
|
180426
|
+
this.baseDelay = baseDelay;
|
|
180425
180427
|
this.fileExclusionHelper = new file_exclusion_1.FileExclusionHelper(workingDirectory);
|
|
180426
180428
|
}
|
|
180427
180429
|
/**
|
|
@@ -180613,7 +180615,7 @@ class PRAnalyzer {
|
|
|
180613
180615
|
}
|
|
180614
180616
|
// Check if this is a retryable error
|
|
180615
180617
|
if (this.isRetryableError(error)) {
|
|
180616
|
-
const delay = Math.min(
|
|
180618
|
+
const delay = Math.min(this.baseDelay * Math.pow(2, attempt), this.baseDelay * 5); // Exponential backoff
|
|
180617
180619
|
await new Promise(resolve => setTimeout(resolve, delay));
|
|
180618
180620
|
}
|
|
180619
180621
|
else {
|
|
@@ -187344,6 +187346,7 @@ const liquid_extensions_1 = __nccwpck_require__(33042);
|
|
|
187344
187346
|
const env_resolver_1 = __nccwpck_require__(58749);
|
|
187345
187347
|
const sandbox_1 = __nccwpck_require__(12630);
|
|
187346
187348
|
const template_context_1 = __nccwpck_require__(1581);
|
|
187349
|
+
const oauth2_token_cache_1 = __nccwpck_require__(34713);
|
|
187347
187350
|
const logger_1 = __nccwpck_require__(86999);
|
|
187348
187351
|
const fs = __importStar(__nccwpck_require__(79896));
|
|
187349
187352
|
const path = __importStar(__nccwpck_require__(16928));
|
|
@@ -187375,13 +187378,15 @@ class HttpClientProvider extends check_provider_interface_1.CheckProvider {
|
|
|
187375
187378
|
if (cfg.type !== 'http_client') {
|
|
187376
187379
|
return false;
|
|
187377
187380
|
}
|
|
187378
|
-
// Must have
|
|
187379
|
-
|
|
187381
|
+
// Must have either `url` or `base_url` specified
|
|
187382
|
+
const hasUrl = typeof cfg.url === 'string' && cfg.url;
|
|
187383
|
+
const hasBaseUrl = typeof cfg.base_url === 'string' && cfg.base_url;
|
|
187384
|
+
if (!hasUrl && !hasBaseUrl) {
|
|
187380
187385
|
return false;
|
|
187381
187386
|
}
|
|
187382
|
-
// Validate URL format
|
|
187387
|
+
// Validate URL format (check whichever is provided)
|
|
187383
187388
|
try {
|
|
187384
|
-
new URL(cfg.url);
|
|
187389
|
+
new URL((hasUrl ? cfg.url : cfg.base_url));
|
|
187385
187390
|
return true;
|
|
187386
187391
|
}
|
|
187387
187392
|
catch {
|
|
@@ -187389,13 +187394,34 @@ class HttpClientProvider extends check_provider_interface_1.CheckProvider {
|
|
|
187389
187394
|
}
|
|
187390
187395
|
}
|
|
187391
187396
|
async execute(prInfo, config, dependencyResults, context) {
|
|
187392
|
-
const
|
|
187397
|
+
const baseUrl = config.base_url;
|
|
187398
|
+
const rawPath = config.path;
|
|
187399
|
+
const pathParams = config.params || {};
|
|
187400
|
+
const queryParams = config.query || {};
|
|
187401
|
+
const authConfig = config.auth;
|
|
187402
|
+
// Build URL: either direct `url` or `base_url` + `path` with param substitution
|
|
187403
|
+
let url;
|
|
187404
|
+
if (baseUrl && rawPath) {
|
|
187405
|
+
// Substitute {param} placeholders in path
|
|
187406
|
+
let resolvedPath = rawPath;
|
|
187407
|
+
for (const [key, value] of Object.entries(pathParams)) {
|
|
187408
|
+
resolvedPath = resolvedPath.replace(`{${key}}`, encodeURIComponent(value));
|
|
187409
|
+
}
|
|
187410
|
+
url = `${baseUrl.replace(/\/+$/, '')}/${resolvedPath.replace(/^\/+/, '')}`;
|
|
187411
|
+
// Append query parameters
|
|
187412
|
+
if (Object.keys(queryParams).length > 0) {
|
|
187413
|
+
const qs = new URLSearchParams(queryParams).toString();
|
|
187414
|
+
url += `${url.includes('?') ? '&' : '?'}${qs}`;
|
|
187415
|
+
}
|
|
187416
|
+
}
|
|
187417
|
+
else {
|
|
187418
|
+
url = config.url;
|
|
187419
|
+
}
|
|
187393
187420
|
const method = config.method || 'GET';
|
|
187394
187421
|
const headers = config.headers || {};
|
|
187395
187422
|
const timeout = config.timeout || 30000;
|
|
187396
187423
|
const transform = config.transform;
|
|
187397
187424
|
const transformJs = config.transform_js;
|
|
187398
|
-
const bodyTemplate = config.body;
|
|
187399
187425
|
const outputFileTemplate = config.output_file;
|
|
187400
187426
|
const skipIfExists = config.skip_if_exists !== false; // Default true for caching
|
|
187401
187427
|
// Track resolved URL for error messages
|
|
@@ -187416,9 +187442,14 @@ class HttpClientProvider extends check_provider_interface_1.CheckProvider {
|
|
|
187416
187442
|
renderedUrl = await this.liquid.parseAndRender(renderedUrl, templateContext);
|
|
187417
187443
|
resolvedUrlForErrors = renderedUrl; // Update after Liquid rendering
|
|
187418
187444
|
}
|
|
187419
|
-
// Prepare request body
|
|
187445
|
+
// Prepare request body — supports both Liquid template strings and JSON objects
|
|
187420
187446
|
let requestBody;
|
|
187421
|
-
|
|
187447
|
+
const rawBody = config.body;
|
|
187448
|
+
const bodyTemplate = typeof rawBody === 'string' ? rawBody : undefined;
|
|
187449
|
+
if (rawBody && typeof rawBody === 'object') {
|
|
187450
|
+
requestBody = JSON.stringify(rawBody);
|
|
187451
|
+
}
|
|
187452
|
+
else if (bodyTemplate) {
|
|
187422
187453
|
// First resolve shell-style environment variables
|
|
187423
187454
|
let resolvedBody = String(env_resolver_1.EnvironmentResolver.resolveValue(bodyTemplate));
|
|
187424
187455
|
// Then render Liquid templates if present
|
|
@@ -187444,6 +187475,12 @@ class HttpClientProvider extends check_provider_interface_1.CheckProvider {
|
|
|
187444
187475
|
logger_1.logger.verbose(`[http_client] ${key}: ${maskedValue}`);
|
|
187445
187476
|
}
|
|
187446
187477
|
}
|
|
187478
|
+
// Inject OAuth2 Bearer token if auth config is provided
|
|
187479
|
+
if (authConfig?.type === 'oauth2_client_credentials') {
|
|
187480
|
+
const tokenCache = oauth2_token_cache_1.OAuth2TokenCache.getInstance();
|
|
187481
|
+
const token = await tokenCache.getToken(authConfig);
|
|
187482
|
+
resolvedHeaders['Authorization'] = `Bearer ${token}`;
|
|
187483
|
+
}
|
|
187447
187484
|
// Resolve output_file path if specified
|
|
187448
187485
|
let resolvedOutputFile;
|
|
187449
187486
|
if (outputFileTemplate) {
|
|
@@ -187741,6 +187778,11 @@ class HttpClientProvider extends check_provider_interface_1.CheckProvider {
|
|
|
187741
187778
|
return [
|
|
187742
187779
|
'type',
|
|
187743
187780
|
'url',
|
|
187781
|
+
'base_url',
|
|
187782
|
+
'path',
|
|
187783
|
+
'params',
|
|
187784
|
+
'query',
|
|
187785
|
+
'auth',
|
|
187744
187786
|
'method',
|
|
187745
187787
|
'headers',
|
|
187746
187788
|
'body',
|
|
@@ -200422,6 +200464,9 @@ class SlackSocketRunner {
|
|
|
200422
200464
|
genericScheduler;
|
|
200423
200465
|
messageTriggerEvaluator;
|
|
200424
200466
|
activeThreads = new Set();
|
|
200467
|
+
heartbeatTimer;
|
|
200468
|
+
lastPong = 0;
|
|
200469
|
+
closing = false; // prevent duplicate reconnects
|
|
200425
200470
|
constructor(engine, cfg, opts) {
|
|
200426
200471
|
const app = opts.appToken || process.env.SLACK_APP_TOKEN || '';
|
|
200427
200472
|
if (!app)
|
|
@@ -200612,21 +200657,93 @@ class SlackSocketRunner {
|
|
|
200612
200657
|
return json.url;
|
|
200613
200658
|
}
|
|
200614
200659
|
async connect(url) {
|
|
200615
|
-
|
|
200616
|
-
this.
|
|
200660
|
+
// Close previous WebSocket to prevent ghost event handlers
|
|
200661
|
+
this.closeWebSocket();
|
|
200662
|
+
const ws = new ws_1.default(url);
|
|
200663
|
+
this.ws = ws;
|
|
200664
|
+
this.closing = false;
|
|
200665
|
+
ws.on('open', () => {
|
|
200617
200666
|
this.retryCount = 0; // Reset on successful connection
|
|
200667
|
+
this.lastPong = Date.now();
|
|
200618
200668
|
logger_1.logger.info('[SlackSocket] WebSocket connected');
|
|
200669
|
+
this.startHeartbeat();
|
|
200619
200670
|
});
|
|
200620
|
-
|
|
200671
|
+
ws.on('close', (code, reason) => {
|
|
200621
200672
|
logger_1.logger.warn(`[SlackSocket] WebSocket closed: ${code} ${reason}`);
|
|
200622
|
-
|
|
200673
|
+
this.stopHeartbeat();
|
|
200674
|
+
// Only reconnect if this is still the active WebSocket
|
|
200675
|
+
if (this.ws === ws && !this.closing) {
|
|
200676
|
+
this.closing = true;
|
|
200677
|
+
setTimeout(() => this.restart(), 1000);
|
|
200678
|
+
}
|
|
200623
200679
|
});
|
|
200624
|
-
|
|
200680
|
+
ws.on('error', err => {
|
|
200625
200681
|
logger_1.logger.error(`[SlackSocket] WebSocket error: ${err}`);
|
|
200626
200682
|
});
|
|
200627
|
-
|
|
200683
|
+
ws.on('pong', () => {
|
|
200684
|
+
this.lastPong = Date.now();
|
|
200685
|
+
});
|
|
200686
|
+
ws.on('message', data => this.handleMessage(data.toString()).catch(() => { }));
|
|
200687
|
+
}
|
|
200688
|
+
/**
|
|
200689
|
+
* Close the current WebSocket connection and stop heartbeat.
|
|
200690
|
+
* Safe to call multiple times.
|
|
200691
|
+
*/
|
|
200692
|
+
closeWebSocket() {
|
|
200693
|
+
this.stopHeartbeat();
|
|
200694
|
+
if (this.ws) {
|
|
200695
|
+
const old = this.ws;
|
|
200696
|
+
this.ws = undefined;
|
|
200697
|
+
try {
|
|
200698
|
+
// Remove listeners to prevent ghost close/message handlers
|
|
200699
|
+
old.removeAllListeners();
|
|
200700
|
+
old.close();
|
|
200701
|
+
}
|
|
200702
|
+
catch {
|
|
200703
|
+
// best effort
|
|
200704
|
+
}
|
|
200705
|
+
}
|
|
200706
|
+
}
|
|
200707
|
+
/**
|
|
200708
|
+
* Start periodic WebSocket ping to detect dead connections.
|
|
200709
|
+
* If no pong is received within 60s, force a reconnect.
|
|
200710
|
+
*/
|
|
200711
|
+
startHeartbeat() {
|
|
200712
|
+
this.stopHeartbeat();
|
|
200713
|
+
const PING_INTERVAL_MS = 30_000; // ping every 30s
|
|
200714
|
+
const PONG_TIMEOUT_MS = 60_000; // dead if no pong for 60s
|
|
200715
|
+
this.heartbeatTimer = setInterval(() => {
|
|
200716
|
+
if (!this.ws || this.ws.readyState !== ws_1.default.OPEN)
|
|
200717
|
+
return;
|
|
200718
|
+
// Check if last pong is stale
|
|
200719
|
+
const sincePong = Date.now() - this.lastPong;
|
|
200720
|
+
if (this.lastPong > 0 && sincePong > PONG_TIMEOUT_MS) {
|
|
200721
|
+
logger_1.logger.warn(`[SlackSocket] No pong received for ${Math.round(sincePong / 1000)}s, forcing reconnect`);
|
|
200722
|
+
this.closeWebSocket();
|
|
200723
|
+
this.closing = true;
|
|
200724
|
+
this.restart();
|
|
200725
|
+
return;
|
|
200726
|
+
}
|
|
200727
|
+
try {
|
|
200728
|
+
this.ws.ping();
|
|
200729
|
+
}
|
|
200730
|
+
catch {
|
|
200731
|
+
// ping failed — connection is likely dead
|
|
200732
|
+
logger_1.logger.warn('[SlackSocket] Ping failed, forcing reconnect');
|
|
200733
|
+
this.closeWebSocket();
|
|
200734
|
+
this.closing = true;
|
|
200735
|
+
this.restart();
|
|
200736
|
+
}
|
|
200737
|
+
}, PING_INTERVAL_MS);
|
|
200738
|
+
}
|
|
200739
|
+
stopHeartbeat() {
|
|
200740
|
+
if (this.heartbeatTimer) {
|
|
200741
|
+
clearInterval(this.heartbeatTimer);
|
|
200742
|
+
this.heartbeatTimer = undefined;
|
|
200743
|
+
}
|
|
200628
200744
|
}
|
|
200629
200745
|
async restart() {
|
|
200746
|
+
this.closing = false;
|
|
200630
200747
|
try {
|
|
200631
200748
|
const url = await this.openConnection();
|
|
200632
200749
|
await this.connect(url);
|
|
@@ -200636,7 +200753,7 @@ class SlackSocketRunner {
|
|
|
200636
200753
|
// Exponential backoff: 2s, 4s, 8s, 16s, 32s, capped at 60s
|
|
200637
200754
|
const delay = Math.min(2000 * Math.pow(2, this.retryCount - 1), 60000);
|
|
200638
200755
|
logger_1.logger.error(`[SlackSocket] Restart failed (attempt ${this.retryCount}), retrying in ${Math.round(delay / 1000)}s: ${e instanceof Error ? e.message : e}`);
|
|
200639
|
-
setTimeout(() => this.restart()
|
|
200756
|
+
setTimeout(() => this.restart(), delay);
|
|
200640
200757
|
}
|
|
200641
200758
|
}
|
|
200642
200759
|
send(obj) {
|
|
@@ -200714,6 +200831,16 @@ class SlackSocketRunner {
|
|
|
200714
200831
|
return;
|
|
200715
200832
|
if (env.envelope_id)
|
|
200716
200833
|
this.send({ envelope_id: env.envelope_id }); // ack ASAP
|
|
200834
|
+
// Handle Slack disconnect events — proactively reconnect before the connection dies
|
|
200835
|
+
if (env.type === 'disconnect') {
|
|
200836
|
+
const reason = env.reason || 'unknown';
|
|
200837
|
+
logger_1.logger.info(`[SlackSocket] Received disconnect event (reason: ${reason}), reconnecting`);
|
|
200838
|
+
// Slack will close the connection shortly; proactively reconnect now
|
|
200839
|
+
this.closeWebSocket();
|
|
200840
|
+
this.closing = true;
|
|
200841
|
+
this.restart();
|
|
200842
|
+
return;
|
|
200843
|
+
}
|
|
200717
200844
|
if (env.type !== 'events_api' || !env.payload) {
|
|
200718
200845
|
if (process.env.VISOR_DEBUG === 'true') {
|
|
200719
200846
|
logger_1.logger.debug(`[SlackSocket] Dropping non-events payload: type=${String(env.type || '-')}`);
|
|
@@ -201417,17 +201544,10 @@ class SlackSocketRunner {
|
|
|
201417
201544
|
logger_1.logger.warn(`[SlackSocket] Error stopping generic scheduler: ${e instanceof Error ? e.message : e}`);
|
|
201418
201545
|
}
|
|
201419
201546
|
}
|
|
201420
|
-
// Close WebSocket connection
|
|
201421
|
-
|
|
201422
|
-
|
|
201423
|
-
|
|
201424
|
-
this.ws = undefined;
|
|
201425
|
-
logger_1.logger.info('[SlackSocket] WebSocket closed');
|
|
201426
|
-
}
|
|
201427
|
-
catch {
|
|
201428
|
-
// Best effort
|
|
201429
|
-
}
|
|
201430
|
-
}
|
|
201547
|
+
// Close WebSocket connection and stop heartbeat
|
|
201548
|
+
this.closing = true; // prevent reconnect on close
|
|
201549
|
+
this.closeWebSocket();
|
|
201550
|
+
logger_1.logger.info('[SlackSocket] WebSocket closed');
|
|
201431
201551
|
}
|
|
201432
201552
|
/**
|
|
201433
201553
|
* Get the scheduler instance
|
|
@@ -223021,6 +223141,130 @@ function emitMermaidFromMarkdown(checkName, markdown, origin) {
|
|
|
223021
223141
|
}
|
|
223022
223142
|
|
|
223023
223143
|
|
|
223144
|
+
/***/ }),
|
|
223145
|
+
|
|
223146
|
+
/***/ 34713:
|
|
223147
|
+
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
223148
|
+
|
|
223149
|
+
"use strict";
|
|
223150
|
+
|
|
223151
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
223152
|
+
exports.OAuth2TokenCache = void 0;
|
|
223153
|
+
const logger_1 = __nccwpck_require__(86999);
|
|
223154
|
+
const env_resolver_1 = __nccwpck_require__(58749);
|
|
223155
|
+
/**
|
|
223156
|
+
* Singleton cache for OAuth2 tokens.
|
|
223157
|
+
*
|
|
223158
|
+
* - Keyed by hash(token_url + client_id) to support multiple providers
|
|
223159
|
+
* - Lazy refresh: only fetches when expired or near-expiry
|
|
223160
|
+
* - Deduplicates concurrent requests: if two calls hit with an expired token,
|
|
223161
|
+
* both await the same fetch promise
|
|
223162
|
+
*/
|
|
223163
|
+
class OAuth2TokenCache {
|
|
223164
|
+
static instance;
|
|
223165
|
+
cache = new Map();
|
|
223166
|
+
static getInstance() {
|
|
223167
|
+
if (!OAuth2TokenCache.instance) {
|
|
223168
|
+
OAuth2TokenCache.instance = new OAuth2TokenCache();
|
|
223169
|
+
}
|
|
223170
|
+
return OAuth2TokenCache.instance;
|
|
223171
|
+
}
|
|
223172
|
+
/** Visible for testing */
|
|
223173
|
+
static resetInstance() {
|
|
223174
|
+
OAuth2TokenCache.instance = undefined;
|
|
223175
|
+
}
|
|
223176
|
+
/**
|
|
223177
|
+
* Get a valid Bearer token for the given config.
|
|
223178
|
+
* Returns a cached token if still valid, otherwise fetches a new one.
|
|
223179
|
+
*/
|
|
223180
|
+
async getToken(config) {
|
|
223181
|
+
const clientId = String(env_resolver_1.EnvironmentResolver.resolveValue(config.client_id));
|
|
223182
|
+
const clientSecret = String(env_resolver_1.EnvironmentResolver.resolveValue(config.client_secret));
|
|
223183
|
+
const tokenUrl = String(env_resolver_1.EnvironmentResolver.resolveValue(config.token_url));
|
|
223184
|
+
const bufferMs = (config.token_ttl_buffer ?? 300) * 1000;
|
|
223185
|
+
const cacheKey = `${tokenUrl}|${clientId}`;
|
|
223186
|
+
const cached = this.cache.get(cacheKey);
|
|
223187
|
+
// Return cached token if still valid (with buffer)
|
|
223188
|
+
if (cached && cached.expires_at - bufferMs > Date.now()) {
|
|
223189
|
+
logger_1.logger.verbose('[oauth2] Using cached token');
|
|
223190
|
+
return cached.access_token;
|
|
223191
|
+
}
|
|
223192
|
+
// If another request is already refreshing, await it
|
|
223193
|
+
if (cached?.refreshPromise) {
|
|
223194
|
+
logger_1.logger.verbose('[oauth2] Awaiting in-flight token refresh');
|
|
223195
|
+
return cached.refreshPromise;
|
|
223196
|
+
}
|
|
223197
|
+
// Fetch a new token
|
|
223198
|
+
const refreshPromise = this.fetchToken(tokenUrl, clientId, clientSecret, config.scopes);
|
|
223199
|
+
// Store the promise so concurrent callers share it
|
|
223200
|
+
if (cached) {
|
|
223201
|
+
cached.refreshPromise = refreshPromise;
|
|
223202
|
+
}
|
|
223203
|
+
else {
|
|
223204
|
+
this.cache.set(cacheKey, {
|
|
223205
|
+
access_token: '',
|
|
223206
|
+
expires_at: 0,
|
|
223207
|
+
refreshPromise,
|
|
223208
|
+
});
|
|
223209
|
+
}
|
|
223210
|
+
try {
|
|
223211
|
+
const token = await refreshPromise;
|
|
223212
|
+
return token;
|
|
223213
|
+
}
|
|
223214
|
+
finally {
|
|
223215
|
+
// Clear the in-flight promise regardless of outcome
|
|
223216
|
+
const entry = this.cache.get(cacheKey);
|
|
223217
|
+
if (entry) {
|
|
223218
|
+
entry.refreshPromise = undefined;
|
|
223219
|
+
}
|
|
223220
|
+
}
|
|
223221
|
+
}
|
|
223222
|
+
async fetchToken(tokenUrl, clientId, clientSecret, scopes) {
|
|
223223
|
+
logger_1.logger.verbose(`[oauth2] Fetching token from ${tokenUrl}`);
|
|
223224
|
+
const credentials = Buffer.from(`${clientId}:${clientSecret}`).toString('base64');
|
|
223225
|
+
const bodyParams = new URLSearchParams({ grant_type: 'client_credentials' });
|
|
223226
|
+
if (scopes?.length) {
|
|
223227
|
+
bodyParams.set('scope', scopes.join(' '));
|
|
223228
|
+
}
|
|
223229
|
+
const response = await fetch(tokenUrl, {
|
|
223230
|
+
method: 'POST',
|
|
223231
|
+
headers: {
|
|
223232
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
223233
|
+
Authorization: `Basic ${credentials}`,
|
|
223234
|
+
},
|
|
223235
|
+
body: bodyParams.toString(),
|
|
223236
|
+
});
|
|
223237
|
+
if (!response.ok) {
|
|
223238
|
+
let errorDetail = '';
|
|
223239
|
+
try {
|
|
223240
|
+
errorDetail = await response.text();
|
|
223241
|
+
}
|
|
223242
|
+
catch { }
|
|
223243
|
+
throw new Error(`OAuth2 token request failed: HTTP ${response.status} ${response.statusText}${errorDetail ? ` - ${errorDetail.substring(0, 200)}` : ''}`);
|
|
223244
|
+
}
|
|
223245
|
+
const data = (await response.json());
|
|
223246
|
+
if (!data.access_token) {
|
|
223247
|
+
throw new Error('OAuth2 token response missing access_token');
|
|
223248
|
+
}
|
|
223249
|
+
// Default to 1 hour if expires_in not provided
|
|
223250
|
+
const expiresIn = data.expires_in ?? 3600;
|
|
223251
|
+
const expiresAt = Date.now() + expiresIn * 1000;
|
|
223252
|
+
const cacheKey = `${tokenUrl}|${clientId}`;
|
|
223253
|
+
this.cache.set(cacheKey, {
|
|
223254
|
+
access_token: data.access_token,
|
|
223255
|
+
expires_at: expiresAt,
|
|
223256
|
+
});
|
|
223257
|
+
logger_1.logger.verbose(`[oauth2] Token acquired, expires in ${expiresIn}s`);
|
|
223258
|
+
return data.access_token;
|
|
223259
|
+
}
|
|
223260
|
+
/** Clear all cached tokens (for testing or credential rotation) */
|
|
223261
|
+
clear() {
|
|
223262
|
+
this.cache.clear();
|
|
223263
|
+
}
|
|
223264
|
+
}
|
|
223265
|
+
exports.OAuth2TokenCache = OAuth2TokenCache;
|
|
223266
|
+
|
|
223267
|
+
|
|
223024
223268
|
/***/ }),
|
|
223025
223269
|
|
|
223026
223270
|
/***/ 12630:
|
|
@@ -249925,9 +250169,7 @@ async function acquireFileLock(lockPath, version2) {
|
|
|
249925
250169
|
};
|
|
249926
250170
|
try {
|
|
249927
250171
|
await import_fs_extra2.default.writeFile(lockPath, JSON.stringify(lockData), { flag: "wx" });
|
|
249928
|
-
|
|
249929
|
-
console.log(`Acquired file lock: ${lockPath}`);
|
|
249930
|
-
}
|
|
250172
|
+
console.log(`Acquired file lock: ${lockPath}`);
|
|
249931
250173
|
return true;
|
|
249932
250174
|
} catch (error2) {
|
|
249933
250175
|
if (error2.code === "EEXIST") {
|
|
@@ -249935,15 +250177,11 @@ async function acquireFileLock(lockPath, version2) {
|
|
|
249935
250177
|
const existingLock = JSON.parse(await import_fs_extra2.default.readFile(lockPath, "utf-8"));
|
|
249936
250178
|
const lockAge = Date.now() - existingLock.timestamp;
|
|
249937
250179
|
if (lockAge > LOCK_TIMEOUT_MS) {
|
|
249938
|
-
|
|
249939
|
-
console.log(`Removing stale lock file (age: ${Math.round(lockAge / 1e3)}s, pid: ${existingLock.pid})`);
|
|
249940
|
-
}
|
|
250180
|
+
console.log(`Removing stale lock file (age: ${Math.round(lockAge / 1e3)}s, pid: ${existingLock.pid})`);
|
|
249941
250181
|
await import_fs_extra2.default.remove(lockPath);
|
|
249942
250182
|
return false;
|
|
249943
250183
|
}
|
|
249944
|
-
|
|
249945
|
-
console.log(`Download in progress by process ${existingLock.pid}, waiting...`);
|
|
249946
|
-
}
|
|
250184
|
+
console.log(`Download in progress by process ${existingLock.pid}, waiting...`);
|
|
249947
250185
|
return false;
|
|
249948
250186
|
} catch (readError) {
|
|
249949
250187
|
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
|
|
@@ -249984,36 +250222,36 @@ async function releaseFileLock(lockPath) {
|
|
|
249984
250222
|
}
|
|
249985
250223
|
async function waitForFileLock(lockPath, binaryPath) {
|
|
249986
250224
|
const startTime = Date.now();
|
|
250225
|
+
let lastStatusTime = startTime;
|
|
250226
|
+
console.log(`Waiting for file lock to clear: ${lockPath}`);
|
|
249987
250227
|
while (Date.now() - startTime < MAX_LOCK_WAIT_MS) {
|
|
249988
250228
|
if (await import_fs_extra2.default.pathExists(binaryPath)) {
|
|
249989
|
-
|
|
249990
|
-
|
|
249991
|
-
}
|
|
250229
|
+
const waitedSeconds = Math.round((Date.now() - startTime) / 1e3);
|
|
250230
|
+
console.log(`Binary now available at ${binaryPath}, download completed by another process (waited ${waitedSeconds}s)`);
|
|
249992
250231
|
return true;
|
|
249993
250232
|
}
|
|
249994
250233
|
const lockExists = await import_fs_extra2.default.pathExists(lockPath);
|
|
249995
250234
|
if (!lockExists) {
|
|
249996
|
-
|
|
249997
|
-
console.log(`Lock file removed but binary not found - download may have failed`);
|
|
249998
|
-
}
|
|
250235
|
+
console.log(`Lock file removed but binary not found - download may have failed`);
|
|
249999
250236
|
return false;
|
|
250000
250237
|
}
|
|
250001
250238
|
try {
|
|
250002
250239
|
const lockData = JSON.parse(await import_fs_extra2.default.readFile(lockPath, "utf-8"));
|
|
250003
250240
|
const lockAge = Date.now() - lockData.timestamp;
|
|
250004
250241
|
if (lockAge > LOCK_TIMEOUT_MS) {
|
|
250005
|
-
|
|
250006
|
-
console.log(`Lock expired (age: ${Math.round(lockAge / 1e3)}s), will retry download`);
|
|
250007
|
-
}
|
|
250242
|
+
console.log(`Lock expired (age: ${Math.round(lockAge / 1e3)}s), will retry download`);
|
|
250008
250243
|
return false;
|
|
250009
250244
|
}
|
|
250010
250245
|
} catch {
|
|
250011
250246
|
}
|
|
250247
|
+
if (Date.now() - lastStatusTime >= 15e3) {
|
|
250248
|
+
const elapsedSeconds = Math.round((Date.now() - startTime) / 1e3);
|
|
250249
|
+
console.log(`Still waiting for file lock (${elapsedSeconds}s/${MAX_LOCK_WAIT_MS / 1e3}s max)`);
|
|
250250
|
+
lastStatusTime = Date.now();
|
|
250251
|
+
}
|
|
250012
250252
|
await new Promise((resolve8) => setTimeout(resolve8, LOCK_POLL_INTERVAL_MS));
|
|
250013
250253
|
}
|
|
250014
|
-
|
|
250015
|
-
console.log(`Timeout waiting for file lock`);
|
|
250016
|
-
}
|
|
250254
|
+
console.log(`Timeout waiting for file lock after ${MAX_LOCK_WAIT_MS / 1e3}s`);
|
|
250017
250255
|
return false;
|
|
250018
250256
|
}
|
|
250019
250257
|
async function withDownloadLock(version2, downloadFn) {
|
|
@@ -250027,9 +250265,7 @@ async function withDownloadLock(version2, downloadFn) {
|
|
|
250027
250265
|
}
|
|
250028
250266
|
downloadLocks.delete(lockKey);
|
|
250029
250267
|
} else {
|
|
250030
|
-
|
|
250031
|
-
console.log(`Download already in progress in this process for version ${lockKey}, waiting...`);
|
|
250032
|
-
}
|
|
250268
|
+
console.log(`Download already in progress in this process for version ${lockKey}, waiting...`);
|
|
250033
250269
|
try {
|
|
250034
250270
|
return await lock.promise;
|
|
250035
250271
|
} catch (error2) {
|
|
@@ -250039,10 +250275,16 @@ async function withDownloadLock(version2, downloadFn) {
|
|
|
250039
250275
|
}
|
|
250040
250276
|
}
|
|
250041
250277
|
}
|
|
250278
|
+
let timeoutId = null;
|
|
250042
250279
|
const downloadPromise = Promise.race([
|
|
250043
250280
|
downloadFn(),
|
|
250044
250281
|
new Promise(
|
|
250045
|
-
(_, reject2) =>
|
|
250282
|
+
(_, reject2) => {
|
|
250283
|
+
timeoutId = setTimeout(() => reject2(new Error(`Download timeout after ${LOCK_TIMEOUT_MS / 1e3}s`)), LOCK_TIMEOUT_MS);
|
|
250284
|
+
if (timeoutId.unref) {
|
|
250285
|
+
timeoutId.unref();
|
|
250286
|
+
}
|
|
250287
|
+
}
|
|
250046
250288
|
)
|
|
250047
250289
|
]);
|
|
250048
250290
|
downloadLocks.set(lockKey, {
|
|
@@ -250053,6 +250295,9 @@ async function withDownloadLock(version2, downloadFn) {
|
|
|
250053
250295
|
const result = await downloadPromise;
|
|
250054
250296
|
return result;
|
|
250055
250297
|
} finally {
|
|
250298
|
+
if (timeoutId) {
|
|
250299
|
+
clearTimeout(timeoutId);
|
|
250300
|
+
}
|
|
250056
250301
|
downloadLocks.delete(lockKey);
|
|
250057
250302
|
}
|
|
250058
250303
|
}
|
|
@@ -285583,14 +285828,14 @@ function resolveTargetPath(target, cwd) {
|
|
|
285583
285828
|
}
|
|
285584
285829
|
return filePart + suffix;
|
|
285585
285830
|
}
|
|
285586
|
-
var import_path5, searchSchema, searchAllSchema, querySchema, extractSchema, delegateSchema, listSkillsSchema, useSkillSchema, listFilesSchema, searchFilesSchema, readImageSchema, bashSchema, analyzeAllSchema, executePlanSchema, cleanupExecutePlanSchema, attemptCompletionSchema, searchDescription, queryDescription, extractDescription, delegateDescription, bashDescription, analyzeAllDescription;
|
|
285831
|
+
var import_path5, searchSchema, searchAllSchema, querySchema, extractSchema, delegateSchema, listSkillsSchema, useSkillSchema, listFilesSchema, searchFilesSchema, readImageSchema, bashSchema, analyzeAllSchema, executePlanSchema, cleanupExecutePlanSchema, attemptCompletionSchema, searchDescription, searchDelegateDescription, queryDescription, extractDescription, delegateDescription, bashDescription, analyzeAllDescription;
|
|
285587
285832
|
var init_common2 = __esm({
|
|
285588
285833
|
"src/tools/common.js"() {
|
|
285589
285834
|
"use strict";
|
|
285590
285835
|
init_zod();
|
|
285591
285836
|
import_path5 = __nccwpck_require__(16928);
|
|
285592
285837
|
searchSchema = external_exports.object({
|
|
285593
|
-
query: external_exports.string().describe("Search query
|
|
285838
|
+
query: external_exports.string().describe("Search query \u2014 natural language questions or Elasticsearch-style keywords both work. For keywords: use quotes for exact phrases, AND/OR for boolean logic, - for negation. Probe handles stemming and camelCase/snake_case splitting automatically, so do NOT try case or style variations of the same keyword."),
|
|
285594
285839
|
path: external_exports.string().optional().default(".").describe('Path to search in. For dependencies use "go:github.com/owner/repo", "js:package_name", or "rust:cargo_name" etc.'),
|
|
285595
285840
|
exact: external_exports.boolean().optional().default(false).describe('Default (false) enables stemming and keyword splitting for exploratory search - "getUserData" matches "get", "user", "data", etc. Set true for precise symbol lookup where "getUserData" matches only "getUserData". Use true when you know the exact symbol name.'),
|
|
285596
285841
|
maxTokens: external_exports.number().nullable().optional().describe("Maximum tokens to return. Default is 20000. Set to null for unlimited results."),
|
|
@@ -285598,7 +285843,7 @@ var init_common2 = __esm({
|
|
|
285598
285843
|
nextPage: external_exports.boolean().optional().default(false).describe("Set to true when requesting the next page of results. Requires passing the same session ID from the previous search output.")
|
|
285599
285844
|
});
|
|
285600
285845
|
searchAllSchema = external_exports.object({
|
|
285601
|
-
query: external_exports.string().describe("Search query
|
|
285846
|
+
query: external_exports.string().describe("Search query \u2014 natural language questions or Elasticsearch-style keywords both work. For keywords: use quotes for exact phrases, AND/OR for boolean logic, - for negation. Probe handles stemming and camelCase/snake_case splitting automatically, so do NOT try case or style variations of the same keyword."),
|
|
285602
285847
|
path: external_exports.string().optional().default(".").describe("Path to search in."),
|
|
285603
285848
|
exact: external_exports.boolean().optional().default(false).describe("Use exact matching instead of stemming."),
|
|
285604
285849
|
maxTokensPerPage: external_exports.number().optional().default(2e4).describe("Tokens per page when paginating. Default 20000."),
|
|
@@ -285705,7 +285950,8 @@ var init_common2 = __esm({
|
|
|
285705
285950
|
};
|
|
285706
285951
|
}
|
|
285707
285952
|
};
|
|
285708
|
-
searchDescription =
|
|
285953
|
+
searchDescription = 'Search code in the repository. Free-form questions are accepted, but Elasticsearch-style keyword queries work best. Use this tool first for any code-related questions. NOTE: By default, search handles stemming, case-insensitive matching, and camelCase/snake_case splitting automatically \u2014 do NOT manually try keyword variations like "getAllUsers" then "get_all_users" then "GetAllUsers". One search covers all variations.';
|
|
285954
|
+
searchDelegateDescription = 'Search code in the repository by asking a question. Accepts natural language questions (e.g., "How does authentication work?", "Where is the user validation logic?"). A specialized subagent breaks down your question into targeted keyword searches and returns extracted code blocks. Do NOT formulate keyword queries yourself \u2014 just ask the question naturally.';
|
|
285709
285955
|
queryDescription = "Search code using ast-grep structural pattern matching. Use this tool to find specific code structures like functions, classes, or methods.";
|
|
285710
285956
|
extractDescription = "Extract code blocks from files based on file paths and optional line numbers. Use this tool to see complete context after finding relevant files. Line numbers from output can be used with edit start_line/end_line for precise editing.";
|
|
285711
285957
|
delegateDescription = "Automatically delegate big distinct tasks to specialized probe subagents within the agentic loop. Used by AI agents to break down complex requests into focused, parallel tasks.";
|
|
@@ -351025,6 +351271,7 @@ function generateSandboxGlobals(options) {
|
|
|
351025
351271
|
executing.add(p5);
|
|
351026
351272
|
results.push(p5);
|
|
351027
351273
|
if (executing.size >= mapConcurrency) {
|
|
351274
|
+
console.error(`[map] Concurrency limit reached (${executing.size}/${mapConcurrency}), waiting for a slot...`);
|
|
351028
351275
|
await Promise.race(executing);
|
|
351029
351276
|
}
|
|
351030
351277
|
}
|
|
@@ -355254,8 +355501,23 @@ __export(ProbeAgent_exports, {
|
|
|
355254
355501
|
ENGINE_ACTIVITY_TIMEOUT_DEFAULT: () => ENGINE_ACTIVITY_TIMEOUT_DEFAULT,
|
|
355255
355502
|
ENGINE_ACTIVITY_TIMEOUT_MAX: () => ENGINE_ACTIVITY_TIMEOUT_MAX,
|
|
355256
355503
|
ENGINE_ACTIVITY_TIMEOUT_MIN: () => ENGINE_ACTIVITY_TIMEOUT_MIN,
|
|
355257
|
-
ProbeAgent: () => ProbeAgent
|
|
355504
|
+
ProbeAgent: () => ProbeAgent,
|
|
355505
|
+
debugLogToolResults: () => debugLogToolResults,
|
|
355506
|
+
debugTruncate: () => debugTruncate
|
|
355258
355507
|
});
|
|
355508
|
+
function debugTruncate(s5, limit = 200) {
|
|
355509
|
+
if (s5.length <= limit) return s5;
|
|
355510
|
+
const half = Math.floor(limit / 2);
|
|
355511
|
+
return s5.substring(0, half) + ` ... [${s5.length} chars] ... ` + s5.substring(s5.length - half);
|
|
355512
|
+
}
|
|
355513
|
+
function debugLogToolResults(toolResults) {
|
|
355514
|
+
if (!toolResults || toolResults.length === 0) return;
|
|
355515
|
+
for (const tr of toolResults) {
|
|
355516
|
+
const argsStr = JSON.stringify(tr.args || {});
|
|
355517
|
+
const resultStr = typeof tr.result === "string" ? tr.result : JSON.stringify(tr.result || "");
|
|
355518
|
+
console.log(`[DEBUG] tool: ${tr.toolName} | args: ${debugTruncate(argsStr)} | result: ${debugTruncate(resultStr)}`);
|
|
355519
|
+
}
|
|
355520
|
+
}
|
|
355259
355521
|
var import_dotenv, import_anthropic2, import_openai2, import_google2, import_ai4, import_crypto8, import_events4, import_fs10, import_promises6, import_path15, ENGINE_ACTIVITY_TIMEOUT_DEFAULT, ENGINE_ACTIVITY_TIMEOUT_MIN, ENGINE_ACTIVITY_TIMEOUT_MAX, MAX_TOOL_ITERATIONS, MAX_HISTORY_MESSAGES, MAX_IMAGE_FILE_SIZE, ProbeAgent;
|
|
355260
355522
|
var init_ProbeAgent = __esm({
|
|
355261
355523
|
"src/agent/ProbeAgent.js"() {
|
|
@@ -355375,6 +355637,7 @@ var init_ProbeAgent = __esm({
|
|
|
355375
355637
|
this.enableExecutePlan = !!options.enableExecutePlan;
|
|
355376
355638
|
this.debug = options.debug || process.env.DEBUG === "1";
|
|
355377
355639
|
this.cancelled = false;
|
|
355640
|
+
this._abortController = new AbortController();
|
|
355378
355641
|
this.tracer = options.tracer || null;
|
|
355379
355642
|
this.outline = !!options.outline;
|
|
355380
355643
|
this.searchDelegate = options.searchDelegate !== void 0 ? !!options.searchDelegate : true;
|
|
@@ -355403,6 +355666,7 @@ var init_ProbeAgent = __esm({
|
|
|
355403
355666
|
this.completionPrompt = options.completionPrompt || null;
|
|
355404
355667
|
this.thinkingEffort = options.thinkingEffort || null;
|
|
355405
355668
|
const effectiveAllowedTools = options.disableTools ? [] : options.allowedTools;
|
|
355669
|
+
this._rawAllowedTools = options.allowedTools;
|
|
355406
355670
|
this.allowedTools = this._parseAllowedTools(effectiveAllowedTools);
|
|
355407
355671
|
this.storageAdapter = options.storageAdapter || new InMemoryStorageAdapter();
|
|
355408
355672
|
this.hooks = new HookManager();
|
|
@@ -355545,6 +355809,16 @@ var init_ProbeAgent = __esm({
|
|
|
355545
355809
|
_filterMcpTools(mcpToolNames) {
|
|
355546
355810
|
return mcpToolNames.filter((toolName) => this._isMcpToolAllowed(toolName));
|
|
355547
355811
|
}
|
|
355812
|
+
/**
|
|
355813
|
+
* Check if query tool was explicitly listed in allowedTools (not via wildcard).
|
|
355814
|
+
* Query (ast-grep) is excluded by default because models struggle with AST pattern syntax.
|
|
355815
|
+
* @returns {boolean}
|
|
355816
|
+
* @private
|
|
355817
|
+
*/
|
|
355818
|
+
_isQueryExplicitlyAllowed() {
|
|
355819
|
+
if (!this._rawAllowedTools) return false;
|
|
355820
|
+
return Array.isArray(this._rawAllowedTools) && this._rawAllowedTools.includes("query");
|
|
355821
|
+
}
|
|
355548
355822
|
/**
|
|
355549
355823
|
* Check if tracer is AppTracer (expects sessionId as first param) vs SimpleAppTracer
|
|
355550
355824
|
* @returns {boolean} - True if tracer is AppTracer style (requires sessionId)
|
|
@@ -355820,6 +356094,8 @@ var init_ProbeAgent = __esm({
|
|
|
355820
356094
|
searchDelegateModel: this.searchDelegateModel,
|
|
355821
356095
|
delegationManager: this.delegationManager,
|
|
355822
356096
|
// Per-instance delegation limits
|
|
356097
|
+
parentAbortSignal: this._abortController.signal,
|
|
356098
|
+
// Propagate cancellation to delegations
|
|
355823
356099
|
outputBuffer: this._outputBuffer,
|
|
355824
356100
|
concurrencyLimiter: this.concurrencyLimiter,
|
|
355825
356101
|
// Global AI concurrency limiter
|
|
@@ -355836,7 +356112,7 @@ var init_ProbeAgent = __esm({
|
|
|
355836
356112
|
if (wrappedTools.searchToolInstance && isToolAllowed("search")) {
|
|
355837
356113
|
this.toolImplementations.search = wrappedTools.searchToolInstance;
|
|
355838
356114
|
}
|
|
355839
|
-
if (wrappedTools.queryToolInstance && isToolAllowed("query")) {
|
|
356115
|
+
if (wrappedTools.queryToolInstance && isToolAllowed("query") && this._isQueryExplicitlyAllowed()) {
|
|
355840
356116
|
this.toolImplementations.query = wrappedTools.queryToolInstance;
|
|
355841
356117
|
}
|
|
355842
356118
|
if (wrappedTools.extractToolInstance && isToolAllowed("extract")) {
|
|
@@ -356267,6 +356543,15 @@ var init_ProbeAgent = __esm({
|
|
|
356267
356543
|
}
|
|
356268
356544
|
const controller = new AbortController();
|
|
356269
356545
|
const timeoutState = { timeoutId: null };
|
|
356546
|
+
if (this._abortController.signal.aborted) {
|
|
356547
|
+
controller.abort();
|
|
356548
|
+
} else {
|
|
356549
|
+
const onAgentAbort = () => controller.abort();
|
|
356550
|
+
this._abortController.signal.addEventListener("abort", onAgentAbort, { once: true });
|
|
356551
|
+
controller.signal.addEventListener("abort", () => {
|
|
356552
|
+
this._abortController.signal.removeEventListener("abort", onAgentAbort);
|
|
356553
|
+
}, { once: true });
|
|
356554
|
+
}
|
|
356270
356555
|
if (this.maxOperationTimeout && this.maxOperationTimeout > 0) {
|
|
356271
356556
|
timeoutState.timeoutId = setTimeout(() => {
|
|
356272
356557
|
controller.abort();
|
|
@@ -356570,7 +356855,8 @@ var init_ProbeAgent = __esm({
|
|
|
356570
356855
|
allowEdit: this.allowEdit,
|
|
356571
356856
|
allowedTools: allowedToolsForDelegate,
|
|
356572
356857
|
debug: this.debug,
|
|
356573
|
-
tracer: this.tracer
|
|
356858
|
+
tracer: this.tracer,
|
|
356859
|
+
parentAbortSignal: this._abortController.signal
|
|
356574
356860
|
};
|
|
356575
356861
|
if (this.debug) {
|
|
356576
356862
|
console.log(`[DEBUG] Executing delegate tool`);
|
|
@@ -356765,12 +357051,13 @@ var init_ProbeAgent = __esm({
|
|
|
356765
357051
|
const toolMap = {
|
|
356766
357052
|
search: {
|
|
356767
357053
|
schema: searchSchema,
|
|
356768
|
-
description: "Search code in the repository using keyword queries with Elasticsearch syntax."
|
|
356769
|
-
},
|
|
356770
|
-
query: {
|
|
356771
|
-
schema: querySchema,
|
|
356772
|
-
description: "Search code using ast-grep structural pattern matching."
|
|
357054
|
+
description: this.searchDelegate ? "Search code in the repository by asking a question. Accepts natural language questions \u2014 a subagent breaks them into targeted keyword searches and returns extracted code blocks. Do NOT formulate keyword queries yourself." : "Search code in the repository using keyword queries with Elasticsearch syntax. Handles stemming, case-insensitive matching, and camelCase/snake_case splitting automatically \u2014 do NOT try keyword variations manually."
|
|
356773
357055
|
},
|
|
357056
|
+
// query tool (ast-grep) removed from AI-facing tools — models struggle with pattern syntax
|
|
357057
|
+
// query: {
|
|
357058
|
+
// schema: querySchema,
|
|
357059
|
+
// description: 'Search code using ast-grep structural pattern matching.'
|
|
357060
|
+
// },
|
|
356774
357061
|
extract: {
|
|
356775
357062
|
schema: extractSchema,
|
|
356776
357063
|
description: "Extract code blocks from files based on file paths and optional line numbers."
|
|
@@ -357438,25 +357725,27 @@ ${this.architectureContext.content}
|
|
|
357438
357725
|
} else {
|
|
357439
357726
|
systemPrompt += predefinedPrompts["code-explorer"] + "\n\n";
|
|
357440
357727
|
}
|
|
357728
|
+
const searchToolDesc1 = this.searchDelegate ? '- search: Ask natural language questions to find code (e.g., "How does authentication work?"). A subagent handles keyword searches and returns extracted code blocks. Do NOT formulate keyword queries \u2014 just ask questions.' : "- search: Find code patterns using keyword queries with Elasticsearch syntax. Handles stemming and case variations automatically \u2014 do NOT try manual keyword variations.";
|
|
357441
357729
|
systemPrompt += `You have access to powerful code search and analysis tools through MCP:
|
|
357442
|
-
|
|
357730
|
+
${searchToolDesc1}
|
|
357443
357731
|
- extract: Extract specific code sections with context
|
|
357444
|
-
- query: Use AST patterns for structural code matching
|
|
357445
357732
|
- listFiles: Browse directory contents
|
|
357446
357733
|
- searchFiles: Find files by name patterns`;
|
|
357447
357734
|
if (this.enableBash) {
|
|
357448
357735
|
systemPrompt += `
|
|
357449
357736
|
- bash: Execute bash commands for system operations`;
|
|
357450
357737
|
}
|
|
357451
|
-
const
|
|
357452
|
-
const
|
|
357738
|
+
const searchGuidance1 = this.searchDelegate ? "1. Start with search \u2014 ask a question about what you want to understand. It returns extracted code blocks directly." : "1. Start with search to find relevant code patterns. One search per concept is usually enough \u2014 probe handles stemming and case variations.";
|
|
357739
|
+
const extractGuidance1 = this.searchDelegate ? "2. Use extract only if you need more context or a full file" : "2. Use extract to get detailed context when needed";
|
|
357453
357740
|
systemPrompt += `
|
|
357454
357741
|
|
|
357455
357742
|
When exploring code:
|
|
357456
|
-
${
|
|
357457
|
-
${
|
|
357743
|
+
${searchGuidance1}
|
|
357744
|
+
${extractGuidance1}
|
|
357458
357745
|
3. Prefer focused, specific searches over broad queries
|
|
357459
|
-
4.
|
|
357746
|
+
4. Do NOT repeat the same search or try trivial keyword variations \u2014 probe handles stemming and case variations automatically
|
|
357747
|
+
5. If 2-3 consecutive searches return no results for a concept, stop searching for it \u2014 the term likely does not exist in that codebase
|
|
357748
|
+
6. Combine multiple tools to build complete understanding`;
|
|
357460
357749
|
if (this.allowedFolders && this.allowedFolders.length > 0) {
|
|
357461
357750
|
systemPrompt += `
|
|
357462
357751
|
|
|
@@ -357491,25 +357780,27 @@ Workspace: ${this.allowedFolders.join(", ")}`;
|
|
|
357491
357780
|
} else {
|
|
357492
357781
|
systemPrompt += predefinedPrompts["code-explorer"] + "\n\n";
|
|
357493
357782
|
}
|
|
357783
|
+
const searchToolDesc2 = this.searchDelegate ? '- search: Ask natural language questions to find code (e.g., "How does authentication work?"). A subagent handles keyword searches and returns extracted code blocks. Do NOT formulate keyword queries \u2014 just ask questions.' : "- search: Find code patterns using keyword queries with Elasticsearch syntax. Handles stemming and case variations automatically \u2014 do NOT try manual keyword variations.";
|
|
357494
357784
|
systemPrompt += `You have access to powerful code search and analysis tools through MCP:
|
|
357495
|
-
|
|
357785
|
+
${searchToolDesc2}
|
|
357496
357786
|
- extract: Extract specific code sections with context
|
|
357497
|
-
- query: Use AST patterns for structural code matching
|
|
357498
357787
|
- listFiles: Browse directory contents
|
|
357499
357788
|
- searchFiles: Find files by name patterns`;
|
|
357500
357789
|
if (this.enableBash) {
|
|
357501
357790
|
systemPrompt += `
|
|
357502
357791
|
- bash: Execute bash commands for system operations`;
|
|
357503
357792
|
}
|
|
357504
|
-
const
|
|
357505
|
-
const
|
|
357793
|
+
const searchGuidance2 = this.searchDelegate ? "1. Start with search \u2014 ask a question about what you want to understand. It returns extracted code blocks directly." : "1. Start with search to find relevant code patterns. One search per concept is usually enough \u2014 probe handles stemming and case variations.";
|
|
357794
|
+
const extractGuidance2 = this.searchDelegate ? "2. Use extract only if you need more context or a full file" : "2. Use extract to get detailed context when needed";
|
|
357506
357795
|
systemPrompt += `
|
|
357507
357796
|
|
|
357508
357797
|
When exploring code:
|
|
357509
|
-
${
|
|
357510
|
-
${
|
|
357798
|
+
${searchGuidance2}
|
|
357799
|
+
${extractGuidance2}
|
|
357511
357800
|
3. Prefer focused, specific searches over broad queries
|
|
357512
|
-
4.
|
|
357801
|
+
4. Do NOT repeat the same search or try trivial keyword variations \u2014 probe handles stemming and case variations automatically
|
|
357802
|
+
5. If 2-3 consecutive searches return no results for a concept, stop searching for it \u2014 the term likely does not exist in that codebase
|
|
357803
|
+
6. Combine multiple tools to build complete understanding`;
|
|
357513
357804
|
if (this.allowedFolders && this.allowedFolders.length > 0) {
|
|
357514
357805
|
systemPrompt += `
|
|
357515
357806
|
|
|
@@ -357560,10 +357851,10 @@ Workspace: ${this.allowedFolders.join(", ")}`;
|
|
|
357560
357851
|
Follow these instructions carefully:
|
|
357561
357852
|
1. Analyze the user's request.
|
|
357562
357853
|
2. Use the available tools step-by-step to fulfill the request.
|
|
357563
|
-
3. You should always prefer the search tool for code-related questions.${this.searchDelegate ? "
|
|
357854
|
+
3. You should always prefer the search tool for code-related questions.${this.searchDelegate ? " Ask natural language questions \u2014 the search subagent handles keyword formulation and returns extracted code blocks. Use extract only to expand context or read full files." : " Search handles stemming and case variations automatically \u2014 do NOT try keyword variations manually. Read full files only if really necessary."}
|
|
357564
357855
|
4. Ensure to get really deep and understand the full picture before answering.
|
|
357565
357856
|
5. Once the task is fully completed, use the attempt_completion tool to provide the final result.
|
|
357566
|
-
6. Prefer concise and focused search queries. Use specific keywords and phrases to narrow down results
|
|
357857
|
+
6. ${this.searchDelegate ? "Ask clear, specific questions when searching. Each search should target a distinct concept or question." : "Prefer concise and focused search queries. Use specific keywords and phrases to narrow down results."}${this.allowEdit ? `
|
|
357567
357858
|
7. When modifying files, choose the appropriate tool:
|
|
357568
357859
|
- Use 'edit' for all code modifications:
|
|
357569
357860
|
* PREFERRED: Use start_line (and optionally end_line) for line-targeted editing \u2014 this is the safest and most precise approach.${this.hashLines ? ' Use the line:hash references from extract/search output (e.g. "42:ab") for integrity verification.' : ""} Always use extract first to see line numbers${this.hashLines ? " and hashes" : ""}, then edit by line reference.
|
|
@@ -357887,6 +358178,10 @@ You are working with a workspace. Available paths: ${workspaceDesc}
|
|
|
357887
358178
|
completionResult = result;
|
|
357888
358179
|
completionAttempted = true;
|
|
357889
358180
|
}, toolContext);
|
|
358181
|
+
if (this.debug) {
|
|
358182
|
+
const toolNames = Object.keys(tools2);
|
|
358183
|
+
console.log(`[DEBUG] Agent tools registered (${toolNames.length}): ${toolNames.join(", ")}`);
|
|
358184
|
+
}
|
|
357890
358185
|
let maxResponseTokens = this.maxResponseTokens;
|
|
357891
358186
|
if (!maxResponseTokens) {
|
|
357892
358187
|
maxResponseTokens = 4e3;
|
|
@@ -357926,6 +358221,7 @@ You are working with a workspace. Available paths: ${workspaceDesc}
|
|
|
357926
358221
|
}
|
|
357927
358222
|
if (this.debug) {
|
|
357928
358223
|
console.log(`[DEBUG] Step ${currentIteration}/${maxIterations} finished (reason: ${finishReason}, tools: ${toolResults?.length || 0})`);
|
|
358224
|
+
debugLogToolResults(toolResults);
|
|
357929
358225
|
}
|
|
357930
358226
|
}
|
|
357931
358227
|
};
|
|
@@ -358082,6 +358378,7 @@ Double-check your response based on the criteria above. If everything looks good
|
|
|
358082
358378
|
}
|
|
358083
358379
|
if (this.debug) {
|
|
358084
358380
|
console.log(`[DEBUG] Completion prompt step finished (reason: ${finishReason}, tools: ${toolResults?.length || 0})`);
|
|
358381
|
+
debugLogToolResults(toolResults);
|
|
358085
358382
|
}
|
|
358086
358383
|
}
|
|
358087
358384
|
};
|
|
@@ -358792,6 +359089,9 @@ Convert your previous response content into actual JSON data that follows this s
|
|
|
358792
359089
|
* Clean up resources (including MCP connections)
|
|
358793
359090
|
*/
|
|
358794
359091
|
async cleanup() {
|
|
359092
|
+
if (!this._abortController.signal.aborted) {
|
|
359093
|
+
this._abortController.abort();
|
|
359094
|
+
}
|
|
358795
359095
|
if (this.mcpBridge) {
|
|
358796
359096
|
try {
|
|
358797
359097
|
await this.mcpBridge.cleanup();
|
|
@@ -358815,14 +359115,25 @@ Convert your previous response content into actual JSON data that follows this s
|
|
|
358815
359115
|
this.clearHistory();
|
|
358816
359116
|
}
|
|
358817
359117
|
/**
|
|
358818
|
-
* Cancel the current request
|
|
359118
|
+
* Cancel the current request and all in-flight delegations.
|
|
359119
|
+
* Aborts the internal AbortController so streamText, subagents,
|
|
359120
|
+
* and any code checking the signal will stop.
|
|
358819
359121
|
*/
|
|
358820
359122
|
cancel() {
|
|
358821
359123
|
this.cancelled = true;
|
|
359124
|
+
this._abortController.abort();
|
|
358822
359125
|
if (this.debug) {
|
|
358823
359126
|
console.log(`[DEBUG] Agent cancelled for session ${this.sessionId}`);
|
|
358824
359127
|
}
|
|
358825
359128
|
}
|
|
359129
|
+
/**
|
|
359130
|
+
* Get the abort signal for this agent.
|
|
359131
|
+
* Delegations and subagents should check this signal.
|
|
359132
|
+
* @returns {AbortSignal}
|
|
359133
|
+
*/
|
|
359134
|
+
get abortSignal() {
|
|
359135
|
+
return this._abortController.signal;
|
|
359136
|
+
}
|
|
358826
359137
|
};
|
|
358827
359138
|
}
|
|
358828
359139
|
});
|
|
@@ -358855,12 +359166,17 @@ async function delegate({
|
|
|
358855
359166
|
mcpConfigPath = null,
|
|
358856
359167
|
delegationManager = null,
|
|
358857
359168
|
// Optional per-instance manager, falls back to default singleton
|
|
358858
|
-
concurrencyLimiter = null
|
|
359169
|
+
concurrencyLimiter = null,
|
|
358859
359170
|
// Optional global AI concurrency limiter
|
|
359171
|
+
parentAbortSignal = null
|
|
359172
|
+
// Optional AbortSignal from parent to cancel this delegation
|
|
358860
359173
|
}) {
|
|
358861
359174
|
if (!task || typeof task !== "string") {
|
|
358862
359175
|
throw new Error("Task parameter is required and must be a string");
|
|
358863
359176
|
}
|
|
359177
|
+
if (parentAbortSignal?.aborted) {
|
|
359178
|
+
throw new Error("Delegation cancelled: parent operation was aborted");
|
|
359179
|
+
}
|
|
358864
359180
|
const hasExplicitTimeout = Object.prototype.hasOwnProperty.call(arguments?.[0] ?? {}, "timeout");
|
|
358865
359181
|
if (!hasExplicitTimeout) {
|
|
358866
359182
|
const envTimeoutMs = parseInt(process.env.DELEGATION_TIMEOUT_MS || "", 10);
|
|
@@ -358945,12 +359261,37 @@ async function delegate({
|
|
|
358945
359261
|
}
|
|
358946
359262
|
const timeoutPromise = new Promise((_, reject2) => {
|
|
358947
359263
|
timeoutId = setTimeout(() => {
|
|
359264
|
+
subagent.cancel();
|
|
358948
359265
|
reject2(new Error(`Delegation timed out after ${timeout} seconds`));
|
|
358949
359266
|
}, timeout * 1e3);
|
|
358950
359267
|
});
|
|
359268
|
+
let parentAbortHandler;
|
|
359269
|
+
const parentAbortPromise = new Promise((_, reject2) => {
|
|
359270
|
+
if (parentAbortSignal) {
|
|
359271
|
+
if (parentAbortSignal.aborted) {
|
|
359272
|
+
subagent.cancel();
|
|
359273
|
+
reject2(new Error("Delegation cancelled: parent operation was aborted"));
|
|
359274
|
+
return;
|
|
359275
|
+
}
|
|
359276
|
+
parentAbortHandler = () => {
|
|
359277
|
+
subagent.cancel();
|
|
359278
|
+
reject2(new Error("Delegation cancelled: parent operation was aborted"));
|
|
359279
|
+
};
|
|
359280
|
+
parentAbortSignal.addEventListener("abort", parentAbortHandler, { once: true });
|
|
359281
|
+
}
|
|
359282
|
+
});
|
|
358951
359283
|
const answerOptions = schema ? { schema } : void 0;
|
|
358952
359284
|
const answerPromise = answerOptions ? subagent.answer(task, [], answerOptions) : subagent.answer(task);
|
|
358953
|
-
const
|
|
359285
|
+
const racers = [answerPromise, timeoutPromise];
|
|
359286
|
+
if (parentAbortSignal) racers.push(parentAbortPromise);
|
|
359287
|
+
let response;
|
|
359288
|
+
try {
|
|
359289
|
+
response = await Promise.race(racers);
|
|
359290
|
+
} finally {
|
|
359291
|
+
if (parentAbortHandler && parentAbortSignal) {
|
|
359292
|
+
parentAbortSignal.removeEventListener("abort", parentAbortHandler);
|
|
359293
|
+
}
|
|
359294
|
+
}
|
|
358954
359295
|
if (timeoutId !== null) {
|
|
358955
359296
|
clearTimeout(timeoutId);
|
|
358956
359297
|
timeoutId = null;
|
|
@@ -359106,10 +359447,9 @@ var init_delegate = __esm({
|
|
|
359106
359447
|
if (this.tryAcquire(parentSessionId)) {
|
|
359107
359448
|
return true;
|
|
359108
359449
|
}
|
|
359109
|
-
|
|
359110
|
-
console.error(`[DelegationManager] Slot unavailable (${this.globalActive}/${this.maxConcurrent}), queuing... (queue size: ${this.waitQueue.length}, timeout: ${effectiveTimeout}ms)`);
|
|
359111
|
-
}
|
|
359450
|
+
console.error(`[DelegationManager] Slot unavailable (${this.globalActive}/${this.maxConcurrent}), queuing... (queue size: ${this.waitQueue.length + 1}, timeout: ${effectiveTimeout}ms)`);
|
|
359112
359451
|
return new Promise((resolve8, reject2) => {
|
|
359452
|
+
const queuedAt = Date.now();
|
|
359113
359453
|
const entry = {
|
|
359114
359454
|
resolve: null,
|
|
359115
359455
|
// Will be wrapped below
|
|
@@ -359117,20 +359457,23 @@ var init_delegate = __esm({
|
|
|
359117
359457
|
// Will be wrapped below
|
|
359118
359458
|
parentSessionId,
|
|
359119
359459
|
debug,
|
|
359120
|
-
queuedAt
|
|
359121
|
-
timeoutId: null
|
|
359460
|
+
queuedAt,
|
|
359461
|
+
timeoutId: null,
|
|
359462
|
+
reminderId: null
|
|
359122
359463
|
};
|
|
359123
359464
|
let settled = false;
|
|
359124
359465
|
entry.resolve = (value) => {
|
|
359125
359466
|
if (settled) return;
|
|
359126
359467
|
settled = true;
|
|
359127
359468
|
if (entry.timeoutId) clearTimeout(entry.timeoutId);
|
|
359469
|
+
if (entry.reminderId) clearInterval(entry.reminderId);
|
|
359128
359470
|
resolve8(value);
|
|
359129
359471
|
};
|
|
359130
359472
|
entry.reject = (error2) => {
|
|
359131
359473
|
if (settled) return;
|
|
359132
359474
|
settled = true;
|
|
359133
359475
|
if (entry.timeoutId) clearTimeout(entry.timeoutId);
|
|
359476
|
+
if (entry.reminderId) clearInterval(entry.reminderId);
|
|
359134
359477
|
reject2(error2);
|
|
359135
359478
|
};
|
|
359136
359479
|
if (effectiveTimeout > 0) {
|
|
@@ -359142,6 +359485,13 @@ var init_delegate = __esm({
|
|
|
359142
359485
|
entry.reject(new Error(`Delegation queue timeout: waited ${effectiveTimeout}ms for an available slot`));
|
|
359143
359486
|
}, effectiveTimeout);
|
|
359144
359487
|
}
|
|
359488
|
+
entry.reminderId = setInterval(() => {
|
|
359489
|
+
const waitedSeconds = Math.round((Date.now() - queuedAt) / 1e3);
|
|
359490
|
+
console.error(`[DelegationManager] Still waiting for slot (${waitedSeconds}s). ${this.globalActive}/${this.maxConcurrent} active, ${this.waitQueue.length} queued.`);
|
|
359491
|
+
}, 15e3);
|
|
359492
|
+
if (entry.reminderId.unref) {
|
|
359493
|
+
entry.reminderId.unref();
|
|
359494
|
+
}
|
|
359145
359495
|
this.waitQueue.push(entry);
|
|
359146
359496
|
});
|
|
359147
359497
|
}
|
|
@@ -359180,18 +359530,14 @@ var init_delegate = __esm({
|
|
|
359180
359530
|
const sessionData = this.sessionDelegations.get(parentSessionId);
|
|
359181
359531
|
const sessionCount = sessionData?.count || 0;
|
|
359182
359532
|
if (sessionCount >= this.maxPerSession) {
|
|
359183
|
-
|
|
359184
|
-
console.error(`[DelegationManager] Session limit (${this.maxPerSession}) reached for queued item, rejecting`);
|
|
359185
|
-
}
|
|
359533
|
+
console.error(`[DelegationManager] Session limit (${this.maxPerSession}) reached for queued item, rejecting`);
|
|
359186
359534
|
toReject.push({ reject: reject2, error: new Error(`Maximum delegations per session (${this.maxPerSession}) reached for session ${parentSessionId}`) });
|
|
359187
359535
|
continue;
|
|
359188
359536
|
}
|
|
359189
359537
|
}
|
|
359190
359538
|
this._incrementCounters(parentSessionId);
|
|
359191
|
-
|
|
359192
|
-
|
|
359193
|
-
console.error(`[DelegationManager] Granted slot from queue (waited ${waitTime}ms). Active: ${this.globalActive}/${this.maxConcurrent}`);
|
|
359194
|
-
}
|
|
359539
|
+
const waitTime = Date.now() - queuedAt;
|
|
359540
|
+
console.error(`[DelegationManager] Granted slot from queue (waited ${waitTime}ms). Active: ${this.globalActive}/${this.maxConcurrent}`);
|
|
359195
359541
|
toResolve.push(resolve8);
|
|
359196
359542
|
}
|
|
359197
359543
|
if (toResolve.length > 0 || toReject.length > 0) {
|
|
@@ -359241,6 +359587,9 @@ var init_delegate = __esm({
|
|
|
359241
359587
|
if (entry.timeoutId) {
|
|
359242
359588
|
clearTimeout(entry.timeoutId);
|
|
359243
359589
|
}
|
|
359590
|
+
if (entry.reminderId) {
|
|
359591
|
+
clearInterval(entry.reminderId);
|
|
359592
|
+
}
|
|
359244
359593
|
if (entry.reject) {
|
|
359245
359594
|
entry.reject(new Error("DelegationManager was cleaned up"));
|
|
359246
359595
|
}
|
|
@@ -359363,8 +359712,9 @@ Instructions:
|
|
|
359363
359712
|
promptType: "code-researcher",
|
|
359364
359713
|
allowedTools: ["extract"],
|
|
359365
359714
|
maxIterations: 5,
|
|
359366
|
-
delegationManager: options.delegationManager
|
|
359715
|
+
delegationManager: options.delegationManager,
|
|
359367
359716
|
// Per-instance delegation limits
|
|
359717
|
+
parentAbortSignal: options.parentAbortSignal || null
|
|
359368
359718
|
// timeout removed - inherit default from delegate (300s)
|
|
359369
359719
|
});
|
|
359370
359720
|
return { chunk, result };
|
|
@@ -359384,16 +359734,12 @@ async function processChunksParallel(chunks, extractionPrompt, maxWorkers, optio
|
|
|
359384
359734
|
return result;
|
|
359385
359735
|
});
|
|
359386
359736
|
active.add(promise);
|
|
359387
|
-
|
|
359388
|
-
console.error(`[analyze_all] Started processing chunk ${chunk.id}/${chunk.total}`);
|
|
359389
|
-
}
|
|
359737
|
+
console.error(`[analyze_all] Started processing chunk ${chunk.id}/${chunk.total}`);
|
|
359390
359738
|
}
|
|
359391
359739
|
if (active.size > 0) {
|
|
359392
359740
|
const result = await Promise.race(active);
|
|
359393
359741
|
results.push(result);
|
|
359394
|
-
|
|
359395
|
-
console.error(`[analyze_all] Completed chunk ${result.chunk.id}/${result.chunk.total}`);
|
|
359396
|
-
}
|
|
359742
|
+
console.error(`[analyze_all] Completed chunk ${result.chunk.id}/${result.chunk.total}`);
|
|
359397
359743
|
}
|
|
359398
359744
|
}
|
|
359399
359745
|
results.sort((a5, b5) => a5.chunk.id - b5.chunk.id);
|
|
@@ -359463,8 +359809,9 @@ Organize all findings into clear categories with items listed under each.${compl
|
|
|
359463
359809
|
promptType: "code-researcher",
|
|
359464
359810
|
allowedTools: [],
|
|
359465
359811
|
maxIterations: 5,
|
|
359466
|
-
delegationManager: options.delegationManager
|
|
359812
|
+
delegationManager: options.delegationManager,
|
|
359467
359813
|
// Per-instance delegation limits
|
|
359814
|
+
parentAbortSignal: options.parentAbortSignal || null
|
|
359468
359815
|
// timeout removed - inherit default from delegate (300s)
|
|
359469
359816
|
});
|
|
359470
359817
|
return result;
|
|
@@ -359528,8 +359875,9 @@ CRITICAL: Do NOT guess keywords. Actually run searches and see what returns resu
|
|
|
359528
359875
|
promptType: "code-researcher",
|
|
359529
359876
|
// Full tool access for exploration and experimentation
|
|
359530
359877
|
maxIterations: 15,
|
|
359531
|
-
delegationManager: options.delegationManager
|
|
359878
|
+
delegationManager: options.delegationManager,
|
|
359532
359879
|
// Per-instance delegation limits
|
|
359880
|
+
parentAbortSignal: options.parentAbortSignal || null
|
|
359533
359881
|
// timeout removed - inherit default from delegate (300s)
|
|
359534
359882
|
});
|
|
359535
359883
|
const plan = parsePlanningResult(stripResultTags(result));
|
|
@@ -359586,8 +359934,9 @@ When done, use the attempt_completion tool with your answer as the result.`;
|
|
|
359586
359934
|
promptType: "code-researcher",
|
|
359587
359935
|
allowedTools: [],
|
|
359588
359936
|
maxIterations: 5,
|
|
359589
|
-
delegationManager: options.delegationManager
|
|
359937
|
+
delegationManager: options.delegationManager,
|
|
359590
359938
|
// Per-instance delegation limits
|
|
359939
|
+
parentAbortSignal: options.parentAbortSignal || null
|
|
359591
359940
|
// timeout removed - inherit default from delegate (300s)
|
|
359592
359941
|
});
|
|
359593
359942
|
return stripResultTags(result);
|
|
@@ -359900,11 +360249,41 @@ function buildSearchDelegateTask({ searchQuery, searchPath, exact, language, all
|
|
|
359900
360249
|
"- extract: Verify code snippets to ensure targets are actually relevant before including them.",
|
|
359901
360250
|
"- listFiles: Understand directory structure to find where relevant code might live.",
|
|
359902
360251
|
"",
|
|
359903
|
-
"
|
|
360252
|
+
"CRITICAL - How probe search works (do NOT ignore):",
|
|
360253
|
+
"- By default (exact=false), probe ALREADY handles stemming, case-insensitive matching, and camelCase/snake_case splitting.",
|
|
360254
|
+
'- Searching "allowed_ips" ALREADY matches "AllowedIPs", "allowedIps", "allowed_ips", etc. Do NOT manually try case/style variations.',
|
|
360255
|
+
'- Searching "getUserData" ALREADY matches "get", "user", "data" and their variations.',
|
|
360256
|
+
"- NEVER repeat the same search query \u2014 you will get the same results.",
|
|
360257
|
+
"- NEVER search trivial variations of the same keyword (e.g., AllowedIPs then allowedIps then allowed_ips). This is wasteful \u2014 probe handles it.",
|
|
360258
|
+
"- If a search returns no results, the term likely does not exist in that path. Try a genuinely DIFFERENT keyword or concept, not a variation.",
|
|
360259
|
+
"- If 2-3 consecutive searches return no results for a concept, STOP searching for it and move on.",
|
|
360260
|
+
"",
|
|
360261
|
+
"GOOD search strategy (do this):",
|
|
360262
|
+
' Query: "How does authentication work and how are sessions managed?"',
|
|
360263
|
+
' \u2192 search "authentication" \u2192 search "session management" (two different concepts)',
|
|
360264
|
+
' Query: "Find the IP allowlist middleware"',
|
|
360265
|
+
' \u2192 search "allowlist middleware" (one search, probe handles IP/ip/Ip variations)',
|
|
360266
|
+
' Query: "How does BM25 scoring work with SIMD optimization?"',
|
|
360267
|
+
' \u2192 search "BM25 scoring" \u2192 search "SIMD optimization" (two different concepts)',
|
|
360268
|
+
"",
|
|
360269
|
+
"BAD search strategy (never do this):",
|
|
360270
|
+
' \u2192 search "AllowedIPs" \u2192 search "allowedIps" \u2192 search "allowed_ips" (WRONG: these are trivial case variations, probe handles them)',
|
|
360271
|
+
' \u2192 search "CIDR" \u2192 search "cidr" \u2192 search "Cidr" \u2192 search "*cidr*" (WRONG: same keyword repeated with variations)',
|
|
360272
|
+
' \u2192 search "error handling" \u2192 search "error handling" \u2192 search "error handling" (WRONG: repeating exact same query)',
|
|
360273
|
+
"",
|
|
360274
|
+
"Keyword tips:",
|
|
360275
|
+
"- Common programming keywords are filtered as stopwords when unquoted: function, class, return, new, struct, impl, var, let, const, etc.",
|
|
360276
|
+
'- Avoid searching for these alone \u2014 combine with a specific term (e.g., "middleware function" is fine, "function" alone is too generic).',
|
|
360277
|
+
'- To bypass stopword filtering: wrap terms in quotes ("return", "struct") or set exact=true. Both disable stemming and splitting too.',
|
|
360278
|
+
"- Multiple words without operators use OR logic: foo bar = foo OR bar. Use AND explicitly if you need both: foo AND bar.",
|
|
360279
|
+
'- camelCase terms are split: getUserData becomes "get", "user", "data" \u2014 so one search covers all naming styles.',
|
|
360280
|
+
"",
|
|
360281
|
+
"Strategy:",
|
|
359904
360282
|
"1. Analyze the query - identify key concepts, entities, and relationships",
|
|
359905
|
-
|
|
359906
|
-
"3.
|
|
359907
|
-
"4.
|
|
360283
|
+
"2. Run ONE focused search per concept with the most natural keyword. Trust probe to handle variations.",
|
|
360284
|
+
"3. If a search returns results, use extract to verify relevance",
|
|
360285
|
+
"4. Only try a different keyword if the first one returned irrelevant results (not if it returned no results \u2014 that means the concept is absent)",
|
|
360286
|
+
"5. Combine all relevant targets in your final response",
|
|
359908
360287
|
"",
|
|
359909
360288
|
`Query: ${searchQuery}`,
|
|
359910
360289
|
`Search path(s): ${searchPath}`,
|
|
@@ -359957,9 +360336,12 @@ var init_vercel = __esm({
|
|
|
359957
360336
|
}
|
|
359958
360337
|
return result;
|
|
359959
360338
|
};
|
|
360339
|
+
const previousSearches = /* @__PURE__ */ new Set();
|
|
360340
|
+
const paginationCounts = /* @__PURE__ */ new Map();
|
|
360341
|
+
const MAX_PAGES_PER_QUERY = 3;
|
|
359960
360342
|
return (0, import_ai5.tool)({
|
|
359961
360343
|
name: "search",
|
|
359962
|
-
description: searchDelegate ?
|
|
360344
|
+
description: searchDelegate ? searchDelegateDescription : searchDescription,
|
|
359963
360345
|
inputSchema: searchSchema,
|
|
359964
360346
|
execute: async ({ query: searchQuery, path: path9, allow_tests, exact, maxTokens: paramMaxTokens, language, session, nextPage }) => {
|
|
359965
360347
|
const effectiveMaxTokens = paramMaxTokens || maxTokens;
|
|
@@ -359997,6 +360379,26 @@ var init_vercel = __esm({
|
|
|
359997
360379
|
return await search(searchOptions);
|
|
359998
360380
|
};
|
|
359999
360381
|
if (!searchDelegate) {
|
|
360382
|
+
const searchKey = `${searchQuery}::${searchPath}::${exact || false}`;
|
|
360383
|
+
if (!nextPage) {
|
|
360384
|
+
if (previousSearches.has(searchKey)) {
|
|
360385
|
+
if (debug) {
|
|
360386
|
+
console.error(`[DEDUP] Blocked duplicate search: "${searchQuery}" in "${searchPath}"`);
|
|
360387
|
+
}
|
|
360388
|
+
return "DUPLICATE SEARCH BLOCKED: You already searched for this exact query in this path. Do NOT repeat the same search. If you need more results, set nextPage=true with the session ID from the previous search. Otherwise, try a genuinely different keyword, use extract to examine results you already found, or use attempt_completion if you have enough information.";
|
|
360389
|
+
}
|
|
360390
|
+
previousSearches.add(searchKey);
|
|
360391
|
+
paginationCounts.set(searchKey, 0);
|
|
360392
|
+
} else {
|
|
360393
|
+
const pageCount = (paginationCounts.get(searchKey) || 0) + 1;
|
|
360394
|
+
paginationCounts.set(searchKey, pageCount);
|
|
360395
|
+
if (pageCount > MAX_PAGES_PER_QUERY) {
|
|
360396
|
+
if (debug) {
|
|
360397
|
+
console.error(`[DEDUP] Blocked excessive pagination (page ${pageCount}/${MAX_PAGES_PER_QUERY}): "${searchQuery}" in "${searchPath}"`);
|
|
360398
|
+
}
|
|
360399
|
+
return `PAGINATION LIMIT REACHED: You have already retrieved ${MAX_PAGES_PER_QUERY} pages of results for this query. You have enough results \u2014 use extract to examine specific files, or use attempt_completion to return your findings.`;
|
|
360400
|
+
}
|
|
360401
|
+
}
|
|
360000
360402
|
try {
|
|
360001
360403
|
const result = maybeAnnotate(await runRawSearch());
|
|
360002
360404
|
if (options.fileTracker && typeof result === "string") {
|
|
@@ -360035,7 +360437,8 @@ var init_vercel = __esm({
|
|
|
360035
360437
|
promptType: "code-searcher",
|
|
360036
360438
|
allowedTools: ["search", "extract", "listFiles", "attempt_completion"],
|
|
360037
360439
|
searchDelegate: false,
|
|
360038
|
-
schema: CODE_SEARCH_SCHEMA
|
|
360440
|
+
schema: CODE_SEARCH_SCHEMA,
|
|
360441
|
+
parentAbortSignal: options.parentAbortSignal || null
|
|
360039
360442
|
});
|
|
360040
360443
|
const delegateResult = options.tracer?.withSpan ? await options.tracer.withSpan("search.delegate", runDelegation, {
|
|
360041
360444
|
"search.query": searchQuery,
|
|
@@ -360249,7 +360652,7 @@ var init_vercel = __esm({
|
|
|
360249
360652
|
name: "delegate",
|
|
360250
360653
|
description: delegateDescription,
|
|
360251
360654
|
inputSchema: delegateSchema,
|
|
360252
|
-
execute: async ({ task, currentIteration, maxIterations, parentSessionId, path: path9, provider, model, tracer, searchDelegate }) => {
|
|
360655
|
+
execute: async ({ task, currentIteration, maxIterations, parentSessionId, path: path9, provider, model, tracer, searchDelegate, parentAbortSignal }) => {
|
|
360253
360656
|
if (!task || typeof task !== "string") {
|
|
360254
360657
|
throw new Error("Task parameter is required and must be a non-empty string");
|
|
360255
360658
|
}
|
|
@@ -360307,8 +360710,9 @@ var init_vercel = __esm({
|
|
|
360307
360710
|
enableMcp,
|
|
360308
360711
|
mcpConfig,
|
|
360309
360712
|
mcpConfigPath,
|
|
360310
|
-
delegationManager
|
|
360713
|
+
delegationManager,
|
|
360311
360714
|
// Per-instance delegation limits
|
|
360715
|
+
parentAbortSignal
|
|
360312
360716
|
});
|
|
360313
360717
|
return result;
|
|
360314
360718
|
}
|
|
@@ -360346,8 +360750,9 @@ var init_vercel = __esm({
|
|
|
360346
360750
|
provider: options.provider,
|
|
360347
360751
|
model: options.model,
|
|
360348
360752
|
tracer: options.tracer,
|
|
360349
|
-
delegationManager
|
|
360753
|
+
delegationManager,
|
|
360350
360754
|
// Per-instance delegation limits
|
|
360755
|
+
parentAbortSignal: options.parentAbortSignal || null
|
|
360351
360756
|
});
|
|
360352
360757
|
return result;
|
|
360353
360758
|
} catch (error2) {
|
|
@@ -397563,7 +397968,7 @@ module.exports = /*#__PURE__*/JSON.parse('{"100":"Continue","101":"Switching Pro
|
|
|
397563
397968
|
/***/ ((module) => {
|
|
397564
397969
|
|
|
397565
397970
|
"use strict";
|
|
397566
|
-
module.exports = /*#__PURE__*/JSON.parse('{"name":"@probelabs/visor","version":"0.1.42","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","@modelcontextprotocol/sdk":"^1.25.3","@nyariv/sandboxjs":"github:probelabs/SandboxJS#f1c13b8eee98734a8ea024061eada4aa9a9ff2e9","@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/core":"^1.30.1","@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-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-
|
|
397971
|
+
module.exports = /*#__PURE__*/JSON.parse('{"name":"@probelabs/visor","version":"0.1.42","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","@modelcontextprotocol/sdk":"^1.25.3","@nyariv/sandboxjs":"github:probelabs/SandboxJS#f1c13b8eee98734a8ea024061eada4aa9a9ff2e9","@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/core":"^1.30.1","@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-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-rc280","@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","cli-table3":"^0.6.5","commander":"^14.0.0","deepmerge":"^4.3.1","dotenv":"^17.2.3","ignore":"^7.0.5","js-yaml":"^4.1.0","jsonpath-plus":"^10.4.0","liquidjs":"^10.21.1","minimatch":"^10.2.2","node-cron":"^3.0.3","open":"^9.1.0","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/node":"^24.3.0","@types/node-cron":"^3.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"]}}');
|
|
397567
397972
|
|
|
397568
397973
|
/***/ })
|
|
397569
397974
|
|