@probelabs/visor 0.1.180-ee → 0.1.181-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/agent-protocol/track-execution.d.ts +1 -1
- package/dist/agent-protocol/track-execution.d.ts.map +1 -1
- package/dist/ai-review-service.d.ts +17 -1
- package/dist/ai-review-service.d.ts.map +1 -1
- package/dist/cli-main.d.ts.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/docs/commands.md +34 -1
- package/dist/email/polling-runner.d.ts +3 -1
- package/dist/email/polling-runner.d.ts.map +1 -1
- package/dist/frontends/github-frontend.d.ts.map +1 -1
- package/dist/index.js +1555 -752
- package/dist/mcp-server.d.ts +50 -6
- package/dist/mcp-server.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/runners/mcp-server-runner.d.ts +66 -0
- package/dist/runners/mcp-server-runner.d.ts.map +1 -0
- package/dist/runners/runner-factory.d.ts +12 -0
- package/dist/runners/runner-factory.d.ts.map +1 -0
- package/dist/runners/runner-host.d.ts +30 -0
- package/dist/runners/runner-host.d.ts.map +1 -0
- package/dist/runners/runner.d.ts +21 -0
- package/dist/runners/runner.d.ts.map +1 -0
- package/dist/runners/telemetry-init.d.ts +10 -0
- package/dist/runners/telemetry-init.d.ts.map +1 -0
- package/dist/sdk/{a2a-frontend-6FNPD53G.mjs → a2a-frontend-BDACLGMA.mjs} +2 -2
- package/dist/sdk/{check-provider-registry-Z4MVXFLJ.mjs → check-provider-registry-4YKTEDKF.mjs} +8 -8
- package/dist/sdk/{check-provider-registry-T4HIUBMT.mjs → check-provider-registry-Z7EHECLC.mjs} +7 -7
- package/dist/sdk/{chunk-NBUN22ZG.mjs → chunk-3JFK6KCD.mjs} +4 -10
- package/dist/sdk/chunk-3JFK6KCD.mjs.map +1 -0
- package/dist/sdk/{chunk-STAAKOPU.mjs → chunk-6HLDM4OB.mjs} +218 -48
- package/dist/sdk/chunk-6HLDM4OB.mjs.map +1 -0
- package/dist/sdk/{chunk-F25U4YWJ.mjs → chunk-7XRSCOKE.mjs} +3 -3
- package/dist/sdk/{chunk-ANCIFGQH.mjs.map → chunk-7XRSCOKE.mjs.map} +1 -1
- package/dist/sdk/{chunk-MWUQFSEK.mjs → chunk-7YZSSO4X.mjs} +213 -43
- package/dist/sdk/chunk-7YZSSO4X.mjs.map +1 -0
- package/dist/sdk/{chunk-3ZKBUWDB.mjs → chunk-KBGQJKIZ.mjs} +3 -3
- package/dist/sdk/{chunk-5DQY4LTK.mjs → chunk-U6K5SK7X.mjs} +2 -2
- package/dist/sdk/{chunk-KAVOGMLR.mjs → chunk-VMVIM4JB.mjs} +2 -1
- package/dist/sdk/{chunk-KAVOGMLR.mjs.map → chunk-VMVIM4JB.mjs.map} +1 -1
- package/dist/sdk/{config-ZZKC47SV.mjs → config-TSA5FUOM.mjs} +2 -2
- package/dist/sdk/dist-3UGGEZB3.mjs +8008 -0
- package/dist/sdk/dist-3UGGEZB3.mjs.map +1 -0
- package/dist/sdk/email-frontend-WSNADJPI.mjs +701 -0
- package/dist/sdk/email-frontend-WSNADJPI.mjs.map +1 -0
- package/dist/sdk/{failure-condition-evaluator-WNCCIP6N.mjs → failure-condition-evaluator-FFWJRAEQ.mjs} +3 -3
- package/dist/sdk/{github-frontend-QVMVUL3Y.mjs → github-frontend-KGV2R5Z6.mjs} +4 -4
- package/dist/sdk/github-frontend-KGV2R5Z6.mjs.map +1 -0
- package/dist/sdk/{host-5TJBWGGH.mjs → host-6QBBL3QW.mjs} +3 -3
- package/dist/sdk/{host-RVLIZMTE.mjs → host-CVH2CSHM.mjs} +4 -4
- package/dist/sdk/{routing-5DHNS7IW.mjs → routing-XALEDC2G.mjs} +4 -4
- package/dist/sdk/{schedule-tool-25CFKVOI.mjs → schedule-tool-5XBASQVY.mjs} +7 -7
- package/dist/sdk/{schedule-tool-UGWYLGJK.mjs → schedule-tool-ADUXTCY7.mjs} +8 -8
- package/dist/sdk/{schedule-tool-handler-VWBX4JEF.mjs → schedule-tool-handler-GBIJS376.mjs} +7 -7
- package/dist/sdk/{schedule-tool-handler-WK22RO3M.mjs → schedule-tool-handler-N7UNABOA.mjs} +8 -8
- package/dist/sdk/sdk.js +792 -6339
- package/dist/sdk/sdk.js.map +1 -1
- package/dist/sdk/sdk.mjs +7 -7
- package/dist/sdk/{trace-helpers-GCLQ3YKO.mjs → trace-helpers-3FFAI7X3.mjs} +2 -2
- package/dist/sdk/{track-execution-GCGJKMAO.mjs → track-execution-AMQQNXKE.mjs} +1 -1
- package/dist/sdk/track-execution-AMQQNXKE.mjs.map +1 -0
- package/dist/sdk/{utcp-check-provider-HT2MA5SS.mjs → utcp-check-provider-JLIYF5HH.mjs} +2 -2
- package/dist/sdk/{workflow-check-provider-I732XE7D.mjs → workflow-check-provider-3IXIADSV.mjs} +7 -7
- package/dist/sdk/{workflow-check-provider-T4PFK2EG.mjs → workflow-check-provider-SRIMWKLQ.mjs} +8 -8
- package/dist/slack/socket-runner.d.ts +3 -1
- package/dist/slack/socket-runner.d.ts.map +1 -1
- package/dist/state-machine/dispatch/template-renderer.d.ts.map +1 -1
- package/dist/state-machine/runner.d.ts.map +1 -1
- package/dist/teams/webhook-runner.d.ts +3 -1
- package/dist/teams/webhook-runner.d.ts.map +1 -1
- package/dist/telegram/polling-runner.d.ts +3 -1
- package/dist/telegram/polling-runner.d.ts.map +1 -1
- package/dist/types/cli.d.ts +6 -0
- package/dist/types/cli.d.ts.map +1 -1
- package/dist/whatsapp/webhook-runner.d.ts +3 -1
- package/dist/whatsapp/webhook-runner.d.ts.map +1 -1
- package/package.json +4 -10
- package/dist/sdk/chunk-ANCIFGQH.mjs +0 -825
- package/dist/sdk/chunk-F25U4YWJ.mjs.map +0 -1
- package/dist/sdk/chunk-MWUQFSEK.mjs.map +0 -1
- package/dist/sdk/chunk-NBUN22ZG.mjs.map +0 -1
- package/dist/sdk/chunk-STAAKOPU.mjs.map +0 -1
- package/dist/sdk/dist-X4HSBKSA.mjs +0 -5716
- package/dist/sdk/dist-X4HSBKSA.mjs.map +0 -1
- package/dist/sdk/dist-XF2FTM6E.mjs +0 -5716
- package/dist/sdk/dist-XF2FTM6E.mjs.map +0 -1
- package/dist/sdk/github-frontend-QVMVUL3Y.mjs.map +0 -1
- package/dist/sdk/track-execution-GCGJKMAO.mjs.map +0 -1
- package/dist/sdk/utcp-check-provider-6YTBN5WQ.mjs +0 -16
- package/dist/sdk/workflow-check-provider-T4PFK2EG.mjs.map +0 -1
- /package/dist/sdk/{a2a-frontend-6FNPD53G.mjs.map → a2a-frontend-BDACLGMA.mjs.map} +0 -0
- /package/dist/sdk/{check-provider-registry-T4HIUBMT.mjs.map → check-provider-registry-4YKTEDKF.mjs.map} +0 -0
- /package/dist/sdk/{check-provider-registry-Z4MVXFLJ.mjs.map → check-provider-registry-Z7EHECLC.mjs.map} +0 -0
- /package/dist/sdk/{chunk-3ZKBUWDB.mjs.map → chunk-KBGQJKIZ.mjs.map} +0 -0
- /package/dist/sdk/{chunk-5DQY4LTK.mjs.map → chunk-U6K5SK7X.mjs.map} +0 -0
- /package/dist/sdk/{config-ZZKC47SV.mjs.map → config-TSA5FUOM.mjs.map} +0 -0
- /package/dist/sdk/{failure-condition-evaluator-WNCCIP6N.mjs.map → failure-condition-evaluator-FFWJRAEQ.mjs.map} +0 -0
- /package/dist/sdk/{host-5TJBWGGH.mjs.map → host-6QBBL3QW.mjs.map} +0 -0
- /package/dist/sdk/{host-RVLIZMTE.mjs.map → host-CVH2CSHM.mjs.map} +0 -0
- /package/dist/sdk/{routing-5DHNS7IW.mjs.map → routing-XALEDC2G.mjs.map} +0 -0
- /package/dist/sdk/{schedule-tool-25CFKVOI.mjs.map → schedule-tool-5XBASQVY.mjs.map} +0 -0
- /package/dist/sdk/{schedule-tool-UGWYLGJK.mjs.map → schedule-tool-ADUXTCY7.mjs.map} +0 -0
- /package/dist/sdk/{schedule-tool-handler-VWBX4JEF.mjs.map → schedule-tool-handler-GBIJS376.mjs.map} +0 -0
- /package/dist/sdk/{schedule-tool-handler-WK22RO3M.mjs.map → schedule-tool-handler-N7UNABOA.mjs.map} +0 -0
- /package/dist/sdk/{trace-helpers-GCLQ3YKO.mjs.map → trace-helpers-3FFAI7X3.mjs.map} +0 -0
- /package/dist/sdk/{utcp-check-provider-6YTBN5WQ.mjs.map → utcp-check-provider-JLIYF5HH.mjs.map} +0 -0
- /package/dist/sdk/{utcp-check-provider-HT2MA5SS.mjs.map → workflow-check-provider-3IXIADSV.mjs.map} +0 -0
- /package/dist/sdk/{workflow-check-provider-I732XE7D.mjs.map → workflow-check-provider-SRIMWKLQ.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.181';
|
|
3
|
+
process.env.PROBE_VERSION = '0.6.0-rc297';
|
|
4
|
+
process.env.VISOR_COMMIT_SHA = 'c204877cf5806cf0582397a486599ba83a8e45a0';
|
|
5
|
+
process.env.VISOR_COMMIT_SHORT = 'c204877';
|
|
6
6
|
/******/ (() => { // webpackBootstrap
|
|
7
7
|
/******/ var __webpack_modules__ = ({
|
|
8
8
|
|
|
@@ -294716,6 +294716,17 @@ const PROBE_GRACEFUL_MARGIN_MS = 90_000;
|
|
|
294716
294716
|
* as-is because there isn't enough room for a meaningful margin.
|
|
294717
294717
|
*/
|
|
294718
294718
|
const MIN_TIMEOUT_FOR_MARGIN_MS = PROBE_GRACEFUL_MARGIN_MS + 30_000; // 120 000
|
|
294719
|
+
/**
|
|
294720
|
+
* Lightweight callback bridge for dynamically extending a withTimeout deadline.
|
|
294721
|
+
* Created per-call, wired to ProbeAgent's `timeout.extended` event so the
|
|
294722
|
+
* parent's Promise.race deadline tracks the child's negotiated extensions.
|
|
294723
|
+
*/
|
|
294724
|
+
class TimeoutExtender {
|
|
294725
|
+
_listener;
|
|
294726
|
+
extend(extraMs) {
|
|
294727
|
+
this._listener?.(extraMs);
|
|
294728
|
+
}
|
|
294729
|
+
}
|
|
294719
294730
|
/**
|
|
294720
294731
|
* Helper function to log debug messages using the centralized logger
|
|
294721
294732
|
*/
|
|
@@ -295118,9 +295129,14 @@ class AIReviewService {
|
|
|
295118
295129
|
}
|
|
295119
295130
|
}
|
|
295120
295131
|
try {
|
|
295121
|
-
|
|
295132
|
+
// Create an extender so withTimeout can be dynamically extended when the
|
|
295133
|
+
// agent's negotiated timeout observer grants more time (timeout.extended event).
|
|
295134
|
+
const extender = new TimeoutExtender();
|
|
295135
|
+
const call = this.callProbeAgent(prompt, schema, debugInfo, checkName, sessionId, extender);
|
|
295122
295136
|
const timeoutMs = Math.max(0, this.config.timeout || 0);
|
|
295123
|
-
const { response, effectiveSchema, sessionId: usedSessionId, } = timeoutMs > 0
|
|
295137
|
+
const { response, effectiveSchema, sessionId: usedSessionId, } = timeoutMs > 0
|
|
295138
|
+
? await this.withTimeout(call, timeoutMs, 'AI review', sessionId, extender)
|
|
295139
|
+
: await call;
|
|
295124
295140
|
const processingTime = Date.now() - startTime;
|
|
295125
295141
|
if (debugInfo) {
|
|
295126
295142
|
debugInfo.rawResponse = response;
|
|
@@ -295250,10 +295266,14 @@ class AIReviewService {
|
|
|
295250
295266
|
};
|
|
295251
295267
|
}
|
|
295252
295268
|
try {
|
|
295269
|
+
// Create an extender so withTimeout tracks agent's negotiated extensions
|
|
295270
|
+
const extender = new TimeoutExtender();
|
|
295253
295271
|
// Use the determined agent (cloned or original)
|
|
295254
|
-
const call = this.callProbeAgentWithExistingSession(agentToUse, prompt, schema, debugInfo, checkName);
|
|
295272
|
+
const call = this.callProbeAgentWithExistingSession(agentToUse, prompt, schema, debugInfo, checkName, extender);
|
|
295255
295273
|
const timeoutMs = Math.max(0, this.config.timeout || 0);
|
|
295256
|
-
const { response, effectiveSchema } = timeoutMs > 0
|
|
295274
|
+
const { response, effectiveSchema } = timeoutMs > 0
|
|
295275
|
+
? await this.withTimeout(call, timeoutMs, 'AI review (session)', currentSessionId, extender)
|
|
295276
|
+
: await call;
|
|
295257
295277
|
const processingTime = Date.now() - startTime;
|
|
295258
295278
|
if (debugInfo) {
|
|
295259
295279
|
debugInfo.rawResponse = response;
|
|
@@ -295299,19 +295319,110 @@ class AIReviewService {
|
|
|
295299
295319
|
}
|
|
295300
295320
|
}
|
|
295301
295321
|
/**
|
|
295302
|
-
* Promise timeout helper that rejects after ms if unresolved
|
|
295322
|
+
* Promise timeout helper that rejects after ms if unresolved.
|
|
295323
|
+
* When a sessionId is provided, triggers graceful wind-down on the
|
|
295324
|
+
* ProbeAgent before rejecting, giving it a chance to summarize.
|
|
295325
|
+
*
|
|
295326
|
+
* When an extender is provided, the deadline can be dynamically pushed
|
|
295327
|
+
* forward (e.g. when the agent's negotiated timeout observer grants an
|
|
295328
|
+
* extension and emits a `timeout.extended` event).
|
|
295303
295329
|
*/
|
|
295304
|
-
async withTimeout(p, ms, label = 'operation') {
|
|
295330
|
+
async withTimeout(p, ms, label = 'operation', sessionId, extender) {
|
|
295305
295331
|
let timer;
|
|
295332
|
+
const startTime = Date.now();
|
|
295333
|
+
let deadlineMs = ms; // total ms from startTime
|
|
295306
295334
|
try {
|
|
295307
295335
|
const timeout = new Promise((_, reject) => {
|
|
295308
|
-
|
|
295336
|
+
const scheduleTimer = () => {
|
|
295337
|
+
if (timer)
|
|
295338
|
+
clearTimeout(timer);
|
|
295339
|
+
const remaining = deadlineMs - (Date.now() - startTime);
|
|
295340
|
+
if (remaining <= 0) {
|
|
295341
|
+
fireTimeout(reject);
|
|
295342
|
+
return;
|
|
295343
|
+
}
|
|
295344
|
+
timer = setTimeout(() => fireTimeout(reject), remaining);
|
|
295345
|
+
};
|
|
295346
|
+
const fireTimeout = (rej) => {
|
|
295347
|
+
// Signal the agent to wind down before the hard kill.
|
|
295348
|
+
// This gives the agent a chance to produce partial results
|
|
295349
|
+
// in its bonus wind-down steps before we reject the promise.
|
|
295350
|
+
if (sessionId) {
|
|
295351
|
+
try {
|
|
295352
|
+
const agent = this.sessionRegistry.getSession(sessionId);
|
|
295353
|
+
if (agent && typeof agent.triggerGracefulWindDown === 'function') {
|
|
295354
|
+
agent.triggerGracefulWindDown();
|
|
295355
|
+
}
|
|
295356
|
+
}
|
|
295357
|
+
catch {
|
|
295358
|
+
// Best-effort: don't let registry errors block the timeout
|
|
295359
|
+
}
|
|
295360
|
+
}
|
|
295361
|
+
rej(new Error(`${label} timed out after ${deadlineMs}ms`));
|
|
295362
|
+
};
|
|
295363
|
+
// Allow the deadline to be extended dynamically
|
|
295364
|
+
if (extender) {
|
|
295365
|
+
extender._listener = (extraMs) => {
|
|
295366
|
+
deadlineMs += extraMs;
|
|
295367
|
+
try {
|
|
295368
|
+
const { addEvent } = __nccwpck_require__(75338);
|
|
295369
|
+
addEvent('visor.timeout_extended', {
|
|
295370
|
+
extra_ms: extraMs,
|
|
295371
|
+
new_deadline_ms: deadlineMs,
|
|
295372
|
+
elapsed_ms: Date.now() - startTime,
|
|
295373
|
+
});
|
|
295374
|
+
}
|
|
295375
|
+
catch { }
|
|
295376
|
+
log(`⏱️ Timeout extended by ${Math.round(extraMs / 60000)}min → new deadline ${Math.round(deadlineMs / 60000)}min`);
|
|
295377
|
+
scheduleTimer(); // Reset the timer with the new deadline
|
|
295378
|
+
};
|
|
295379
|
+
}
|
|
295380
|
+
scheduleTimer();
|
|
295309
295381
|
});
|
|
295310
295382
|
return (await Promise.race([p, timeout]));
|
|
295311
295383
|
}
|
|
295312
295384
|
finally {
|
|
295313
295385
|
if (timer)
|
|
295314
295386
|
clearTimeout(timer);
|
|
295387
|
+
if (extender)
|
|
295388
|
+
extender._listener = undefined;
|
|
295389
|
+
}
|
|
295390
|
+
}
|
|
295391
|
+
/**
|
|
295392
|
+
* Wire ProbeAgent's timeout events to a TimeoutExtender so the parent's
|
|
295393
|
+
* withTimeout deadline dynamically tracks the agent's negotiated extensions.
|
|
295394
|
+
*
|
|
295395
|
+
* - `timeout.extended`: observer granted more time → push deadline forward
|
|
295396
|
+
* - `timeout.windingDown`: observer declined → agent is finishing, log it
|
|
295397
|
+
*
|
|
295398
|
+
* Safe to call on older Probe versions that don't emit these events.
|
|
295399
|
+
*/
|
|
295400
|
+
wireTimeoutEvents(agent, extender) {
|
|
295401
|
+
try {
|
|
295402
|
+
const events = agent.events;
|
|
295403
|
+
if (!events || typeof events.on !== 'function')
|
|
295404
|
+
return;
|
|
295405
|
+
if (extender) {
|
|
295406
|
+
events.on('timeout.extended', (data) => {
|
|
295407
|
+
log(`⏱️ Agent extended timeout: +${Math.round(data.grantedMs / 60000)}min (${data.reason || 'work in progress'})`);
|
|
295408
|
+
extender.extend(data.grantedMs);
|
|
295409
|
+
});
|
|
295410
|
+
}
|
|
295411
|
+
events.on('timeout.windingDown', (data) => {
|
|
295412
|
+
log(`⏱️ Agent winding down: ${data.reason || 'observer declined'} (extensions used: ${data.extensionsUsed ?? 0}, total extra: ${Math.round((data.totalExtraTimeMs ?? 0) / 60000)}min)`);
|
|
295413
|
+
try {
|
|
295414
|
+
const { addEvent } = __nccwpck_require__(75338);
|
|
295415
|
+
addEvent('visor.agent_winding_down', {
|
|
295416
|
+
reason: data.reason || 'observer declined',
|
|
295417
|
+
extensions_used: data.extensionsUsed ?? 0,
|
|
295418
|
+
total_extra_time_ms: data.totalExtraTimeMs ?? 0,
|
|
295419
|
+
});
|
|
295420
|
+
}
|
|
295421
|
+
catch { }
|
|
295422
|
+
});
|
|
295423
|
+
}
|
|
295424
|
+
catch {
|
|
295425
|
+
// Best-effort: older Probe versions may not have events
|
|
295315
295426
|
}
|
|
295316
295427
|
}
|
|
295317
295428
|
/**
|
|
@@ -295905,7 +296016,7 @@ ${this.escapeXml(processedFallbackDiff)}
|
|
|
295905
296016
|
/**
|
|
295906
296017
|
* Call ProbeAgent with an existing session
|
|
295907
296018
|
*/
|
|
295908
|
-
async callProbeAgentWithExistingSession(agent, prompt, schema, debugInfo, _checkName) {
|
|
296019
|
+
async callProbeAgentWithExistingSession(agent, prompt, schema, debugInfo, _checkName, extender) {
|
|
295909
296020
|
// Handle mock model/provider for testing
|
|
295910
296021
|
if (this.config.model === 'mock' || this.config.provider === 'mock') {
|
|
295911
296022
|
log('🎭 Using mock AI model/provider for testing (session reuse)');
|
|
@@ -295925,7 +296036,10 @@ ${this.escapeXml(processedFallbackDiff)}
|
|
|
295925
296036
|
if (reuseAiTimeout > 0) {
|
|
295926
296037
|
agent.maxOperationTimeout = reuseAiTimeout;
|
|
295927
296038
|
}
|
|
295928
|
-
// Update negotiated timeout / graceful stop options on session reuse
|
|
296039
|
+
// Update negotiated timeout / graceful stop options on session reuse.
|
|
296040
|
+
// Budget/per-request values are passed through without capping — the agent's
|
|
296041
|
+
// observer now emits `timeout.extended` events and the parent dynamically
|
|
296042
|
+
// extends its withTimeout deadline to stay in sync (Probe #524).
|
|
295929
296043
|
if (this.config.timeoutBehavior) {
|
|
295930
296044
|
agent.timeoutBehavior = this.config.timeoutBehavior;
|
|
295931
296045
|
}
|
|
@@ -295941,6 +296055,8 @@ ${this.escapeXml(processedFallbackDiff)}
|
|
|
295941
296055
|
if (this.config.gracefulStopDeadline !== undefined) {
|
|
295942
296056
|
agent.gracefulStopDeadline = this.config.gracefulStopDeadline;
|
|
295943
296057
|
}
|
|
296058
|
+
// Wire agent timeout events to the extender so withTimeout tracks extensions
|
|
296059
|
+
this.wireTimeoutEvents(agent, extender);
|
|
295944
296060
|
try {
|
|
295945
296061
|
log('🚀 Calling existing ProbeAgent with answer()...');
|
|
295946
296062
|
// Load and pass the actual schema content if provided (skip for plain schema)
|
|
@@ -296255,7 +296371,7 @@ ${'='.repeat(60)}
|
|
|
296255
296371
|
/**
|
|
296256
296372
|
* Call ProbeAgent SDK with built-in schema validation
|
|
296257
296373
|
*/
|
|
296258
|
-
async callProbeAgent(prompt, schema, debugInfo, _checkName, providedSessionId) {
|
|
296374
|
+
async callProbeAgent(prompt, schema, debugInfo, _checkName, providedSessionId, extender) {
|
|
296259
296375
|
// Derive a stable session ID for this call so the engine can reuse it later
|
|
296260
296376
|
const sessionId = providedSessionId ||
|
|
296261
296377
|
(() => {
|
|
@@ -296393,7 +296509,10 @@ ${'='.repeat(60)}
|
|
|
296393
296509
|
if (aiTimeout > 0) {
|
|
296394
296510
|
options.maxOperationTimeout = aiTimeout;
|
|
296395
296511
|
}
|
|
296396
|
-
// Pass negotiated timeout / graceful stop options to ProbeAgent
|
|
296512
|
+
// Pass negotiated timeout / graceful stop options to ProbeAgent.
|
|
296513
|
+
// Budget/per-request values are passed through without capping — the
|
|
296514
|
+
// agent's observer emits `timeout.extended` events and withTimeout
|
|
296515
|
+
// dynamically extends its deadline to stay in sync (Probe #524).
|
|
296397
296516
|
if (this.config.timeoutBehavior) {
|
|
296398
296517
|
options.timeoutBehavior = this.config.timeoutBehavior;
|
|
296399
296518
|
}
|
|
@@ -296527,6 +296646,8 @@ ${'='.repeat(60)}
|
|
|
296527
296646
|
if (typeof agent.initialize === 'function') {
|
|
296528
296647
|
await agent.initialize();
|
|
296529
296648
|
}
|
|
296649
|
+
// Wire agent timeout events to the extender so withTimeout tracks extensions
|
|
296650
|
+
this.wireTimeoutEvents(agent, extender);
|
|
296530
296651
|
log('🚀 Calling ProbeAgent...');
|
|
296531
296652
|
// Load and pass the actual schema content if provided (skip for plain schema)
|
|
296532
296653
|
let schemaString = undefined;
|
|
@@ -298574,6 +298695,13 @@ async function main() {
|
|
|
298574
298695
|
configPath: getArg('--config'),
|
|
298575
298696
|
toolName: getArg('--mcp-tool-name'),
|
|
298576
298697
|
toolDescription: getArg('--mcp-tool-description'),
|
|
298698
|
+
transport: getArg('--transport') || 'stdio',
|
|
298699
|
+
port: getArg('--port') ? Number(getArg('--port')) : 8080,
|
|
298700
|
+
host: getArg('--host') || '0.0.0.0',
|
|
298701
|
+
authToken: getArg('--auth-token'),
|
|
298702
|
+
authTokenEnv: getArg('--auth-token-env'),
|
|
298703
|
+
tlsCert: getArg('--tls-cert'),
|
|
298704
|
+
tlsKey: getArg('--tls-key'),
|
|
298577
298705
|
};
|
|
298578
298706
|
const { startMcpServer } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(93143)));
|
|
298579
298707
|
await startMcpServer(mcpOptions);
|
|
@@ -298999,111 +299127,38 @@ async function main() {
|
|
|
298999
299127
|
logger_1.logger.warn(`[TaskTracking] Failed to initialize task store: ${err instanceof Error ? err.message : err}`);
|
|
299000
299128
|
}
|
|
299001
299129
|
}
|
|
299002
|
-
// ----
|
|
299003
|
-
|
|
299004
|
-
|
|
299005
|
-
|
|
299006
|
-
|
|
299007
|
-
|
|
299008
|
-
|
|
299009
|
-
|
|
299010
|
-
|
|
299011
|
-
|
|
299012
|
-
|
|
299130
|
+
// ---- Parallel Runner Mode (--slack, --telegram, --a2a, --mcp, etc.) ----
|
|
299131
|
+
const requestedRunners = [];
|
|
299132
|
+
if (options.a2a || config.agent_protocol?.enabled)
|
|
299133
|
+
requestedRunners.push('a2a');
|
|
299134
|
+
if (options.slack)
|
|
299135
|
+
requestedRunners.push('slack');
|
|
299136
|
+
if (options.mcp)
|
|
299137
|
+
requestedRunners.push('mcp');
|
|
299138
|
+
if (options.telegram)
|
|
299139
|
+
requestedRunners.push('telegram');
|
|
299140
|
+
if (options.email)
|
|
299141
|
+
requestedRunners.push('email');
|
|
299142
|
+
if (options.whatsapp)
|
|
299143
|
+
requestedRunners.push('whatsapp');
|
|
299144
|
+
if (options.teams)
|
|
299145
|
+
requestedRunners.push('teams');
|
|
299146
|
+
if (requestedRunners.length > 0) {
|
|
299147
|
+
const { RunnerHost } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(89736)));
|
|
299148
|
+
const { createRunner } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(11866)));
|
|
299149
|
+
const { initTelemetryFromConfig } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(84763)));
|
|
299150
|
+
await initTelemetryFromConfig(config);
|
|
299151
|
+
const engine = new state_machine_execution_engine_1.StateMachineExecutionEngine();
|
|
299152
|
+
const host = new RunnerHost();
|
|
299153
|
+
for (const name of requestedRunners) {
|
|
299154
|
+
host.addRunner(await createRunner(name, engine, config, options));
|
|
299013
299155
|
}
|
|
299014
|
-
const engine = new SMEngine();
|
|
299015
|
-
const frontend = new A2AFrontend(agentConfig, sharedTaskStore ?? undefined);
|
|
299016
|
-
frontend.setEngine(engine);
|
|
299017
|
-
frontend.setVisorConfig(config);
|
|
299018
|
-
const eventBus = new EventBus();
|
|
299019
|
-
const ctx = {
|
|
299020
|
-
eventBus,
|
|
299021
|
-
logger: logger_1.logger,
|
|
299022
|
-
config,
|
|
299023
|
-
run: { runId: crypto.randomUUID() },
|
|
299024
|
-
engine,
|
|
299025
|
-
visorConfig: config,
|
|
299026
|
-
};
|
|
299027
|
-
await frontend.start(ctx);
|
|
299028
|
-
const port = agentConfig.port ?? 9000;
|
|
299029
|
-
const host = agentConfig.host ?? '0.0.0.0';
|
|
299030
|
-
console.log(`A2A server running on ${host}:${port}`);
|
|
299031
|
-
if (options.slack === true) {
|
|
299032
|
-
// Both --a2a and --slack: keep references and fall through to Slack startup
|
|
299033
|
-
a2aFrontendInstance = frontend;
|
|
299034
|
-
sharedEngine = engine;
|
|
299035
|
-
}
|
|
299036
|
-
else {
|
|
299037
|
-
// Standalone --a2a mode: block here with shutdown handlers
|
|
299038
|
-
let shuttingDown = false;
|
|
299039
|
-
const onShutdown = async (sig) => {
|
|
299040
|
-
if (shuttingDown) {
|
|
299041
|
-
process.exit(1);
|
|
299042
|
-
return;
|
|
299043
|
-
}
|
|
299044
|
-
shuttingDown = true;
|
|
299045
|
-
logger_1.logger.info(`[A2A] Received ${sig}, shutting down gracefully...`);
|
|
299046
|
-
const forceTimer = setTimeout(() => {
|
|
299047
|
-
logger_1.logger.error('[A2A] Shutdown timed out, forcing exit');
|
|
299048
|
-
process.exit(1);
|
|
299049
|
-
}, 5000);
|
|
299050
|
-
forceTimer.unref();
|
|
299051
|
-
try {
|
|
299052
|
-
await frontend.stop();
|
|
299053
|
-
}
|
|
299054
|
-
catch { }
|
|
299055
|
-
process.exit(0);
|
|
299056
|
-
};
|
|
299057
|
-
process.on('SIGINT', sig => {
|
|
299058
|
-
onShutdown(sig);
|
|
299059
|
-
});
|
|
299060
|
-
process.on('SIGTERM', sig => {
|
|
299061
|
-
onShutdown(sig);
|
|
299062
|
-
});
|
|
299063
|
-
process.stdin.resume();
|
|
299064
|
-
return;
|
|
299065
|
-
}
|
|
299066
|
-
}
|
|
299067
|
-
// Socket Mode runner: visor --slack [--config file]
|
|
299068
|
-
if (options.slack === true) {
|
|
299069
|
-
const { SlackSocketRunner } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(45278)));
|
|
299070
|
-
const engine = sharedEngine ?? new state_machine_execution_engine_1.StateMachineExecutionEngine();
|
|
299071
|
-
const slackAny = config.slack || {};
|
|
299072
|
-
const endpoint = slackAny.endpoint || '/bots/slack/support';
|
|
299073
|
-
const mentions = slackAny.mentions || 'direct';
|
|
299074
|
-
const threads = slackAny.threads || 'any';
|
|
299075
|
-
const allow = Array.isArray(slackAny.channel_allowlist) ? slackAny.channel_allowlist : [];
|
|
299076
|
-
const appToken = slackAny.app_token || process.env.SLACK_APP_TOKEN;
|
|
299077
|
-
// Initialize telemetry for Slack mode (normally done later for CLI runs).
|
|
299078
|
-
if (config?.telemetry) {
|
|
299079
|
-
const t = config.telemetry;
|
|
299080
|
-
await (0, opentelemetry_1.initTelemetry)({
|
|
299081
|
-
enabled: process.env.VISOR_TELEMETRY_ENABLED === 'true' || !!t?.enabled,
|
|
299082
|
-
sink: process.env.VISOR_TELEMETRY_SINK || t?.sink || 'file',
|
|
299083
|
-
file: { dir: process.env.VISOR_TRACE_DIR || t?.file?.dir, ndjson: !!t?.file?.ndjson },
|
|
299084
|
-
autoInstrument: !!t?.tracing?.auto_instrumentations,
|
|
299085
|
-
traceReport: !!t?.tracing?.trace_report?.enabled,
|
|
299086
|
-
});
|
|
299087
|
-
}
|
|
299088
|
-
else {
|
|
299089
|
-
await (0, opentelemetry_1.initTelemetry)({
|
|
299090
|
-
enabled: process.env.VISOR_TELEMETRY_ENABLED === 'true',
|
|
299091
|
-
sink: process.env.VISOR_TELEMETRY_SINK || 'file',
|
|
299092
|
-
file: { dir: process.env.VISOR_TRACE_DIR },
|
|
299093
|
-
});
|
|
299094
|
-
}
|
|
299095
|
-
const runner = new SlackSocketRunner(engine, config, {
|
|
299096
|
-
appToken,
|
|
299097
|
-
endpoint,
|
|
299098
|
-
mentions,
|
|
299099
|
-
threads,
|
|
299100
|
-
channel_allowlist: allow,
|
|
299101
|
-
});
|
|
299102
299156
|
if (sharedTaskStore)
|
|
299103
|
-
|
|
299104
|
-
await
|
|
299105
|
-
|
|
299106
|
-
|
|
299157
|
+
host.setTaskStore(sharedTaskStore, options.configPath);
|
|
299158
|
+
await host.startAll();
|
|
299159
|
+
const names = requestedRunners.join(', ');
|
|
299160
|
+
console.log(`✅ Runner(s) started: ${names}. Press Ctrl+C to exit.`);
|
|
299161
|
+
// Config watcher (shared, broadcasts to all runners)
|
|
299107
299162
|
let configWatcher;
|
|
299108
299163
|
let configWatchStore;
|
|
299109
299164
|
if (options.watch) {
|
|
@@ -299123,7 +299178,7 @@ async function main() {
|
|
|
299123
299178
|
snapshotStore: watchStore,
|
|
299124
299179
|
onSwap: newConfig => {
|
|
299125
299180
|
config = newConfig;
|
|
299126
|
-
|
|
299181
|
+
host.broadcastConfigUpdate(newConfig);
|
|
299127
299182
|
logger_1.logger.info('[Watch] Config updated');
|
|
299128
299183
|
},
|
|
299129
299184
|
});
|
|
@@ -299134,23 +299189,20 @@ async function main() {
|
|
|
299134
299189
|
logger_1.logger.info('Config watching enabled');
|
|
299135
299190
|
}
|
|
299136
299191
|
catch (watchErr) {
|
|
299137
|
-
logger_1.logger.warn(`Config watch setup failed (
|
|
299192
|
+
logger_1.logger.warn(`Config watch setup failed (runners continue without it): ${watchErr}`);
|
|
299138
299193
|
}
|
|
299139
299194
|
}
|
|
299140
|
-
//
|
|
299195
|
+
// Unified graceful shutdown
|
|
299141
299196
|
let shuttingDown = false;
|
|
299142
299197
|
const onShutdown = async (sig) => {
|
|
299143
299198
|
if (shuttingDown) {
|
|
299144
|
-
// Second signal — force exit immediately
|
|
299145
|
-
logger_1.logger.warn(`[Slack] Received ${sig} again, forcing exit`);
|
|
299146
299199
|
process.exit(1);
|
|
299147
299200
|
return;
|
|
299148
299201
|
}
|
|
299149
299202
|
shuttingDown = true;
|
|
299150
|
-
logger_1.logger.info(`[
|
|
299151
|
-
// Force exit after 5s if graceful shutdown hangs
|
|
299203
|
+
logger_1.logger.info(`[RunnerHost] Received ${sig}, shutting down gracefully…`);
|
|
299152
299204
|
const forceTimer = setTimeout(() => {
|
|
299153
|
-
logger_1.logger.error('[
|
|
299205
|
+
logger_1.logger.error('[RunnerHost] Shutdown timed out after 5s, forcing exit');
|
|
299154
299206
|
process.exit(1);
|
|
299155
299207
|
}, 5000);
|
|
299156
299208
|
forceTimer.unref();
|
|
@@ -299159,15 +299211,7 @@ async function main() {
|
|
|
299159
299211
|
configWatcher.stop();
|
|
299160
299212
|
if (configWatchStore)
|
|
299161
299213
|
configWatchStore.shutdown().catch(() => { });
|
|
299162
|
-
|
|
299163
|
-
try {
|
|
299164
|
-
await a2aFrontendInstance.stop();
|
|
299165
|
-
}
|
|
299166
|
-
catch {
|
|
299167
|
-
/* ignore */
|
|
299168
|
-
}
|
|
299169
|
-
}
|
|
299170
|
-
await runner.stop();
|
|
299214
|
+
await host.stopAll();
|
|
299171
299215
|
if (sharedTaskStore) {
|
|
299172
299216
|
try {
|
|
299173
299217
|
await sharedTaskStore.shutdown();
|
|
@@ -299176,444 +299220,8 @@ async function main() {
|
|
|
299176
299220
|
}
|
|
299177
299221
|
}
|
|
299178
299222
|
catch (err) {
|
|
299179
|
-
logger_1.logger.warn(`[
|
|
299180
|
-
}
|
|
299181
|
-
process.exit(0);
|
|
299182
|
-
};
|
|
299183
|
-
process.on('SIGINT', sig => {
|
|
299184
|
-
onShutdown(sig);
|
|
299185
|
-
});
|
|
299186
|
-
process.on('SIGTERM', sig => {
|
|
299187
|
-
onShutdown(sig);
|
|
299188
|
-
});
|
|
299189
|
-
process.stdin.resume();
|
|
299190
|
-
return;
|
|
299191
|
-
}
|
|
299192
|
-
// Long-polling runner: visor --telegram [--config file]
|
|
299193
|
-
if (options.telegram === true) {
|
|
299194
|
-
const { TelegramPollingRunner } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(33519)));
|
|
299195
|
-
const engine = sharedEngine ?? new state_machine_execution_engine_1.StateMachineExecutionEngine();
|
|
299196
|
-
const telegramAny = config.telegram || {};
|
|
299197
|
-
// Initialize telemetry for Telegram mode
|
|
299198
|
-
if (config?.telemetry) {
|
|
299199
|
-
const t = config.telemetry;
|
|
299200
|
-
await (0, opentelemetry_1.initTelemetry)({
|
|
299201
|
-
enabled: process.env.VISOR_TELEMETRY_ENABLED === 'true' || !!t?.enabled,
|
|
299202
|
-
sink: process.env.VISOR_TELEMETRY_SINK || t?.sink || 'file',
|
|
299203
|
-
file: { dir: process.env.VISOR_TRACE_DIR || t?.file?.dir, ndjson: !!t?.file?.ndjson },
|
|
299204
|
-
autoInstrument: !!t?.tracing?.auto_instrumentations,
|
|
299205
|
-
traceReport: !!t?.tracing?.trace_report?.enabled,
|
|
299206
|
-
});
|
|
299207
|
-
}
|
|
299208
|
-
else {
|
|
299209
|
-
await (0, opentelemetry_1.initTelemetry)({
|
|
299210
|
-
enabled: process.env.VISOR_TELEMETRY_ENABLED === 'true',
|
|
299211
|
-
sink: process.env.VISOR_TELEMETRY_SINK || 'file',
|
|
299212
|
-
file: { dir: process.env.VISOR_TRACE_DIR },
|
|
299213
|
-
});
|
|
299214
|
-
}
|
|
299215
|
-
const runner = new TelegramPollingRunner(engine, config, {
|
|
299216
|
-
botToken: telegramAny.bot_token || process.env.TELEGRAM_BOT_TOKEN,
|
|
299217
|
-
pollingTimeout: telegramAny.polling_timeout || 30,
|
|
299218
|
-
chatAllowlist: telegramAny.chat_allowlist,
|
|
299219
|
-
requireMention: telegramAny.require_mention ?? true,
|
|
299220
|
-
workflow: telegramAny.workflow,
|
|
299221
|
-
});
|
|
299222
|
-
if (sharedTaskStore)
|
|
299223
|
-
runner.setTaskStore(sharedTaskStore, options.configPath);
|
|
299224
|
-
await runner.start();
|
|
299225
|
-
console.log('✅ Telegram long-polling is running. Press Ctrl+C to exit.');
|
|
299226
|
-
// Config watcher (same pattern as Slack)
|
|
299227
|
-
let configWatcher;
|
|
299228
|
-
let configWatchStore;
|
|
299229
|
-
if (options.watch) {
|
|
299230
|
-
if (!options.configPath) {
|
|
299231
|
-
console.error('❌ --watch requires --config <path>');
|
|
299232
|
-
process.exit(1);
|
|
299233
|
-
}
|
|
299234
|
-
try {
|
|
299235
|
-
const { ConfigSnapshotStore } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(23147)));
|
|
299236
|
-
const { ConfigReloader } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(75773)));
|
|
299237
|
-
const { ConfigWatcher } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(39995)));
|
|
299238
|
-
const watchStore = new ConfigSnapshotStore();
|
|
299239
|
-
await watchStore.initialize();
|
|
299240
|
-
const reloader = new ConfigReloader({
|
|
299241
|
-
configPath: options.configPath,
|
|
299242
|
-
configManager,
|
|
299243
|
-
snapshotStore: watchStore,
|
|
299244
|
-
onSwap: newConfig => {
|
|
299245
|
-
config = newConfig;
|
|
299246
|
-
runner.updateConfig(newConfig);
|
|
299247
|
-
logger_1.logger.info('[Watch] Config updated');
|
|
299248
|
-
},
|
|
299249
|
-
});
|
|
299250
|
-
const watcher = new ConfigWatcher(options.configPath, reloader);
|
|
299251
|
-
watcher.start();
|
|
299252
|
-
configWatcher = watcher;
|
|
299253
|
-
configWatchStore = watchStore;
|
|
299254
|
-
logger_1.logger.info('Config watching enabled');
|
|
299255
|
-
}
|
|
299256
|
-
catch (watchErr) {
|
|
299257
|
-
logger_1.logger.warn(`Config watch setup failed (Telegram mode continues without it): ${watchErr}`);
|
|
299258
|
-
}
|
|
299259
|
-
}
|
|
299260
|
-
// Graceful shutdown
|
|
299261
|
-
let shuttingDown = false;
|
|
299262
|
-
const onShutdown = async (sig) => {
|
|
299263
|
-
if (shuttingDown) {
|
|
299264
|
-
process.exit(1);
|
|
299265
|
-
return;
|
|
299223
|
+
logger_1.logger.warn(`[RunnerHost] Error during shutdown: ${err}`);
|
|
299266
299224
|
}
|
|
299267
|
-
shuttingDown = true;
|
|
299268
|
-
logger_1.logger.info(`[Telegram] Received ${sig}, shutting down gracefully…`);
|
|
299269
|
-
const forceTimer = setTimeout(() => {
|
|
299270
|
-
logger_1.logger.error('[Telegram] Shutdown timed out, forcing exit');
|
|
299271
|
-
process.exit(1);
|
|
299272
|
-
}, 5000);
|
|
299273
|
-
forceTimer.unref();
|
|
299274
|
-
try {
|
|
299275
|
-
if (configWatcher)
|
|
299276
|
-
configWatcher.stop();
|
|
299277
|
-
if (configWatchStore)
|
|
299278
|
-
configWatchStore.shutdown().catch(() => { });
|
|
299279
|
-
await runner.stop();
|
|
299280
|
-
if (sharedTaskStore) {
|
|
299281
|
-
try {
|
|
299282
|
-
await sharedTaskStore.shutdown();
|
|
299283
|
-
}
|
|
299284
|
-
catch { }
|
|
299285
|
-
}
|
|
299286
|
-
}
|
|
299287
|
-
catch { }
|
|
299288
|
-
process.exit(0);
|
|
299289
|
-
};
|
|
299290
|
-
process.on('SIGINT', sig => {
|
|
299291
|
-
onShutdown(sig);
|
|
299292
|
-
});
|
|
299293
|
-
process.on('SIGTERM', sig => {
|
|
299294
|
-
onShutdown(sig);
|
|
299295
|
-
});
|
|
299296
|
-
process.stdin.resume();
|
|
299297
|
-
return;
|
|
299298
|
-
}
|
|
299299
|
-
// Email polling runner: visor --email [--config file]
|
|
299300
|
-
if (options.email === true) {
|
|
299301
|
-
const { EmailPollingRunner } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(66550)));
|
|
299302
|
-
const engine = sharedEngine ?? new state_machine_execution_engine_1.StateMachineExecutionEngine();
|
|
299303
|
-
const emailAny = config.email || {};
|
|
299304
|
-
// Initialize telemetry for Email mode
|
|
299305
|
-
if (config?.telemetry) {
|
|
299306
|
-
const t = config.telemetry;
|
|
299307
|
-
await (0, opentelemetry_1.initTelemetry)({
|
|
299308
|
-
enabled: process.env.VISOR_TELEMETRY_ENABLED === 'true' || !!t?.enabled,
|
|
299309
|
-
sink: process.env.VISOR_TELEMETRY_SINK || t?.sink || 'file',
|
|
299310
|
-
file: { dir: process.env.VISOR_TRACE_DIR || t?.file?.dir, ndjson: !!t?.file?.ndjson },
|
|
299311
|
-
autoInstrument: !!t?.tracing?.auto_instrumentations,
|
|
299312
|
-
traceReport: !!t?.tracing?.trace_report?.enabled,
|
|
299313
|
-
});
|
|
299314
|
-
}
|
|
299315
|
-
else {
|
|
299316
|
-
await (0, opentelemetry_1.initTelemetry)({
|
|
299317
|
-
enabled: process.env.VISOR_TELEMETRY_ENABLED === 'true',
|
|
299318
|
-
sink: process.env.VISOR_TELEMETRY_SINK || 'file',
|
|
299319
|
-
file: { dir: process.env.VISOR_TRACE_DIR },
|
|
299320
|
-
});
|
|
299321
|
-
}
|
|
299322
|
-
const runner = new EmailPollingRunner(engine, config, {
|
|
299323
|
-
receive: emailAny.receive || {},
|
|
299324
|
-
send: emailAny.send || {},
|
|
299325
|
-
allowlist: emailAny.allowlist,
|
|
299326
|
-
workflow: emailAny.workflow,
|
|
299327
|
-
});
|
|
299328
|
-
if (sharedTaskStore)
|
|
299329
|
-
runner.setTaskStore(sharedTaskStore, options.configPath);
|
|
299330
|
-
await runner.start();
|
|
299331
|
-
const receiveType = emailAny.receive?.type || 'imap';
|
|
299332
|
-
console.log(`✅ Email runner (${receiveType}) is running. Press Ctrl+C to exit.`);
|
|
299333
|
-
// Config watcher (same pattern as Telegram)
|
|
299334
|
-
let configWatcher;
|
|
299335
|
-
let configWatchStore;
|
|
299336
|
-
if (options.watch) {
|
|
299337
|
-
if (!options.configPath) {
|
|
299338
|
-
console.error('❌ --watch requires --config <path>');
|
|
299339
|
-
process.exit(1);
|
|
299340
|
-
}
|
|
299341
|
-
try {
|
|
299342
|
-
const { ConfigSnapshotStore } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(23147)));
|
|
299343
|
-
const { ConfigReloader } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(75773)));
|
|
299344
|
-
const { ConfigWatcher } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(39995)));
|
|
299345
|
-
const watchStore = new ConfigSnapshotStore();
|
|
299346
|
-
await watchStore.initialize();
|
|
299347
|
-
const reloader = new ConfigReloader({
|
|
299348
|
-
configPath: options.configPath,
|
|
299349
|
-
configManager,
|
|
299350
|
-
snapshotStore: watchStore,
|
|
299351
|
-
onSwap: newConfig => {
|
|
299352
|
-
config = newConfig;
|
|
299353
|
-
runner.updateConfig(newConfig);
|
|
299354
|
-
logger_1.logger.info('[Watch] Config updated');
|
|
299355
|
-
},
|
|
299356
|
-
});
|
|
299357
|
-
const watcher = new ConfigWatcher(options.configPath, reloader);
|
|
299358
|
-
watcher.start();
|
|
299359
|
-
configWatcher = watcher;
|
|
299360
|
-
configWatchStore = watchStore;
|
|
299361
|
-
logger_1.logger.info('Config watching enabled');
|
|
299362
|
-
}
|
|
299363
|
-
catch (watchErr) {
|
|
299364
|
-
logger_1.logger.warn(`Config watch setup failed (Email mode continues without it): ${watchErr}`);
|
|
299365
|
-
}
|
|
299366
|
-
}
|
|
299367
|
-
// Graceful shutdown
|
|
299368
|
-
let shuttingDown = false;
|
|
299369
|
-
const onShutdown = async (sig) => {
|
|
299370
|
-
if (shuttingDown) {
|
|
299371
|
-
process.exit(1);
|
|
299372
|
-
return;
|
|
299373
|
-
}
|
|
299374
|
-
shuttingDown = true;
|
|
299375
|
-
logger_1.logger.info(`[Email] Received ${sig}, shutting down gracefully…`);
|
|
299376
|
-
const forceTimer = setTimeout(() => {
|
|
299377
|
-
logger_1.logger.error('[Email] Shutdown timed out, forcing exit');
|
|
299378
|
-
process.exit(1);
|
|
299379
|
-
}, 5000);
|
|
299380
|
-
forceTimer.unref();
|
|
299381
|
-
try {
|
|
299382
|
-
if (configWatcher)
|
|
299383
|
-
configWatcher.stop();
|
|
299384
|
-
if (configWatchStore)
|
|
299385
|
-
configWatchStore.shutdown().catch(() => { });
|
|
299386
|
-
await runner.stop();
|
|
299387
|
-
if (sharedTaskStore) {
|
|
299388
|
-
try {
|
|
299389
|
-
await sharedTaskStore.shutdown();
|
|
299390
|
-
}
|
|
299391
|
-
catch { }
|
|
299392
|
-
}
|
|
299393
|
-
}
|
|
299394
|
-
catch { }
|
|
299395
|
-
process.exit(0);
|
|
299396
|
-
};
|
|
299397
|
-
process.on('SIGINT', sig => {
|
|
299398
|
-
onShutdown(sig);
|
|
299399
|
-
});
|
|
299400
|
-
process.on('SIGTERM', sig => {
|
|
299401
|
-
onShutdown(sig);
|
|
299402
|
-
});
|
|
299403
|
-
process.stdin.resume();
|
|
299404
|
-
return;
|
|
299405
|
-
}
|
|
299406
|
-
// WhatsApp webhook runner: visor --whatsapp [--config file]
|
|
299407
|
-
if (options.whatsapp === true) {
|
|
299408
|
-
const { WhatsAppWebhookRunner } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(21718)));
|
|
299409
|
-
const engine = sharedEngine ?? new state_machine_execution_engine_1.StateMachineExecutionEngine();
|
|
299410
|
-
const waAny = config.whatsapp || {};
|
|
299411
|
-
// Initialize telemetry for WhatsApp mode
|
|
299412
|
-
if (config?.telemetry) {
|
|
299413
|
-
const t = config.telemetry;
|
|
299414
|
-
await (0, opentelemetry_1.initTelemetry)({
|
|
299415
|
-
enabled: process.env.VISOR_TELEMETRY_ENABLED === 'true' || !!t?.enabled,
|
|
299416
|
-
sink: process.env.VISOR_TELEMETRY_SINK || t?.sink || 'file',
|
|
299417
|
-
file: { dir: process.env.VISOR_TRACE_DIR || t?.file?.dir, ndjson: !!t?.file?.ndjson },
|
|
299418
|
-
autoInstrument: !!t?.tracing?.auto_instrumentations,
|
|
299419
|
-
traceReport: !!t?.tracing?.trace_report?.enabled,
|
|
299420
|
-
});
|
|
299421
|
-
}
|
|
299422
|
-
else {
|
|
299423
|
-
await (0, opentelemetry_1.initTelemetry)({
|
|
299424
|
-
enabled: process.env.VISOR_TELEMETRY_ENABLED === 'true',
|
|
299425
|
-
sink: process.env.VISOR_TELEMETRY_SINK || 'file',
|
|
299426
|
-
file: { dir: process.env.VISOR_TRACE_DIR },
|
|
299427
|
-
});
|
|
299428
|
-
}
|
|
299429
|
-
const runner = new WhatsAppWebhookRunner(engine, config, {
|
|
299430
|
-
accessToken: waAny.access_token || process.env.WHATSAPP_ACCESS_TOKEN,
|
|
299431
|
-
phoneNumberId: waAny.phone_number_id || process.env.WHATSAPP_PHONE_NUMBER_ID,
|
|
299432
|
-
appSecret: waAny.app_secret || process.env.WHATSAPP_APP_SECRET,
|
|
299433
|
-
verifyToken: waAny.verify_token || process.env.WHATSAPP_VERIFY_TOKEN,
|
|
299434
|
-
apiVersion: waAny.api_version || 'v21.0',
|
|
299435
|
-
port: waAny.port || parseInt(process.env.WHATSAPP_WEBHOOK_PORT || '8443'),
|
|
299436
|
-
host: waAny.host || '0.0.0.0',
|
|
299437
|
-
phoneAllowlist: waAny.phone_allowlist,
|
|
299438
|
-
workflow: waAny.workflow,
|
|
299439
|
-
});
|
|
299440
|
-
if (sharedTaskStore)
|
|
299441
|
-
runner.setTaskStore(sharedTaskStore, options.configPath);
|
|
299442
|
-
await runner.start();
|
|
299443
|
-
const port = waAny.port || parseInt(process.env.WHATSAPP_WEBHOOK_PORT || '8443');
|
|
299444
|
-
console.log(`✅ WhatsApp webhook server running on port ${port}. Press Ctrl+C to exit.`);
|
|
299445
|
-
// Config watcher (same pattern as Telegram/Email)
|
|
299446
|
-
let configWatcher;
|
|
299447
|
-
let configWatchStore;
|
|
299448
|
-
if (options.watch) {
|
|
299449
|
-
if (!options.configPath) {
|
|
299450
|
-
console.error('❌ --watch requires --config <path>');
|
|
299451
|
-
process.exit(1);
|
|
299452
|
-
}
|
|
299453
|
-
try {
|
|
299454
|
-
const { ConfigSnapshotStore } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(23147)));
|
|
299455
|
-
const { ConfigReloader } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(75773)));
|
|
299456
|
-
const { ConfigWatcher } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(39995)));
|
|
299457
|
-
const watchStore = new ConfigSnapshotStore();
|
|
299458
|
-
await watchStore.initialize();
|
|
299459
|
-
const reloader = new ConfigReloader({
|
|
299460
|
-
configPath: options.configPath,
|
|
299461
|
-
configManager,
|
|
299462
|
-
snapshotStore: watchStore,
|
|
299463
|
-
onSwap: newConfig => {
|
|
299464
|
-
config = newConfig;
|
|
299465
|
-
runner.updateConfig(newConfig);
|
|
299466
|
-
logger_1.logger.info('[Watch] Config updated');
|
|
299467
|
-
},
|
|
299468
|
-
});
|
|
299469
|
-
const watcher = new ConfigWatcher(options.configPath, reloader);
|
|
299470
|
-
watcher.start();
|
|
299471
|
-
configWatcher = watcher;
|
|
299472
|
-
configWatchStore = watchStore;
|
|
299473
|
-
logger_1.logger.info('Config watching enabled');
|
|
299474
|
-
}
|
|
299475
|
-
catch (watchErr) {
|
|
299476
|
-
logger_1.logger.warn(`Config watch setup failed (WhatsApp mode continues without it): ${watchErr}`);
|
|
299477
|
-
}
|
|
299478
|
-
}
|
|
299479
|
-
// Graceful shutdown
|
|
299480
|
-
let shuttingDown = false;
|
|
299481
|
-
const onShutdown = async (sig) => {
|
|
299482
|
-
if (shuttingDown) {
|
|
299483
|
-
process.exit(1);
|
|
299484
|
-
return;
|
|
299485
|
-
}
|
|
299486
|
-
shuttingDown = true;
|
|
299487
|
-
logger_1.logger.info(`[WhatsApp] Received ${sig}, shutting down gracefully…`);
|
|
299488
|
-
const forceTimer = setTimeout(() => {
|
|
299489
|
-
logger_1.logger.error('[WhatsApp] Shutdown timed out, forcing exit');
|
|
299490
|
-
process.exit(1);
|
|
299491
|
-
}, 5000);
|
|
299492
|
-
forceTimer.unref();
|
|
299493
|
-
try {
|
|
299494
|
-
if (configWatcher)
|
|
299495
|
-
configWatcher.stop();
|
|
299496
|
-
if (configWatchStore)
|
|
299497
|
-
configWatchStore.shutdown().catch(() => { });
|
|
299498
|
-
await runner.stop();
|
|
299499
|
-
if (sharedTaskStore) {
|
|
299500
|
-
try {
|
|
299501
|
-
await sharedTaskStore.shutdown();
|
|
299502
|
-
}
|
|
299503
|
-
catch { }
|
|
299504
|
-
}
|
|
299505
|
-
}
|
|
299506
|
-
catch { }
|
|
299507
|
-
process.exit(0);
|
|
299508
|
-
};
|
|
299509
|
-
process.on('SIGINT', sig => {
|
|
299510
|
-
onShutdown(sig);
|
|
299511
|
-
});
|
|
299512
|
-
process.on('SIGTERM', sig => {
|
|
299513
|
-
onShutdown(sig);
|
|
299514
|
-
});
|
|
299515
|
-
process.stdin.resume();
|
|
299516
|
-
return;
|
|
299517
|
-
}
|
|
299518
|
-
// ── Microsoft Teams webhook runner ──────────────────────────────
|
|
299519
|
-
if (options.teams === true) {
|
|
299520
|
-
const { TeamsWebhookRunner } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(86710)));
|
|
299521
|
-
const engine = sharedEngine ?? new state_machine_execution_engine_1.StateMachineExecutionEngine();
|
|
299522
|
-
const teamsAny = config.teams || {};
|
|
299523
|
-
// Initialize telemetry for Teams mode
|
|
299524
|
-
if (config?.telemetry) {
|
|
299525
|
-
const t = config.telemetry;
|
|
299526
|
-
await (0, opentelemetry_1.initTelemetry)({
|
|
299527
|
-
enabled: process.env.VISOR_TELEMETRY_ENABLED === 'true' || !!t?.enabled,
|
|
299528
|
-
sink: process.env.VISOR_TELEMETRY_SINK || t?.sink || 'file',
|
|
299529
|
-
file: { dir: process.env.VISOR_TRACE_DIR || t?.file?.dir, ndjson: !!t?.file?.ndjson },
|
|
299530
|
-
autoInstrument: !!t?.tracing?.auto_instrumentations,
|
|
299531
|
-
traceReport: !!t?.tracing?.trace_report?.enabled,
|
|
299532
|
-
});
|
|
299533
|
-
}
|
|
299534
|
-
else {
|
|
299535
|
-
await (0, opentelemetry_1.initTelemetry)({
|
|
299536
|
-
enabled: process.env.VISOR_TELEMETRY_ENABLED === 'true',
|
|
299537
|
-
sink: process.env.VISOR_TELEMETRY_SINK || 'file',
|
|
299538
|
-
file: { dir: process.env.VISOR_TRACE_DIR },
|
|
299539
|
-
});
|
|
299540
|
-
}
|
|
299541
|
-
const runner = new TeamsWebhookRunner(engine, config, {
|
|
299542
|
-
appId: teamsAny.app_id || process.env.TEAMS_APP_ID,
|
|
299543
|
-
appPassword: teamsAny.app_password || process.env.TEAMS_APP_PASSWORD,
|
|
299544
|
-
tenantId: teamsAny.tenant_id || process.env.TEAMS_TENANT_ID,
|
|
299545
|
-
port: teamsAny.port || parseInt(process.env.TEAMS_WEBHOOK_PORT || '3978'),
|
|
299546
|
-
host: teamsAny.host || '0.0.0.0',
|
|
299547
|
-
userAllowlist: teamsAny.user_allowlist,
|
|
299548
|
-
workflow: teamsAny.workflow,
|
|
299549
|
-
});
|
|
299550
|
-
if (sharedTaskStore)
|
|
299551
|
-
runner.setTaskStore(sharedTaskStore, options.configPath);
|
|
299552
|
-
await runner.start();
|
|
299553
|
-
const port = teamsAny.port || parseInt(process.env.TEAMS_WEBHOOK_PORT || '3978');
|
|
299554
|
-
console.log(`✅ Teams webhook server running on port ${port}. Press Ctrl+C to exit.`);
|
|
299555
|
-
// Config watcher (same pattern as WhatsApp/Telegram/Email)
|
|
299556
|
-
let configWatcher;
|
|
299557
|
-
let configWatchStore;
|
|
299558
|
-
if (options.watch) {
|
|
299559
|
-
if (!options.configPath) {
|
|
299560
|
-
console.error('❌ --watch requires --config <path>');
|
|
299561
|
-
process.exit(1);
|
|
299562
|
-
}
|
|
299563
|
-
try {
|
|
299564
|
-
const { ConfigSnapshotStore } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(23147)));
|
|
299565
|
-
const { ConfigReloader } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(75773)));
|
|
299566
|
-
const { ConfigWatcher } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(39995)));
|
|
299567
|
-
const watchStore = new ConfigSnapshotStore();
|
|
299568
|
-
await watchStore.initialize();
|
|
299569
|
-
const reloader = new ConfigReloader({
|
|
299570
|
-
configPath: options.configPath,
|
|
299571
|
-
configManager,
|
|
299572
|
-
snapshotStore: watchStore,
|
|
299573
|
-
onSwap: newConfig => {
|
|
299574
|
-
config = newConfig;
|
|
299575
|
-
runner.updateConfig(newConfig);
|
|
299576
|
-
logger_1.logger.info('[Watch] Config updated');
|
|
299577
|
-
},
|
|
299578
|
-
});
|
|
299579
|
-
const watcher = new ConfigWatcher(options.configPath, reloader);
|
|
299580
|
-
watcher.start();
|
|
299581
|
-
configWatcher = watcher;
|
|
299582
|
-
configWatchStore = watchStore;
|
|
299583
|
-
logger_1.logger.info('Config watching enabled');
|
|
299584
|
-
}
|
|
299585
|
-
catch (watchErr) {
|
|
299586
|
-
logger_1.logger.warn(`Config watch setup failed (Teams mode continues without it): ${watchErr}`);
|
|
299587
|
-
}
|
|
299588
|
-
}
|
|
299589
|
-
// Graceful shutdown
|
|
299590
|
-
let shuttingDown = false;
|
|
299591
|
-
const onShutdown = async (sig) => {
|
|
299592
|
-
if (shuttingDown) {
|
|
299593
|
-
process.exit(1);
|
|
299594
|
-
return;
|
|
299595
|
-
}
|
|
299596
|
-
shuttingDown = true;
|
|
299597
|
-
logger_1.logger.info(`[Teams] Received ${sig}, shutting down gracefully…`);
|
|
299598
|
-
const forceTimer = setTimeout(() => {
|
|
299599
|
-
logger_1.logger.error('[Teams] Shutdown timed out, forcing exit');
|
|
299600
|
-
process.exit(1);
|
|
299601
|
-
}, 5000);
|
|
299602
|
-
forceTimer.unref();
|
|
299603
|
-
try {
|
|
299604
|
-
if (configWatcher)
|
|
299605
|
-
configWatcher.stop();
|
|
299606
|
-
if (configWatchStore)
|
|
299607
|
-
configWatchStore.shutdown().catch(() => { });
|
|
299608
|
-
await runner.stop();
|
|
299609
|
-
if (sharedTaskStore) {
|
|
299610
|
-
try {
|
|
299611
|
-
await sharedTaskStore.shutdown();
|
|
299612
|
-
}
|
|
299613
|
-
catch { }
|
|
299614
|
-
}
|
|
299615
|
-
}
|
|
299616
|
-
catch { }
|
|
299617
299225
|
process.exit(0);
|
|
299618
299226
|
};
|
|
299619
299227
|
process.on('SIGINT', sig => {
|
|
@@ -300502,6 +300110,9 @@ class CLI {
|
|
|
300502
300110
|
.option('--whatsapp', 'Enable WhatsApp webhook runner (uses WHATSAPP_ACCESS_TOKEN)')
|
|
300503
300111
|
.option('--teams', 'Enable Microsoft Teams webhook runner (uses TEAMS_APP_ID)')
|
|
300504
300112
|
.option('--a2a', 'Enable A2A Agent Protocol server mode')
|
|
300113
|
+
.option('--mcp', 'Enable MCP HTTP server runner (composable, requires --mcp-auth-token)')
|
|
300114
|
+
.option('--mcp-port <port>', 'Port for MCP HTTP server (default: 8080)', value => parseInt(value, 10))
|
|
300115
|
+
.option('--mcp-auth-token <token>', 'Bearer token for MCP HTTP server authentication')
|
|
300505
300116
|
.option('-c, --check <type>', 'Specify check type (can be used multiple times)', this.collectChecks, [])
|
|
300506
300117
|
.option('-o, --output <format>', 'Output format (table, json, markdown, sarif)', 'table')
|
|
300507
300118
|
.option('--output-file <path>', 'Write formatted output to a file instead of stdout')
|
|
@@ -300639,6 +300250,9 @@ class CLI {
|
|
|
300639
300250
|
whatsapp: Boolean(options.whatsapp),
|
|
300640
300251
|
teams: Boolean(options.teams),
|
|
300641
300252
|
a2a: Boolean(options.a2a),
|
|
300253
|
+
mcp: Boolean(options.mcp),
|
|
300254
|
+
mcpPort: options.mcpPort,
|
|
300255
|
+
mcpAuthToken: options.mcpAuthToken,
|
|
300642
300256
|
tui: Boolean(options.tui),
|
|
300643
300257
|
keepWorkspace: Boolean(options.keepWorkspace),
|
|
300644
300258
|
workspacePath: options.workspacePath,
|
|
@@ -300784,7 +300398,9 @@ Examples:
|
|
|
300784
300398
|
visor --check all --fail-fast --output json # Stop on first failure
|
|
300785
300399
|
visor --tags local,fast --output table # Run checks tagged as 'local' or 'fast'
|
|
300786
300400
|
visor --exclude-tags slow,experimental --output json # Skip checks tagged as 'slow' or 'experimental'
|
|
300787
|
-
visor --tags security --exclude-tags slow # Run security checks but skip slow ones
|
|
300401
|
+
visor --tags security --exclude-tags slow # Run security checks but skip slow ones
|
|
300402
|
+
visor --slack --mcp --mcp-auth-token secret # Run Slack + MCP HTTP in parallel
|
|
300403
|
+
visor --slack --a2a --telegram # Run multiple frontends in parallel`;
|
|
300788
300404
|
}
|
|
300789
300405
|
/**
|
|
300790
300406
|
* Display help
|
|
@@ -302566,6 +302182,7 @@ class ConfigManager {
|
|
|
302566
302182
|
const allowedTopLevelKeys = new Set([
|
|
302567
302183
|
'tests',
|
|
302568
302184
|
'slack',
|
|
302185
|
+
'mcp_server',
|
|
302569
302186
|
'sandboxes',
|
|
302570
302187
|
'sandbox',
|
|
302571
302188
|
'sandbox_defaults',
|
|
@@ -305334,6 +304951,7 @@ const adapter_1 = __nccwpck_require__(8611);
|
|
|
305334
304951
|
const crypto_1 = __nccwpck_require__(76982);
|
|
305335
304952
|
const workspace_manager_1 = __nccwpck_require__(6134);
|
|
305336
304953
|
class EmailPollingRunner {
|
|
304954
|
+
name = 'email';
|
|
305337
304955
|
client;
|
|
305338
304956
|
adapter;
|
|
305339
304957
|
engine;
|
|
@@ -308595,9 +308213,12 @@ class GitHubFrontend {
|
|
|
308595
308213
|
? failureResults.some((r) => r && r.failed)
|
|
308596
308214
|
: false;
|
|
308597
308215
|
const group = this.getGroupForCheck(ctx, ev.checkId);
|
|
308598
|
-
// Extract text from JSON-like content if template didn't unwrap it properly
|
|
308216
|
+
// Extract text from JSON-like content if template didn't unwrap it properly.
|
|
308217
|
+
// Fall back to output.text / output.response when template rendering failed
|
|
308218
|
+
// (e.g., template file not found in ncc bundle) — this is the primary path
|
|
308219
|
+
// for schema-based checks like comment-assistant / issue-assistant.
|
|
308599
308220
|
const rawContent = ev?.result?.content;
|
|
308600
|
-
const extractedContent = (0, json_text_extractor_1.extractTextFromJson)(rawContent);
|
|
308221
|
+
const extractedContent = (0, json_text_extractor_1.extractTextFromJson)(rawContent) ?? (0, json_text_extractor_1.extractTextFromJson)(ev?.result?.output);
|
|
308601
308222
|
this.upsertSectionState(group, ev.checkId, {
|
|
308602
308223
|
status: 'completed',
|
|
308603
308224
|
conclusion: failed ? 'failure' : 'success',
|
|
@@ -318484,13 +318105,13 @@ function configureLoggerFromCli(options) {
|
|
|
318484
318105
|
* MCP Server for Visor
|
|
318485
318106
|
*
|
|
318486
318107
|
* Exposes Visor workflows as MCP tools, allowing Claude Code and other
|
|
318487
|
-
* MCP clients to execute workflows programmatically via stdio transport.
|
|
318108
|
+
* MCP clients to execute workflows programmatically via stdio or HTTP transport.
|
|
318488
318109
|
*
|
|
318489
318110
|
* Usage:
|
|
318490
|
-
* # Generic mode - workflow is a tool parameter
|
|
318111
|
+
* # Generic mode - workflow is a tool parameter (stdio)
|
|
318491
318112
|
* visor mcp-server
|
|
318492
318113
|
*
|
|
318493
|
-
* # Fixed workflow mode - workflow is pre-configured
|
|
318114
|
+
* # Fixed workflow mode - workflow is pre-configured (stdio)
|
|
318494
318115
|
* visor mcp-server --config defaults/code-review.yaml
|
|
318495
318116
|
*
|
|
318496
318117
|
* # Custom tool name and description
|
|
@@ -318498,6 +318119,17 @@ function configureLoggerFromCli(options) {
|
|
|
318498
318119
|
* --mcp-tool-name "code_review" \
|
|
318499
318120
|
* --mcp-tool-description "Run a code review for current uncommitted changes"
|
|
318500
318121
|
*
|
|
318122
|
+
* # Remote HTTP mode with Bearer token auth
|
|
318123
|
+
* visor mcp-server --transport http --port 8080 --auth-token "my-secret"
|
|
318124
|
+
*
|
|
318125
|
+
* # HTTP with token from environment variable
|
|
318126
|
+
* VISOR_MCP_TOKEN=secret visor mcp-server --transport http --auth-token-env VISOR_MCP_TOKEN
|
|
318127
|
+
*
|
|
318128
|
+
* # HTTPS with TLS certificates
|
|
318129
|
+
* visor mcp-server --transport http --port 443 \
|
|
318130
|
+
* --tls-cert /path/to/cert.pem --tls-key /path/to/key.pem \
|
|
318131
|
+
* --auth-token-env VISOR_MCP_TOKEN
|
|
318132
|
+
*
|
|
318501
318133
|
* Claude Code config example (~/.claude/claude_desktop_config.json):
|
|
318502
318134
|
* {
|
|
318503
318135
|
* "mcpServers": {
|
|
@@ -318547,13 +318179,19 @@ exports.resolveWorkflowPath = resolveWorkflowPath;
|
|
|
318547
318179
|
exports.formatResults = formatResults;
|
|
318548
318180
|
exports.executeWorkflow = executeWorkflow;
|
|
318549
318181
|
exports.executeFixedWorkflow = executeFixedWorkflow;
|
|
318182
|
+
exports.validateBearerToken = validateBearerToken;
|
|
318183
|
+
exports.createHttpMcpServer = createHttpMcpServer;
|
|
318550
318184
|
exports.startMcpServer = startMcpServer;
|
|
318551
318185
|
const mcp_js_1 = __nccwpck_require__(23886);
|
|
318552
318186
|
const stdio_js_1 = __nccwpck_require__(64239);
|
|
318187
|
+
const streamableHttp_js_1 = __nccwpck_require__(1048);
|
|
318553
318188
|
const zod_1 = __nccwpck_require__(50924);
|
|
318554
318189
|
const sdk_1 = __nccwpck_require__(1091);
|
|
318555
318190
|
const path = __importStar(__nccwpck_require__(16928));
|
|
318556
318191
|
const fs = __importStar(__nccwpck_require__(79896));
|
|
318192
|
+
const http = __importStar(__nccwpck_require__(58611));
|
|
318193
|
+
const https = __importStar(__nccwpck_require__(65692));
|
|
318194
|
+
const crypto = __importStar(__nccwpck_require__(76982));
|
|
318557
318195
|
/**
|
|
318558
318196
|
* Available default workflows bundled with Visor.
|
|
318559
318197
|
*/
|
|
@@ -318563,12 +318201,31 @@ exports.DEFAULT_WORKFLOWS = [
|
|
|
318563
318201
|
'task-refinement',
|
|
318564
318202
|
'code-refiner',
|
|
318565
318203
|
];
|
|
318204
|
+
/**
|
|
318205
|
+
* Resolve the Visor version from package.json or environment.
|
|
318206
|
+
*/
|
|
318207
|
+
function getVisorVersion() {
|
|
318208
|
+
if (process.env.VISOR_VERSION)
|
|
318209
|
+
return process.env.VISOR_VERSION;
|
|
318210
|
+
try {
|
|
318211
|
+
const pkgPath = path.join(__dirname, '..', 'package.json');
|
|
318212
|
+
if (fs.existsSync(pkgPath)) {
|
|
318213
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
318214
|
+
if (pkg.version)
|
|
318215
|
+
return pkg.version;
|
|
318216
|
+
}
|
|
318217
|
+
}
|
|
318218
|
+
catch { }
|
|
318219
|
+
return 'unknown';
|
|
318220
|
+
}
|
|
318566
318221
|
/**
|
|
318567
318222
|
* Server metadata for MCP protocol.
|
|
318568
318223
|
*/
|
|
318569
318224
|
exports.SERVER_INFO = {
|
|
318570
318225
|
name: 'visor',
|
|
318571
|
-
version
|
|
318226
|
+
get version() {
|
|
318227
|
+
return getVisorVersion();
|
|
318228
|
+
},
|
|
318572
318229
|
description: 'Visor is an AI-powered code review and workflow automation tool. ' +
|
|
318573
318230
|
'It analyzes code for security vulnerabilities, performance issues, architectural problems, ' +
|
|
318574
318231
|
'and style violations. Visor can also orchestrate complex multi-step workflows with AI agents, ' +
|
|
@@ -318882,15 +318539,233 @@ async function executeFixedWorkflow(args, workflowPath) {
|
|
|
318882
318539
|
};
|
|
318883
318540
|
}
|
|
318884
318541
|
}
|
|
318542
|
+
/**
|
|
318543
|
+
* Validate a Bearer token from an HTTP request using timing-safe comparison.
|
|
318544
|
+
*/
|
|
318545
|
+
function validateBearerToken(req, expectedToken) {
|
|
318546
|
+
const header = req.headers['authorization'];
|
|
318547
|
+
if (!header || !header.startsWith('Bearer '))
|
|
318548
|
+
return false;
|
|
318549
|
+
const token = header.slice(7);
|
|
318550
|
+
if (token.length !== expectedToken.length)
|
|
318551
|
+
return false;
|
|
318552
|
+
try {
|
|
318553
|
+
return crypto.timingSafeEqual(Buffer.from(token), Buffer.from(expectedToken));
|
|
318554
|
+
}
|
|
318555
|
+
catch {
|
|
318556
|
+
return false;
|
|
318557
|
+
}
|
|
318558
|
+
}
|
|
318559
|
+
/**
|
|
318560
|
+
* Read and parse JSON body from an HTTP request.
|
|
318561
|
+
*/
|
|
318562
|
+
function readBody(req) {
|
|
318563
|
+
return new Promise((resolve, reject) => {
|
|
318564
|
+
let data = '';
|
|
318565
|
+
req.on('data', (chunk) => (data += chunk));
|
|
318566
|
+
req.on('end', () => {
|
|
318567
|
+
if (!data.trim()) {
|
|
318568
|
+
resolve(undefined);
|
|
318569
|
+
return;
|
|
318570
|
+
}
|
|
318571
|
+
try {
|
|
318572
|
+
resolve(JSON.parse(data));
|
|
318573
|
+
}
|
|
318574
|
+
catch {
|
|
318575
|
+
reject(new Error('Invalid JSON'));
|
|
318576
|
+
}
|
|
318577
|
+
});
|
|
318578
|
+
req.on('error', reject);
|
|
318579
|
+
});
|
|
318580
|
+
}
|
|
318581
|
+
/**
|
|
318582
|
+
* Create and start an MCP HTTP/HTTPS server, returning a handle for lifecycle control.
|
|
318583
|
+
*
|
|
318584
|
+
* Unlike startHttpMcpServer (used internally by startMcpServer), this function
|
|
318585
|
+
* does NOT register process signal handlers — the caller is responsible for
|
|
318586
|
+
* calling handle.close() during shutdown.
|
|
318587
|
+
*/
|
|
318588
|
+
async function createHttpMcpServer(options) {
|
|
318589
|
+
// If fixed workflow mode, validate config path at startup
|
|
318590
|
+
let resolvedWorkflowPath;
|
|
318591
|
+
if (options.configPath) {
|
|
318592
|
+
resolvedWorkflowPath = resolveWorkflowPath(options.configPath);
|
|
318593
|
+
}
|
|
318594
|
+
const server = new mcp_js_1.McpServer({ name: exports.SERVER_INFO.name, version: exports.SERVER_INFO.version }, { capabilities: { tools: {} } });
|
|
318595
|
+
const toolName = options.toolName || 'run_workflow';
|
|
318596
|
+
const toolDescription = options.toolDescription || exports.RUN_WORKFLOW_DESCRIPTION;
|
|
318597
|
+
if (resolvedWorkflowPath) {
|
|
318598
|
+
server.tool(toolName, toolDescription, {
|
|
318599
|
+
message: exports.FixedWorkflowSchema.shape.message,
|
|
318600
|
+
checks: exports.FixedWorkflowSchema.shape.checks,
|
|
318601
|
+
format: exports.FixedWorkflowSchema.shape.format,
|
|
318602
|
+
}, async (args) => executeFixedWorkflow(args, resolvedWorkflowPath));
|
|
318603
|
+
}
|
|
318604
|
+
else {
|
|
318605
|
+
server.tool(toolName, toolDescription, {
|
|
318606
|
+
workflow: exports.RunWorkflowSchema.shape.workflow,
|
|
318607
|
+
message: exports.RunWorkflowSchema.shape.message,
|
|
318608
|
+
checks: exports.RunWorkflowSchema.shape.checks,
|
|
318609
|
+
format: exports.RunWorkflowSchema.shape.format,
|
|
318610
|
+
}, async (args) => executeWorkflow(args));
|
|
318611
|
+
}
|
|
318612
|
+
return startHttpMcpServerInternal(server, options);
|
|
318613
|
+
}
|
|
318614
|
+
/**
|
|
318615
|
+
* Start the MCP server over HTTP/HTTPS with StreamableHTTPServerTransport.
|
|
318616
|
+
* Returns a handle for non-blocking shutdown.
|
|
318617
|
+
*/
|
|
318618
|
+
async function startHttpMcpServerInternal(server, options) {
|
|
318619
|
+
const port = options.port || 8080;
|
|
318620
|
+
const host = options.host || '0.0.0.0';
|
|
318621
|
+
// Resolve auth token
|
|
318622
|
+
const authToken = options.authToken || (options.authTokenEnv ? process.env[options.authTokenEnv] : undefined);
|
|
318623
|
+
if (!authToken) {
|
|
318624
|
+
throw new Error('HTTP transport requires --auth-token or --auth-token-env for security. ' +
|
|
318625
|
+
'Refusing to start an unauthenticated remote MCP endpoint.');
|
|
318626
|
+
}
|
|
318627
|
+
// Per-session transport map
|
|
318628
|
+
const transports = new Map();
|
|
318629
|
+
const handleRequest = async (req, res) => {
|
|
318630
|
+
try {
|
|
318631
|
+
await handleRequestInner(req, res);
|
|
318632
|
+
}
|
|
318633
|
+
catch (err) {
|
|
318634
|
+
console.error(`[MCP] Request handler error: ${err}`);
|
|
318635
|
+
if (!res.headersSent) {
|
|
318636
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
318637
|
+
res.end(JSON.stringify({ error: 'Internal server error' }));
|
|
318638
|
+
}
|
|
318639
|
+
}
|
|
318640
|
+
};
|
|
318641
|
+
const handleRequestInner = async (req, res) => {
|
|
318642
|
+
// CORS preflight
|
|
318643
|
+
if (req.method === 'OPTIONS') {
|
|
318644
|
+
res.writeHead(204, {
|
|
318645
|
+
'Access-Control-Allow-Origin': '*',
|
|
318646
|
+
'Access-Control-Allow-Methods': 'GET, POST, DELETE, OPTIONS',
|
|
318647
|
+
'Access-Control-Allow-Headers': 'Content-Type, Authorization, mcp-session-id',
|
|
318648
|
+
});
|
|
318649
|
+
res.end();
|
|
318650
|
+
return;
|
|
318651
|
+
}
|
|
318652
|
+
// Auth check on all requests (per MCP spec → OAuth 2.1 § 5.3 → RFC 6750 § 3)
|
|
318653
|
+
if (!validateBearerToken(req, authToken)) {
|
|
318654
|
+
const hasAuthHeader = !!req.headers['authorization'];
|
|
318655
|
+
// RFC 6750 §3.1: invalid_token when a token is present but wrong;
|
|
318656
|
+
// omit error param when no credentials are provided at all.
|
|
318657
|
+
const wwwAuth = hasAuthHeader
|
|
318658
|
+
? 'Bearer error="invalid_token", error_description="The access token is invalid or expired"'
|
|
318659
|
+
: 'Bearer';
|
|
318660
|
+
res.writeHead(401, {
|
|
318661
|
+
'WWW-Authenticate': wwwAuth,
|
|
318662
|
+
'Content-Type': 'application/json',
|
|
318663
|
+
});
|
|
318664
|
+
res.end(JSON.stringify({
|
|
318665
|
+
error: hasAuthHeader ? 'invalid_token' : 'unauthorized',
|
|
318666
|
+
error_description: hasAuthHeader
|
|
318667
|
+
? 'The access token is invalid or expired'
|
|
318668
|
+
: 'Authentication required. Provide a Bearer token in the Authorization header.',
|
|
318669
|
+
}));
|
|
318670
|
+
return;
|
|
318671
|
+
}
|
|
318672
|
+
// Only serve /mcp endpoint
|
|
318673
|
+
const url = new URL(req.url || '/', `http://${req.headers.host || 'localhost'}`);
|
|
318674
|
+
if (url.pathname !== '/mcp') {
|
|
318675
|
+
res.writeHead(404);
|
|
318676
|
+
res.end('Not found');
|
|
318677
|
+
return;
|
|
318678
|
+
}
|
|
318679
|
+
const sessionId = req.headers['mcp-session-id'];
|
|
318680
|
+
if (req.method === 'POST' && !sessionId) {
|
|
318681
|
+
// New session — sessionId is assigned during handleRequest (not connect)
|
|
318682
|
+
const transport = new streamableHttp_js_1.StreamableHTTPServerTransport({
|
|
318683
|
+
sessionIdGenerator: () => crypto.randomUUID(),
|
|
318684
|
+
});
|
|
318685
|
+
transport.onclose = () => {
|
|
318686
|
+
if (transport.sessionId) {
|
|
318687
|
+
console.error(`[MCP] Session closed: ${transport.sessionId}`);
|
|
318688
|
+
transports.delete(transport.sessionId);
|
|
318689
|
+
}
|
|
318690
|
+
};
|
|
318691
|
+
await server.connect(transport);
|
|
318692
|
+
const body = await readBody(req);
|
|
318693
|
+
await transport.handleRequest(req, res, body);
|
|
318694
|
+
if (transport.sessionId) {
|
|
318695
|
+
transports.set(transport.sessionId, transport);
|
|
318696
|
+
console.error(`[MCP] New session created: ${transport.sessionId}`);
|
|
318697
|
+
}
|
|
318698
|
+
return;
|
|
318699
|
+
}
|
|
318700
|
+
if (sessionId) {
|
|
318701
|
+
const transport = transports.get(sessionId);
|
|
318702
|
+
if (!transport) {
|
|
318703
|
+
console.error(`[MCP] Session ${sessionId} not found, active: [${[...transports.keys()].join(', ')}]`);
|
|
318704
|
+
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
318705
|
+
res.end(JSON.stringify({ error: 'Session not found' }));
|
|
318706
|
+
return;
|
|
318707
|
+
}
|
|
318708
|
+
if (req.method === 'DELETE') {
|
|
318709
|
+
await transport.handleRequest(req, res);
|
|
318710
|
+
return;
|
|
318711
|
+
}
|
|
318712
|
+
const body = await readBody(req);
|
|
318713
|
+
await transport.handleRequest(req, res, body);
|
|
318714
|
+
return;
|
|
318715
|
+
}
|
|
318716
|
+
// GET without session (standalone SSE stream)
|
|
318717
|
+
if (req.method === 'GET') {
|
|
318718
|
+
const transport = new streamableHttp_js_1.StreamableHTTPServerTransport({
|
|
318719
|
+
sessionIdGenerator: () => crypto.randomUUID(),
|
|
318720
|
+
});
|
|
318721
|
+
transport.onclose = () => {
|
|
318722
|
+
if (transport.sessionId)
|
|
318723
|
+
transports.delete(transport.sessionId);
|
|
318724
|
+
};
|
|
318725
|
+
await server.connect(transport);
|
|
318726
|
+
if (transport.sessionId)
|
|
318727
|
+
transports.set(transport.sessionId, transport);
|
|
318728
|
+
await transport.handleRequest(req, res);
|
|
318729
|
+
return;
|
|
318730
|
+
}
|
|
318731
|
+
res.writeHead(405);
|
|
318732
|
+
res.end('Method not allowed');
|
|
318733
|
+
};
|
|
318734
|
+
// Create HTTP or HTTPS server
|
|
318735
|
+
let httpServer;
|
|
318736
|
+
if (options.tlsCert && options.tlsKey) {
|
|
318737
|
+
const cert = fs.readFileSync(options.tlsCert);
|
|
318738
|
+
const key = fs.readFileSync(options.tlsKey);
|
|
318739
|
+
httpServer = https.createServer({ cert, key }, handleRequest);
|
|
318740
|
+
console.error(`Visor MCP server (HTTPS) listening on ${host}:${port}`);
|
|
318741
|
+
}
|
|
318742
|
+
else {
|
|
318743
|
+
httpServer = http.createServer(handleRequest);
|
|
318744
|
+
console.error(`Visor MCP server (HTTP) listening on ${host}:${port}`);
|
|
318745
|
+
if (host !== '127.0.0.1' && host !== 'localhost') {
|
|
318746
|
+
console.error('⚠️ WARNING: Running without TLS on a non-localhost address. Use --tls-cert and --tls-key for production.');
|
|
318747
|
+
}
|
|
318748
|
+
}
|
|
318749
|
+
httpServer.listen(port, host);
|
|
318750
|
+
return {
|
|
318751
|
+
close() {
|
|
318752
|
+
console.error('Shutting down MCP server...');
|
|
318753
|
+
for (const transport of transports.values()) {
|
|
318754
|
+
transport.close();
|
|
318755
|
+
}
|
|
318756
|
+
httpServer.close();
|
|
318757
|
+
},
|
|
318758
|
+
};
|
|
318759
|
+
}
|
|
318885
318760
|
/**
|
|
318886
318761
|
* Start the MCP server with Visor tools.
|
|
318887
318762
|
*
|
|
318888
318763
|
* The server exposes the following tools:
|
|
318889
318764
|
* - run_workflow (or custom name): Execute a Visor workflow and return results
|
|
318890
318765
|
*
|
|
318891
|
-
*
|
|
318766
|
+
* Supports stdio (default) and HTTP transports.
|
|
318892
318767
|
*
|
|
318893
|
-
* @param options - Optional configuration for fixed workflow mode
|
|
318768
|
+
* @param options - Optional configuration for fixed workflow mode and transport
|
|
318894
318769
|
*/
|
|
318895
318770
|
async function startMcpServer(options = {}) {
|
|
318896
318771
|
try {
|
|
@@ -318934,9 +318809,18 @@ async function startMcpServer(options = {}) {
|
|
|
318934
318809
|
});
|
|
318935
318810
|
console.error('Visor MCP server started');
|
|
318936
318811
|
}
|
|
318937
|
-
// Connect via
|
|
318938
|
-
|
|
318939
|
-
|
|
318812
|
+
// Connect via selected transport
|
|
318813
|
+
if (options.transport === 'http') {
|
|
318814
|
+
const handle = await startHttpMcpServerInternal(server, options);
|
|
318815
|
+
// Register signal handlers for standalone mode (visor mcp-server subcommand)
|
|
318816
|
+
const shutdown = () => handle.close();
|
|
318817
|
+
process.on('SIGINT', shutdown);
|
|
318818
|
+
process.on('SIGTERM', shutdown);
|
|
318819
|
+
}
|
|
318820
|
+
else {
|
|
318821
|
+
const transport = new stdio_js_1.StdioServerTransport();
|
|
318822
|
+
await server.connect(transport);
|
|
318823
|
+
}
|
|
318940
318824
|
}
|
|
318941
318825
|
catch (error) {
|
|
318942
318826
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -331230,6 +331114,16 @@ class CustomToolsSSEServer {
|
|
|
331230
331114
|
const registry = SessionRegistry.getInstance();
|
|
331231
331115
|
const activeIds = registry.getActiveSessionIds();
|
|
331232
331116
|
for (const sid of activeIds) {
|
|
331117
|
+
// Skip the parent/caller session — it must wait for child tool
|
|
331118
|
+
// responses before winding down, otherwise it has empty history
|
|
331119
|
+
// and produces a generic timeout message instead of summarizing
|
|
331120
|
+
// the actual work done by child workflows.
|
|
331121
|
+
if (sid === this.sessionId) {
|
|
331122
|
+
if (this.debug) {
|
|
331123
|
+
logger_1.logger.debug(`[CustomToolsSSEServer:${this.sessionId}] Skipping parent session ${sid} during graceful stop`);
|
|
331124
|
+
}
|
|
331125
|
+
continue;
|
|
331126
|
+
}
|
|
331233
331127
|
const agent = registry.getSession(sid);
|
|
331234
331128
|
if (agent && typeof agent.triggerGracefulWindDown === 'function') {
|
|
331235
331129
|
agent.triggerGracefulWindDown();
|
|
@@ -333544,6 +333438,36 @@ class WorkflowCheckProvider extends check_provider_interface_1.CheckProvider {
|
|
|
333544
333438
|
}
|
|
333545
333439
|
}
|
|
333546
333440
|
}
|
|
333441
|
+
// Resolve `extends` on inline array items (e.g. skills defined directly in args).
|
|
333442
|
+
// loadConfig() already handles extends internally, but inline arrays bypass it.
|
|
333443
|
+
// This allows skills to use `extends: "visor://skills/..."` without loadConfig.
|
|
333444
|
+
for (const [key, value] of Object.entries(inputs)) {
|
|
333445
|
+
if (!Array.isArray(value))
|
|
333446
|
+
continue;
|
|
333447
|
+
let resolved = false;
|
|
333448
|
+
const resolvedArray = value.map((item) => {
|
|
333449
|
+
if (item &&
|
|
333450
|
+
typeof item === 'object' &&
|
|
333451
|
+
!Array.isArray(item) &&
|
|
333452
|
+
typeof item.extends === 'string') {
|
|
333453
|
+
try {
|
|
333454
|
+
const baseConfig = loadConfig(item.extends);
|
|
333455
|
+
const overrideObj = { ...item };
|
|
333456
|
+
delete overrideObj.extends;
|
|
333457
|
+
resolved = true;
|
|
333458
|
+
return deepMerge(baseConfig, overrideObj);
|
|
333459
|
+
}
|
|
333460
|
+
catch (err) {
|
|
333461
|
+
logger_1.logger.warn(`[WorkflowProvider] Failed to resolve extends '${item.extends}' in input '${key}': ${err}`);
|
|
333462
|
+
return item;
|
|
333463
|
+
}
|
|
333464
|
+
}
|
|
333465
|
+
return item;
|
|
333466
|
+
});
|
|
333467
|
+
if (resolved) {
|
|
333468
|
+
inputs[key] = resolvedArray;
|
|
333469
|
+
}
|
|
333470
|
+
}
|
|
333547
333471
|
// Debug: log all input keys and types for troubleshooting
|
|
333548
333472
|
const inputSummary = Object.entries(inputs)
|
|
333549
333473
|
.map(([k, v]) => `${k}:${Array.isArray(v) ? `array[${v.length}]` : typeof v}`)
|
|
@@ -334720,6 +334644,768 @@ class PRReviewer {
|
|
|
334720
334644
|
exports.PRReviewer = PRReviewer;
|
|
334721
334645
|
|
|
334722
334646
|
|
|
334647
|
+
/***/ }),
|
|
334648
|
+
|
|
334649
|
+
/***/ 31458:
|
|
334650
|
+
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
|
|
334651
|
+
|
|
334652
|
+
"use strict";
|
|
334653
|
+
|
|
334654
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
334655
|
+
if (k2 === undefined) k2 = k;
|
|
334656
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
334657
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
334658
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
334659
|
+
}
|
|
334660
|
+
Object.defineProperty(o, k2, desc);
|
|
334661
|
+
}) : (function(o, m, k, k2) {
|
|
334662
|
+
if (k2 === undefined) k2 = k;
|
|
334663
|
+
o[k2] = m[k];
|
|
334664
|
+
}));
|
|
334665
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
334666
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
334667
|
+
}) : function(o, v) {
|
|
334668
|
+
o["default"] = v;
|
|
334669
|
+
});
|
|
334670
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
334671
|
+
var ownKeys = function(o) {
|
|
334672
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
334673
|
+
var ar = [];
|
|
334674
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
334675
|
+
return ar;
|
|
334676
|
+
};
|
|
334677
|
+
return ownKeys(o);
|
|
334678
|
+
};
|
|
334679
|
+
return function (mod) {
|
|
334680
|
+
if (mod && mod.__esModule) return mod;
|
|
334681
|
+
var result = {};
|
|
334682
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
334683
|
+
__setModuleDefault(result, mod);
|
|
334684
|
+
return result;
|
|
334685
|
+
};
|
|
334686
|
+
})();
|
|
334687
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
334688
|
+
exports.McpServerRunner = void 0;
|
|
334689
|
+
const mcp_js_1 = __nccwpck_require__(23886);
|
|
334690
|
+
const streamableHttp_js_1 = __nccwpck_require__(1048);
|
|
334691
|
+
const zod_1 = __nccwpck_require__(50924);
|
|
334692
|
+
const http = __importStar(__nccwpck_require__(58611));
|
|
334693
|
+
const https = __importStar(__nccwpck_require__(65692));
|
|
334694
|
+
const fs = __importStar(__nccwpck_require__(79896));
|
|
334695
|
+
const crypto = __importStar(__nccwpck_require__(76982));
|
|
334696
|
+
const mcp_server_1 = __nccwpck_require__(93143);
|
|
334697
|
+
const trace_helpers_1 = __nccwpck_require__(75338);
|
|
334698
|
+
/**
|
|
334699
|
+
* Read and parse JSON body from an HTTP request.
|
|
334700
|
+
*/
|
|
334701
|
+
function readBody(req) {
|
|
334702
|
+
return new Promise((resolve, reject) => {
|
|
334703
|
+
let data = '';
|
|
334704
|
+
req.on('data', (chunk) => (data += chunk));
|
|
334705
|
+
req.on('end', () => {
|
|
334706
|
+
if (!data.trim()) {
|
|
334707
|
+
resolve(undefined);
|
|
334708
|
+
return;
|
|
334709
|
+
}
|
|
334710
|
+
try {
|
|
334711
|
+
resolve(JSON.parse(data));
|
|
334712
|
+
}
|
|
334713
|
+
catch {
|
|
334714
|
+
reject(new Error('Invalid JSON'));
|
|
334715
|
+
}
|
|
334716
|
+
});
|
|
334717
|
+
req.on('error', reject);
|
|
334718
|
+
});
|
|
334719
|
+
}
|
|
334720
|
+
/**
|
|
334721
|
+
* MCP Frontend Runner — exposes the Visor assistant as an MCP tool.
|
|
334722
|
+
*
|
|
334723
|
+
* Unlike the standalone `visor mcp-server` (which calls runChecks from the SDK),
|
|
334724
|
+
* this runner dispatches messages through the StateMachineExecutionEngine just like
|
|
334725
|
+
* the Slack/Telegram runners do. This means `{{ conversation.current.text }}` works,
|
|
334726
|
+
* the full workflow config is used, and responses flow back through the engine.
|
|
334727
|
+
*/
|
|
334728
|
+
class McpServerRunner {
|
|
334729
|
+
engine;
|
|
334730
|
+
cfg;
|
|
334731
|
+
options;
|
|
334732
|
+
name = 'mcp';
|
|
334733
|
+
httpServer = null;
|
|
334734
|
+
transports = new Map();
|
|
334735
|
+
taskStore;
|
|
334736
|
+
configPath;
|
|
334737
|
+
constructor(engine, cfg, options) {
|
|
334738
|
+
this.engine = engine;
|
|
334739
|
+
this.cfg = cfg;
|
|
334740
|
+
this.options = options;
|
|
334741
|
+
}
|
|
334742
|
+
async start() {
|
|
334743
|
+
const port = this.options.port || 8080;
|
|
334744
|
+
const host = this.options.host || '0.0.0.0';
|
|
334745
|
+
// Resolve auth token
|
|
334746
|
+
const authToken = this.options.authToken ||
|
|
334747
|
+
(this.options.authTokenEnv ? process.env[this.options.authTokenEnv] : undefined);
|
|
334748
|
+
if (!authToken) {
|
|
334749
|
+
throw new Error('MCP HTTP transport requires an auth token (--mcp-auth-token or VISOR_MCP_AUTH_TOKEN). ' +
|
|
334750
|
+
'Refusing to start an unauthenticated remote MCP endpoint.');
|
|
334751
|
+
}
|
|
334752
|
+
// Create MCP server with send_message tool
|
|
334753
|
+
const mcpServer = new mcp_js_1.McpServer({ name: mcp_server_1.SERVER_INFO.name, version: mcp_server_1.SERVER_INFO.version }, { capabilities: { tools: {} } });
|
|
334754
|
+
const toolName = this.options.toolName || 'send_message';
|
|
334755
|
+
const toolDescription = this.options.toolDescription ||
|
|
334756
|
+
'Send a message to the Visor assistant. The assistant will process your message ' +
|
|
334757
|
+
'through the configured workflow and return a response. Use this for conversations, ' +
|
|
334758
|
+
'questions, task requests, and any interaction with the assistant.';
|
|
334759
|
+
mcpServer.tool(toolName, toolDescription, {
|
|
334760
|
+
message: zod_1.z.string().describe('The message to send to the assistant.'),
|
|
334761
|
+
session_id: zod_1.z
|
|
334762
|
+
.string()
|
|
334763
|
+
.optional()
|
|
334764
|
+
.describe('Optional conversation session ID for maintaining context across messages. ' +
|
|
334765
|
+
'If omitted, a new session is created. Re-use the same session_id for follow-up messages.'),
|
|
334766
|
+
}, async (args) => {
|
|
334767
|
+
return this.handleMessage(args.message, args.session_id);
|
|
334768
|
+
});
|
|
334769
|
+
const { transports } = this;
|
|
334770
|
+
const handleRequest = async (req, res) => {
|
|
334771
|
+
try {
|
|
334772
|
+
// CORS preflight
|
|
334773
|
+
if (req.method === 'OPTIONS') {
|
|
334774
|
+
res.writeHead(204, {
|
|
334775
|
+
'Access-Control-Allow-Origin': '*',
|
|
334776
|
+
'Access-Control-Allow-Methods': 'GET, POST, DELETE, OPTIONS',
|
|
334777
|
+
'Access-Control-Allow-Headers': 'Content-Type, Authorization, mcp-session-id',
|
|
334778
|
+
});
|
|
334779
|
+
res.end();
|
|
334780
|
+
return;
|
|
334781
|
+
}
|
|
334782
|
+
// Auth check (per MCP spec → OAuth 2.1 § 5.3 → RFC 6750 § 3)
|
|
334783
|
+
if (!(0, mcp_server_1.validateBearerToken)(req, authToken)) {
|
|
334784
|
+
const hasAuthHeader = !!req.headers['authorization'];
|
|
334785
|
+
const wwwAuth = hasAuthHeader
|
|
334786
|
+
? 'Bearer error="invalid_token", error_description="The access token is invalid or expired"'
|
|
334787
|
+
: 'Bearer';
|
|
334788
|
+
res.writeHead(401, {
|
|
334789
|
+
'WWW-Authenticate': wwwAuth,
|
|
334790
|
+
'Content-Type': 'application/json',
|
|
334791
|
+
});
|
|
334792
|
+
res.end(JSON.stringify({
|
|
334793
|
+
error: hasAuthHeader ? 'invalid_token' : 'unauthorized',
|
|
334794
|
+
error_description: hasAuthHeader
|
|
334795
|
+
? 'The access token is invalid or expired'
|
|
334796
|
+
: 'Authentication required. Provide a Bearer token in the Authorization header.',
|
|
334797
|
+
}));
|
|
334798
|
+
return;
|
|
334799
|
+
}
|
|
334800
|
+
// Only serve /mcp endpoint
|
|
334801
|
+
const url = new URL(req.url || '/', `http://${req.headers.host || 'localhost'}`);
|
|
334802
|
+
if (url.pathname !== '/mcp') {
|
|
334803
|
+
res.writeHead(404);
|
|
334804
|
+
res.end('Not found');
|
|
334805
|
+
return;
|
|
334806
|
+
}
|
|
334807
|
+
const sessionId = req.headers['mcp-session-id'];
|
|
334808
|
+
if (req.method === 'POST' && !sessionId) {
|
|
334809
|
+
// New session
|
|
334810
|
+
const transport = new streamableHttp_js_1.StreamableHTTPServerTransport({
|
|
334811
|
+
sessionIdGenerator: () => crypto.randomUUID(),
|
|
334812
|
+
});
|
|
334813
|
+
transport.onclose = () => {
|
|
334814
|
+
if (transport.sessionId)
|
|
334815
|
+
transports.delete(transport.sessionId);
|
|
334816
|
+
};
|
|
334817
|
+
await mcpServer.connect(transport);
|
|
334818
|
+
const body = await readBody(req);
|
|
334819
|
+
await transport.handleRequest(req, res, body);
|
|
334820
|
+
if (transport.sessionId)
|
|
334821
|
+
transports.set(transport.sessionId, transport);
|
|
334822
|
+
return;
|
|
334823
|
+
}
|
|
334824
|
+
if (sessionId) {
|
|
334825
|
+
const transport = transports.get(sessionId);
|
|
334826
|
+
if (!transport) {
|
|
334827
|
+
if (req.method === 'DELETE') {
|
|
334828
|
+
// Nothing to close after restart; just acknowledge
|
|
334829
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
334830
|
+
res.end(JSON.stringify({ ok: true }));
|
|
334831
|
+
return;
|
|
334832
|
+
}
|
|
334833
|
+
// Session lost (e.g. server restart). Return 404 per MCP spec
|
|
334834
|
+
// so the client re-initializes with a fresh session. Also include
|
|
334835
|
+
// a JSON-RPC error response so clients that parse the body can
|
|
334836
|
+
// detect the "session expired" condition and auto-reconnect.
|
|
334837
|
+
const body = await readBody(req);
|
|
334838
|
+
const requestId = body?.id ?? null;
|
|
334839
|
+
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
334840
|
+
res.end(JSON.stringify({
|
|
334841
|
+
jsonrpc: '2.0',
|
|
334842
|
+
id: requestId,
|
|
334843
|
+
error: {
|
|
334844
|
+
code: -32000,
|
|
334845
|
+
message: 'Session expired. Please reconnect with a new session.',
|
|
334846
|
+
},
|
|
334847
|
+
}));
|
|
334848
|
+
return;
|
|
334849
|
+
}
|
|
334850
|
+
if (req.method === 'DELETE') {
|
|
334851
|
+
await transport.handleRequest(req, res);
|
|
334852
|
+
return;
|
|
334853
|
+
}
|
|
334854
|
+
const body = await readBody(req);
|
|
334855
|
+
await transport.handleRequest(req, res, body);
|
|
334856
|
+
return;
|
|
334857
|
+
}
|
|
334858
|
+
// GET without session (standalone SSE stream)
|
|
334859
|
+
if (req.method === 'GET') {
|
|
334860
|
+
const transport = new streamableHttp_js_1.StreamableHTTPServerTransport({
|
|
334861
|
+
sessionIdGenerator: () => crypto.randomUUID(),
|
|
334862
|
+
});
|
|
334863
|
+
transport.onclose = () => {
|
|
334864
|
+
if (transport.sessionId)
|
|
334865
|
+
transports.delete(transport.sessionId);
|
|
334866
|
+
};
|
|
334867
|
+
await mcpServer.connect(transport);
|
|
334868
|
+
await transport.handleRequest(req, res);
|
|
334869
|
+
if (transport.sessionId)
|
|
334870
|
+
transports.set(transport.sessionId, transport);
|
|
334871
|
+
return;
|
|
334872
|
+
}
|
|
334873
|
+
res.writeHead(405);
|
|
334874
|
+
res.end('Method not allowed');
|
|
334875
|
+
}
|
|
334876
|
+
catch (err) {
|
|
334877
|
+
console.error(`[MCP] Request handler error: ${err}`);
|
|
334878
|
+
if (!res.headersSent) {
|
|
334879
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
334880
|
+
res.end(JSON.stringify({ error: 'Internal server error' }));
|
|
334881
|
+
}
|
|
334882
|
+
}
|
|
334883
|
+
};
|
|
334884
|
+
// Create HTTP or HTTPS server
|
|
334885
|
+
if (this.options.tlsCert && this.options.tlsKey) {
|
|
334886
|
+
const cert = fs.readFileSync(this.options.tlsCert);
|
|
334887
|
+
const key = fs.readFileSync(this.options.tlsKey);
|
|
334888
|
+
this.httpServer = https.createServer({ cert, key }, handleRequest);
|
|
334889
|
+
console.error(`Visor MCP frontend (HTTPS) listening on ${host}:${port}`);
|
|
334890
|
+
}
|
|
334891
|
+
else {
|
|
334892
|
+
this.httpServer = http.createServer(handleRequest);
|
|
334893
|
+
console.error(`Visor MCP frontend (HTTP) listening on ${host}:${port}`);
|
|
334894
|
+
if (host !== '127.0.0.1' && host !== 'localhost') {
|
|
334895
|
+
console.error('⚠️ WARNING: Running without TLS on a non-localhost address. Use TLS for production.');
|
|
334896
|
+
}
|
|
334897
|
+
}
|
|
334898
|
+
this.httpServer.listen(port, host);
|
|
334899
|
+
}
|
|
334900
|
+
async stop() {
|
|
334901
|
+
for (const transport of this.transports.values()) {
|
|
334902
|
+
transport.close();
|
|
334903
|
+
}
|
|
334904
|
+
this.transports.clear();
|
|
334905
|
+
if (this.httpServer) {
|
|
334906
|
+
this.httpServer.close();
|
|
334907
|
+
this.httpServer = null;
|
|
334908
|
+
}
|
|
334909
|
+
}
|
|
334910
|
+
updateConfig(cfg) {
|
|
334911
|
+
this.cfg = cfg;
|
|
334912
|
+
}
|
|
334913
|
+
setTaskStore(store, configPath) {
|
|
334914
|
+
this.taskStore = store;
|
|
334915
|
+
this.configPath = configPath;
|
|
334916
|
+
}
|
|
334917
|
+
/**
|
|
334918
|
+
* Handle an incoming message by dispatching it through the engine,
|
|
334919
|
+
* following the same pattern as Slack/Telegram runners.
|
|
334920
|
+
*/
|
|
334921
|
+
async handleMessage(message, sessionId) {
|
|
334922
|
+
try {
|
|
334923
|
+
const { StateMachineExecutionEngine: SMEngine } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(39004)));
|
|
334924
|
+
const { createHash } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(76982)));
|
|
334925
|
+
// Create a dedicated engine for this run (same pattern as Slack)
|
|
334926
|
+
const runEngine = new SMEngine();
|
|
334927
|
+
// Propagate execution context from parent engine
|
|
334928
|
+
try {
|
|
334929
|
+
const parentCtx = this.engine.getExecutionContext?.() || {};
|
|
334930
|
+
const prevCtx = runEngine.getExecutionContext?.() || {};
|
|
334931
|
+
runEngine.setExecutionContext?.({
|
|
334932
|
+
...parentCtx,
|
|
334933
|
+
...prevCtx,
|
|
334934
|
+
});
|
|
334935
|
+
}
|
|
334936
|
+
catch { }
|
|
334937
|
+
// Build conversation context (same structure as Slack/Telegram)
|
|
334938
|
+
const convSessionId = sessionId || crypto.randomUUID();
|
|
334939
|
+
const now = Date.now();
|
|
334940
|
+
const conversationContext = {
|
|
334941
|
+
transport: 'mcp',
|
|
334942
|
+
thread: { id: convSessionId },
|
|
334943
|
+
current: {
|
|
334944
|
+
user: 'mcp-client',
|
|
334945
|
+
text: message,
|
|
334946
|
+
timestamp: now,
|
|
334947
|
+
},
|
|
334948
|
+
messages: [
|
|
334949
|
+
{
|
|
334950
|
+
role: 'user',
|
|
334951
|
+
text: message,
|
|
334952
|
+
timestamp: now,
|
|
334953
|
+
},
|
|
334954
|
+
],
|
|
334955
|
+
};
|
|
334956
|
+
// Build webhook payload (same pattern as Slack's payloadForContext)
|
|
334957
|
+
const endpoint = '/bots/mcp/message';
|
|
334958
|
+
const payload = {
|
|
334959
|
+
event: {
|
|
334960
|
+
type: 'message',
|
|
334961
|
+
text: message,
|
|
334962
|
+
user: 'mcp-client',
|
|
334963
|
+
timestamp: now,
|
|
334964
|
+
},
|
|
334965
|
+
mcp_conversation: conversationContext,
|
|
334966
|
+
};
|
|
334967
|
+
const webhookData = new Map();
|
|
334968
|
+
webhookData.set(endpoint, payload);
|
|
334969
|
+
// Get all checks from config
|
|
334970
|
+
const allChecks = Object.keys(this.cfg.checks || {});
|
|
334971
|
+
if (allChecks.length === 0) {
|
|
334972
|
+
return {
|
|
334973
|
+
content: [{ type: 'text', text: 'No checks configured in workflow.' }],
|
|
334974
|
+
isError: true,
|
|
334975
|
+
};
|
|
334976
|
+
}
|
|
334977
|
+
// Prepare config for run
|
|
334978
|
+
const cfgForRun = (() => {
|
|
334979
|
+
try {
|
|
334980
|
+
const cfg = JSON.parse(JSON.stringify(this.cfg));
|
|
334981
|
+
return cfg;
|
|
334982
|
+
}
|
|
334983
|
+
catch {
|
|
334984
|
+
return this.cfg;
|
|
334985
|
+
}
|
|
334986
|
+
})();
|
|
334987
|
+
// Derive stable workspace name from session
|
|
334988
|
+
const hash = createHash('sha256').update(convSessionId).digest('hex').slice(0, 8);
|
|
334989
|
+
if (!cfgForRun.workspace) {
|
|
334990
|
+
cfgForRun.workspace = {};
|
|
334991
|
+
}
|
|
334992
|
+
cfgForRun.workspace.name = `mcp-${hash}`;
|
|
334993
|
+
cfgForRun.workspace.cleanup_on_exit = false;
|
|
334994
|
+
// Execute through the engine, wrapped in OTel tracing
|
|
334995
|
+
const execFn = () => runEngine.executeChecks({
|
|
334996
|
+
checks: allChecks,
|
|
334997
|
+
showDetails: true,
|
|
334998
|
+
outputFormat: 'json',
|
|
334999
|
+
config: cfgForRun,
|
|
335000
|
+
webhookContext: { webhookData, eventType: 'manual' },
|
|
335001
|
+
debug: process.env.VISOR_DEBUG === 'true',
|
|
335002
|
+
});
|
|
335003
|
+
const result = await (0, trace_helpers_1.withVisorRun)({
|
|
335004
|
+
...(0, trace_helpers_1.getVisorRunAttributes)(),
|
|
335005
|
+
'visor.run.source': 'mcp',
|
|
335006
|
+
'mcp.session_id': convSessionId,
|
|
335007
|
+
'mcp.message_length': message.length,
|
|
335008
|
+
}, {
|
|
335009
|
+
source: 'mcp',
|
|
335010
|
+
workflowId: allChecks.join(','),
|
|
335011
|
+
}, async () => {
|
|
335012
|
+
if (this.taskStore) {
|
|
335013
|
+
const { trackExecution } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(7628)));
|
|
335014
|
+
return trackExecution({
|
|
335015
|
+
taskStore: this.taskStore,
|
|
335016
|
+
source: 'mcp',
|
|
335017
|
+
workflowId: allChecks.join(','),
|
|
335018
|
+
configPath: this.configPath,
|
|
335019
|
+
messageText: message,
|
|
335020
|
+
metadata: { mcp_session: convSessionId },
|
|
335021
|
+
}, execFn);
|
|
335022
|
+
}
|
|
335023
|
+
return execFn();
|
|
335024
|
+
});
|
|
335025
|
+
// Extract response text from results
|
|
335026
|
+
// trackExecution wraps the result in { task, result } — unwrap if needed
|
|
335027
|
+
const rawResult = result?.result ?? result;
|
|
335028
|
+
const responseText = this.extractResponseText(rawResult);
|
|
335029
|
+
return {
|
|
335030
|
+
content: [
|
|
335031
|
+
{
|
|
335032
|
+
type: 'text',
|
|
335033
|
+
text: responseText,
|
|
335034
|
+
},
|
|
335035
|
+
],
|
|
335036
|
+
};
|
|
335037
|
+
}
|
|
335038
|
+
catch (error) {
|
|
335039
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
335040
|
+
return {
|
|
335041
|
+
content: [{ type: 'text', text: `Error: ${errorMessage}` }],
|
|
335042
|
+
isError: true,
|
|
335043
|
+
};
|
|
335044
|
+
}
|
|
335045
|
+
}
|
|
335046
|
+
/**
|
|
335047
|
+
* Extract a human-readable response from engine execution results.
|
|
335048
|
+
*
|
|
335049
|
+
* The result from executeChecks() has this structure:
|
|
335050
|
+
* {
|
|
335051
|
+
* repositoryInfo, reviewSummary: { issues, history: Record<checkId, output[]> },
|
|
335052
|
+
* executionStatistics: { checks: [...], groupedResults: { group: CheckResult[] } },
|
|
335053
|
+
* checksExecuted: string[]
|
|
335054
|
+
* }
|
|
335055
|
+
*
|
|
335056
|
+
* The assistant response text is typically in:
|
|
335057
|
+
* 1. reviewSummary.history.<checkId>[last].text (output history from journal)
|
|
335058
|
+
* 2. executionStatistics.groupedResults.<group>[].output.text (grouped check results)
|
|
335059
|
+
*/
|
|
335060
|
+
extractResponseText(result) {
|
|
335061
|
+
if (!result)
|
|
335062
|
+
return 'No response from workflow.';
|
|
335063
|
+
// The output history (reviewSummary.history) contains outputs keyed by step ID.
|
|
335064
|
+
// For assistant workflows the steps are e.g. chat.route-intent, chat.build-config,
|
|
335065
|
+
// chat.generate-response. The final AI response is the LAST step that has a .text
|
|
335066
|
+
// field with substantial content (not a short routing label).
|
|
335067
|
+
const history = result?.reviewSummary?.history;
|
|
335068
|
+
if (history && typeof history === 'object') {
|
|
335069
|
+
// Collect all candidate text outputs, keeping the last (deepest) one
|
|
335070
|
+
let bestText = '';
|
|
335071
|
+
for (const [, outputs] of Object.entries(history)) {
|
|
335072
|
+
if (!Array.isArray(outputs))
|
|
335073
|
+
continue;
|
|
335074
|
+
for (const item of outputs) {
|
|
335075
|
+
const text = item?.text ?? item?.output?.text;
|
|
335076
|
+
if (typeof text === 'string' && text.length > bestText.length) {
|
|
335077
|
+
bestText = text;
|
|
335078
|
+
}
|
|
335079
|
+
}
|
|
335080
|
+
}
|
|
335081
|
+
if (bestText)
|
|
335082
|
+
return bestText;
|
|
335083
|
+
}
|
|
335084
|
+
// Grouped results from execution statistics
|
|
335085
|
+
const grouped = result?.executionStatistics?.groupedResults;
|
|
335086
|
+
if (grouped && typeof grouped === 'object') {
|
|
335087
|
+
let bestText = '';
|
|
335088
|
+
for (const checkResults of Object.values(grouped)) {
|
|
335089
|
+
if (!Array.isArray(checkResults))
|
|
335090
|
+
continue;
|
|
335091
|
+
for (const cr of checkResults) {
|
|
335092
|
+
const text = cr?.output?.text ??
|
|
335093
|
+
(typeof cr?.output === 'string' ? cr.output : null) ??
|
|
335094
|
+
(typeof cr?.content === 'string' && cr.content.trim() ? cr.content : null);
|
|
335095
|
+
if (typeof text === 'string' && text.length > bestText.length) {
|
|
335096
|
+
bestText = text;
|
|
335097
|
+
}
|
|
335098
|
+
}
|
|
335099
|
+
}
|
|
335100
|
+
if (bestText)
|
|
335101
|
+
return bestText;
|
|
335102
|
+
}
|
|
335103
|
+
// Direct properties on result
|
|
335104
|
+
if (result?.text)
|
|
335105
|
+
return String(result.text);
|
|
335106
|
+
if (result?.output?.text)
|
|
335107
|
+
return String(result.output.text);
|
|
335108
|
+
// Fallback: JSON dump (compact to avoid huge responses)
|
|
335109
|
+
try {
|
|
335110
|
+
const compact = history || grouped || result;
|
|
335111
|
+
return JSON.stringify(compact, null, 2);
|
|
335112
|
+
}
|
|
335113
|
+
catch {
|
|
335114
|
+
return 'Workflow completed but could not format response.';
|
|
335115
|
+
}
|
|
335116
|
+
}
|
|
335117
|
+
}
|
|
335118
|
+
exports.McpServerRunner = McpServerRunner;
|
|
335119
|
+
|
|
335120
|
+
|
|
335121
|
+
/***/ }),
|
|
335122
|
+
|
|
335123
|
+
/***/ 11866:
|
|
335124
|
+
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
|
|
335125
|
+
|
|
335126
|
+
"use strict";
|
|
335127
|
+
|
|
335128
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
335129
|
+
if (k2 === undefined) k2 = k;
|
|
335130
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
335131
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
335132
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
335133
|
+
}
|
|
335134
|
+
Object.defineProperty(o, k2, desc);
|
|
335135
|
+
}) : (function(o, m, k, k2) {
|
|
335136
|
+
if (k2 === undefined) k2 = k;
|
|
335137
|
+
o[k2] = m[k];
|
|
335138
|
+
}));
|
|
335139
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
335140
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
335141
|
+
}) : function(o, v) {
|
|
335142
|
+
o["default"] = v;
|
|
335143
|
+
});
|
|
335144
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
335145
|
+
var ownKeys = function(o) {
|
|
335146
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
335147
|
+
var ar = [];
|
|
335148
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
335149
|
+
return ar;
|
|
335150
|
+
};
|
|
335151
|
+
return ownKeys(o);
|
|
335152
|
+
};
|
|
335153
|
+
return function (mod) {
|
|
335154
|
+
if (mod && mod.__esModule) return mod;
|
|
335155
|
+
var result = {};
|
|
335156
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
335157
|
+
__setModuleDefault(result, mod);
|
|
335158
|
+
return result;
|
|
335159
|
+
};
|
|
335160
|
+
})();
|
|
335161
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
335162
|
+
exports.createRunner = createRunner;
|
|
335163
|
+
/**
|
|
335164
|
+
* Create a Runner instance by name.
|
|
335165
|
+
*
|
|
335166
|
+
* Each case encapsulates the config-extraction logic previously duplicated
|
|
335167
|
+
* in cli-main.ts (reading config sub-objects, env vars, defaults).
|
|
335168
|
+
*/
|
|
335169
|
+
async function createRunner(name, engine, config, options) {
|
|
335170
|
+
switch (name) {
|
|
335171
|
+
case 'slack': {
|
|
335172
|
+
const { SlackSocketRunner } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(45278)));
|
|
335173
|
+
const slackAny = config.slack || {};
|
|
335174
|
+
return new SlackSocketRunner(engine, config, {
|
|
335175
|
+
appToken: slackAny.app_token || process.env.SLACK_APP_TOKEN,
|
|
335176
|
+
endpoint: slackAny.endpoint || '/bots/slack/support',
|
|
335177
|
+
mentions: slackAny.mentions || 'direct',
|
|
335178
|
+
threads: slackAny.threads || 'any',
|
|
335179
|
+
channel_allowlist: Array.isArray(slackAny.channel_allowlist)
|
|
335180
|
+
? slackAny.channel_allowlist
|
|
335181
|
+
: [],
|
|
335182
|
+
});
|
|
335183
|
+
}
|
|
335184
|
+
case 'telegram': {
|
|
335185
|
+
const { TelegramPollingRunner } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(33519)));
|
|
335186
|
+
const telegramAny = config.telegram || {};
|
|
335187
|
+
return new TelegramPollingRunner(engine, config, {
|
|
335188
|
+
botToken: telegramAny.bot_token || process.env.TELEGRAM_BOT_TOKEN,
|
|
335189
|
+
pollingTimeout: telegramAny.polling_timeout || 30,
|
|
335190
|
+
chatAllowlist: telegramAny.chat_allowlist,
|
|
335191
|
+
requireMention: telegramAny.require_mention ?? true,
|
|
335192
|
+
workflow: telegramAny.workflow,
|
|
335193
|
+
});
|
|
335194
|
+
}
|
|
335195
|
+
case 'email': {
|
|
335196
|
+
const { EmailPollingRunner } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(66550)));
|
|
335197
|
+
const emailAny = config.email || {};
|
|
335198
|
+
return new EmailPollingRunner(engine, config, {
|
|
335199
|
+
receive: emailAny.receive || {},
|
|
335200
|
+
send: emailAny.send || {},
|
|
335201
|
+
allowlist: emailAny.allowlist,
|
|
335202
|
+
workflow: emailAny.workflow,
|
|
335203
|
+
});
|
|
335204
|
+
}
|
|
335205
|
+
case 'whatsapp': {
|
|
335206
|
+
const { WhatsAppWebhookRunner } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(21718)));
|
|
335207
|
+
const waAny = config.whatsapp || {};
|
|
335208
|
+
return new WhatsAppWebhookRunner(engine, config, {
|
|
335209
|
+
accessToken: waAny.access_token || process.env.WHATSAPP_ACCESS_TOKEN,
|
|
335210
|
+
phoneNumberId: waAny.phone_number_id || process.env.WHATSAPP_PHONE_NUMBER_ID,
|
|
335211
|
+
appSecret: waAny.app_secret || process.env.WHATSAPP_APP_SECRET,
|
|
335212
|
+
verifyToken: waAny.verify_token || process.env.WHATSAPP_VERIFY_TOKEN,
|
|
335213
|
+
apiVersion: waAny.api_version || 'v21.0',
|
|
335214
|
+
port: waAny.port || parseInt(process.env.WHATSAPP_WEBHOOK_PORT || '8443'),
|
|
335215
|
+
host: waAny.host || '0.0.0.0',
|
|
335216
|
+
phoneAllowlist: waAny.phone_allowlist,
|
|
335217
|
+
workflow: waAny.workflow,
|
|
335218
|
+
});
|
|
335219
|
+
}
|
|
335220
|
+
case 'teams': {
|
|
335221
|
+
const { TeamsWebhookRunner } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(86710)));
|
|
335222
|
+
const teamsAny = config.teams || {};
|
|
335223
|
+
return new TeamsWebhookRunner(engine, config, {
|
|
335224
|
+
appId: teamsAny.app_id || process.env.TEAMS_APP_ID,
|
|
335225
|
+
appPassword: teamsAny.app_password || process.env.TEAMS_APP_PASSWORD,
|
|
335226
|
+
tenantId: teamsAny.tenant_id || process.env.TEAMS_TENANT_ID,
|
|
335227
|
+
port: teamsAny.port || parseInt(process.env.TEAMS_WEBHOOK_PORT || '3978'),
|
|
335228
|
+
host: teamsAny.host || '0.0.0.0',
|
|
335229
|
+
userAllowlist: teamsAny.user_allowlist,
|
|
335230
|
+
workflow: teamsAny.workflow,
|
|
335231
|
+
});
|
|
335232
|
+
}
|
|
335233
|
+
case 'a2a': {
|
|
335234
|
+
const { A2AFrontend } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(75887)));
|
|
335235
|
+
const { EventBus } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(83864)));
|
|
335236
|
+
const { logger } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(86999)));
|
|
335237
|
+
const crypto = await Promise.resolve().then(() => __importStar(__nccwpck_require__(76982)));
|
|
335238
|
+
const agentConfig = config.agent_protocol;
|
|
335239
|
+
if (!agentConfig) {
|
|
335240
|
+
throw new Error('agent_protocol configuration is required for --a2a mode');
|
|
335241
|
+
}
|
|
335242
|
+
const frontend = new A2AFrontend(agentConfig);
|
|
335243
|
+
frontend.setEngine(engine);
|
|
335244
|
+
frontend.setVisorConfig(config);
|
|
335245
|
+
// Return a thin adapter that bridges A2AFrontend → Runner interface
|
|
335246
|
+
return {
|
|
335247
|
+
name: 'a2a',
|
|
335248
|
+
async start() {
|
|
335249
|
+
const eventBus = new EventBus();
|
|
335250
|
+
const ctx = {
|
|
335251
|
+
eventBus,
|
|
335252
|
+
logger,
|
|
335253
|
+
config,
|
|
335254
|
+
run: { runId: crypto.randomUUID() },
|
|
335255
|
+
engine,
|
|
335256
|
+
visorConfig: config,
|
|
335257
|
+
};
|
|
335258
|
+
await frontend.start(ctx);
|
|
335259
|
+
const port = agentConfig.port ?? 9000;
|
|
335260
|
+
const host = agentConfig.host ?? '0.0.0.0';
|
|
335261
|
+
console.log(`A2A server running on ${host}:${port}`);
|
|
335262
|
+
},
|
|
335263
|
+
async stop() {
|
|
335264
|
+
await frontend.stop();
|
|
335265
|
+
},
|
|
335266
|
+
updateConfig(cfg) {
|
|
335267
|
+
frontend.setVisorConfig(cfg);
|
|
335268
|
+
},
|
|
335269
|
+
setTaskStore(store, _configPath) {
|
|
335270
|
+
// A2AFrontend receives task store via constructor; update if possible
|
|
335271
|
+
frontend._taskStore = store;
|
|
335272
|
+
},
|
|
335273
|
+
};
|
|
335274
|
+
}
|
|
335275
|
+
case 'mcp': {
|
|
335276
|
+
const { McpServerRunner } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(31458)));
|
|
335277
|
+
const mcpAny = config.mcp_server || {};
|
|
335278
|
+
return new McpServerRunner(engine, config, {
|
|
335279
|
+
port: options.mcpPort ||
|
|
335280
|
+
mcpAny.port ||
|
|
335281
|
+
(process.env.VISOR_MCP_PORT ? parseInt(process.env.VISOR_MCP_PORT) : 8080),
|
|
335282
|
+
host: mcpAny.host || process.env.VISOR_MCP_HOST || '0.0.0.0',
|
|
335283
|
+
authToken: options.mcpAuthToken || mcpAny.auth_token || process.env.VISOR_MCP_AUTH_TOKEN,
|
|
335284
|
+
authTokenEnv: mcpAny.auth_token_env,
|
|
335285
|
+
tlsCert: mcpAny.tls_cert || process.env.VISOR_MCP_TLS_CERT,
|
|
335286
|
+
tlsKey: mcpAny.tls_key || process.env.VISOR_MCP_TLS_KEY,
|
|
335287
|
+
toolName: mcpAny.tool_name || process.env.VISOR_MCP_TOOL_NAME,
|
|
335288
|
+
toolDescription: mcpAny.tool_description || process.env.VISOR_MCP_TOOL_DESCRIPTION,
|
|
335289
|
+
});
|
|
335290
|
+
}
|
|
335291
|
+
default:
|
|
335292
|
+
throw new Error(`Unknown runner type: "${name}"`);
|
|
335293
|
+
}
|
|
335294
|
+
}
|
|
335295
|
+
|
|
335296
|
+
|
|
335297
|
+
/***/ }),
|
|
335298
|
+
|
|
335299
|
+
/***/ 89736:
|
|
335300
|
+
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
335301
|
+
|
|
335302
|
+
"use strict";
|
|
335303
|
+
|
|
335304
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
335305
|
+
exports.RunnerHost = void 0;
|
|
335306
|
+
const logger_1 = __nccwpck_require__(86999);
|
|
335307
|
+
/**
|
|
335308
|
+
* Orchestrates the lifecycle of multiple Runner instances running in parallel.
|
|
335309
|
+
*
|
|
335310
|
+
* Handles start/stop ordering, config broadcast, and shared task-store propagation.
|
|
335311
|
+
*/
|
|
335312
|
+
class RunnerHost {
|
|
335313
|
+
runners = [];
|
|
335314
|
+
/** Register a runner to be managed by this host. */
|
|
335315
|
+
addRunner(runner) {
|
|
335316
|
+
this.runners.push(runner);
|
|
335317
|
+
}
|
|
335318
|
+
/** Return the list of registered runners. */
|
|
335319
|
+
getRunners() {
|
|
335320
|
+
return this.runners;
|
|
335321
|
+
}
|
|
335322
|
+
/**
|
|
335323
|
+
* Start all registered runners concurrently.
|
|
335324
|
+
* If any runner fails to start, previously-started runners are stopped.
|
|
335325
|
+
*/
|
|
335326
|
+
async startAll() {
|
|
335327
|
+
const started = [];
|
|
335328
|
+
const results = await Promise.allSettled(this.runners.map(async (runner) => {
|
|
335329
|
+
await runner.start();
|
|
335330
|
+
started.push(runner);
|
|
335331
|
+
}));
|
|
335332
|
+
const failures = results.filter(r => r.status === 'rejected');
|
|
335333
|
+
if (failures.length > 0) {
|
|
335334
|
+
// Rollback: stop successfully-started runners
|
|
335335
|
+
await Promise.allSettled(started.map(r => r.stop()));
|
|
335336
|
+
const msgs = failures.map(f => f.reason?.message ?? String(f.reason));
|
|
335337
|
+
throw new Error(`Failed to start runner(s): ${msgs.join('; ')}`);
|
|
335338
|
+
}
|
|
335339
|
+
}
|
|
335340
|
+
/**
|
|
335341
|
+
* Stop all registered runners concurrently.
|
|
335342
|
+
* Tolerates individual stop failures (logs warnings).
|
|
335343
|
+
*/
|
|
335344
|
+
async stopAll() {
|
|
335345
|
+
const results = await Promise.allSettled(this.runners.map(r => r.stop()));
|
|
335346
|
+
for (let i = 0; i < results.length; i++) {
|
|
335347
|
+
if (results[i].status === 'rejected') {
|
|
335348
|
+
const reason = results[i].reason;
|
|
335349
|
+
logger_1.logger.warn(`[RunnerHost] Failed to stop runner "${this.runners[i].name}": ${reason}`);
|
|
335350
|
+
}
|
|
335351
|
+
}
|
|
335352
|
+
}
|
|
335353
|
+
/** Broadcast a config update to all runners. */
|
|
335354
|
+
broadcastConfigUpdate(cfg) {
|
|
335355
|
+
for (const runner of this.runners) {
|
|
335356
|
+
runner.updateConfig(cfg);
|
|
335357
|
+
}
|
|
335358
|
+
}
|
|
335359
|
+
/** Propagate a shared task store to all runners that support it. */
|
|
335360
|
+
setTaskStore(store, configPath) {
|
|
335361
|
+
for (const runner of this.runners) {
|
|
335362
|
+
if (runner.setTaskStore) {
|
|
335363
|
+
runner.setTaskStore(store, configPath);
|
|
335364
|
+
}
|
|
335365
|
+
}
|
|
335366
|
+
}
|
|
335367
|
+
}
|
|
335368
|
+
exports.RunnerHost = RunnerHost;
|
|
335369
|
+
|
|
335370
|
+
|
|
335371
|
+
/***/ }),
|
|
335372
|
+
|
|
335373
|
+
/***/ 84763:
|
|
335374
|
+
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
335375
|
+
|
|
335376
|
+
"use strict";
|
|
335377
|
+
|
|
335378
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
335379
|
+
exports.initTelemetryFromConfig = initTelemetryFromConfig;
|
|
335380
|
+
const opentelemetry_1 = __nccwpck_require__(6248);
|
|
335381
|
+
/**
|
|
335382
|
+
* Initialize telemetry from a Visor config.
|
|
335383
|
+
*
|
|
335384
|
+
* Extracts the telemetry block (if any) and merges it with environment
|
|
335385
|
+
* variable overrides, then calls the shared `initTelemetry()` helper.
|
|
335386
|
+
* This replaces the ~20-line block that was duplicated per-frontend.
|
|
335387
|
+
*/
|
|
335388
|
+
async function initTelemetryFromConfig(config) {
|
|
335389
|
+
const t = config?.telemetry;
|
|
335390
|
+
if (t) {
|
|
335391
|
+
await (0, opentelemetry_1.initTelemetry)({
|
|
335392
|
+
enabled: process.env.VISOR_TELEMETRY_ENABLED === 'true' || !!t.enabled,
|
|
335393
|
+
sink: process.env.VISOR_TELEMETRY_SINK || t.sink || 'file',
|
|
335394
|
+
file: { dir: process.env.VISOR_TRACE_DIR || t.file?.dir, ndjson: !!t.file?.ndjson },
|
|
335395
|
+
autoInstrument: !!t.tracing?.auto_instrumentations,
|
|
335396
|
+
traceReport: !!t.tracing?.trace_report?.enabled,
|
|
335397
|
+
});
|
|
335398
|
+
}
|
|
335399
|
+
else {
|
|
335400
|
+
await (0, opentelemetry_1.initTelemetry)({
|
|
335401
|
+
enabled: process.env.VISOR_TELEMETRY_ENABLED === 'true',
|
|
335402
|
+
sink: process.env.VISOR_TELEMETRY_SINK || 'file',
|
|
335403
|
+
file: { dir: process.env.VISOR_TRACE_DIR },
|
|
335404
|
+
});
|
|
335405
|
+
}
|
|
335406
|
+
}
|
|
335407
|
+
|
|
335408
|
+
|
|
334723
335409
|
/***/ }),
|
|
334724
335410
|
|
|
334725
335411
|
/***/ 11207:
|
|
@@ -342772,6 +343458,7 @@ const workspace_manager_1 = __nccwpck_require__(6134);
|
|
|
342772
343458
|
const message_trigger_1 = __nccwpck_require__(71983);
|
|
342773
343459
|
const types_1 = __nccwpck_require__(83506);
|
|
342774
343460
|
class SlackSocketRunner {
|
|
343461
|
+
name = 'slack';
|
|
342775
343462
|
appToken;
|
|
342776
343463
|
endpoint;
|
|
342777
343464
|
mentions = 'direct';
|
|
@@ -348014,11 +348701,13 @@ async function renderTemplateContent(checkId, checkConfig, reviewSummary) {
|
|
|
348014
348701
|
let templateContent;
|
|
348015
348702
|
if (checkConfig.template && checkConfig.template.content) {
|
|
348016
348703
|
templateContent = String(checkConfig.template.content);
|
|
348704
|
+
logger_1.logger.debug(`[TemplateRenderer] Using inline template for ${checkId}`);
|
|
348017
348705
|
}
|
|
348018
348706
|
else if (checkConfig.template && checkConfig.template.file) {
|
|
348019
348707
|
const file = String(checkConfig.template.file);
|
|
348020
348708
|
const resolved = path.resolve(process.cwd(), file);
|
|
348021
348709
|
templateContent = await fs.readFile(resolved, 'utf-8');
|
|
348710
|
+
logger_1.logger.debug(`[TemplateRenderer] Using template file for ${checkId}: ${resolved}`);
|
|
348022
348711
|
}
|
|
348023
348712
|
else if (schema && schema !== 'plain') {
|
|
348024
348713
|
const sanitized = String(schema).replace(/[^a-zA-Z0-9-]/g, '');
|
|
@@ -348034,13 +348723,18 @@ async function renderTemplateContent(checkId, checkConfig, reviewSummary) {
|
|
|
348034
348723
|
for (const p of candidatePaths) {
|
|
348035
348724
|
try {
|
|
348036
348725
|
templateContent = await fs.readFile(p, 'utf-8');
|
|
348037
|
-
if (templateContent)
|
|
348726
|
+
if (templateContent) {
|
|
348727
|
+
logger_1.logger.debug(`[TemplateRenderer] Using schema template for ${checkId}: ${p}`);
|
|
348038
348728
|
break;
|
|
348729
|
+
}
|
|
348039
348730
|
}
|
|
348040
348731
|
catch {
|
|
348041
348732
|
// try next
|
|
348042
348733
|
}
|
|
348043
348734
|
}
|
|
348735
|
+
if (!templateContent) {
|
|
348736
|
+
logger_1.logger.warn(`[TemplateRenderer] No template found for schema '${sanitized}' in ${checkId}. __dirname=${__dirname}, cwd=${process.cwd()}, tried ${candidatePaths.length} paths: ${candidatePaths.join(', ')}`);
|
|
348737
|
+
}
|
|
348044
348738
|
}
|
|
348045
348739
|
}
|
|
348046
348740
|
if (!templateContent)
|
|
@@ -348071,8 +348765,13 @@ async function renderTemplateContent(checkId, checkConfig, reviewSummary) {
|
|
|
348071
348765
|
checkName: checkId,
|
|
348072
348766
|
output,
|
|
348073
348767
|
};
|
|
348768
|
+
logger_1.logger.debug(`[TemplateRenderer] Rendering template for ${checkId} with output type=${typeof output}, keys=${output && typeof output === 'object' ? Object.keys(output).join(',') : 'n/a'}`);
|
|
348074
348769
|
const rendered = await liquid.parseAndRender(templateContent, templateData);
|
|
348075
|
-
|
|
348770
|
+
const trimmed = rendered.trim();
|
|
348771
|
+
if (!trimmed) {
|
|
348772
|
+
logger_1.logger.warn(`[TemplateRenderer] Template rendered EMPTY for ${checkId}. output=${JSON.stringify(output)?.substring(0, 200)}`);
|
|
348773
|
+
}
|
|
348774
|
+
return trimmed;
|
|
348076
348775
|
}
|
|
348077
348776
|
catch (error) {
|
|
348078
348777
|
const msg = error instanceof Error ? error.message : String(error);
|
|
@@ -348561,8 +349260,11 @@ class StateMachineRunner {
|
|
|
348561
349260
|
const allIssues = [];
|
|
348562
349261
|
let debug = undefined;
|
|
348563
349262
|
if (checkConfig.forEach && entries.length > 1) {
|
|
348564
|
-
// Aggregate all forEach iterations
|
|
349263
|
+
// Aggregate all forEach iterations.
|
|
349264
|
+
// forEach producers have both an unscoped entry (with the full array output)
|
|
349265
|
+
// and scoped per-item entries. Prefer the unscoped entry's output.
|
|
348565
349266
|
const contents = [];
|
|
349267
|
+
let unscopedOutput = undefined;
|
|
348566
349268
|
for (const entry of entries) {
|
|
348567
349269
|
if (entry.result.content) {
|
|
348568
349270
|
contents.push(entry.result.content);
|
|
@@ -348573,19 +349275,29 @@ class StateMachineRunner {
|
|
|
348573
349275
|
if (entry.result.debug) {
|
|
348574
349276
|
debug = entry.result.debug;
|
|
348575
349277
|
}
|
|
348576
|
-
//
|
|
348577
|
-
if (entry.result.output !== undefined) {
|
|
349278
|
+
// Prefer the unscoped (scope=[]) entry which has the full array output
|
|
349279
|
+
if (entry.scope.length === 0 && entry.result.output !== undefined) {
|
|
349280
|
+
unscopedOutput = entry.result.output;
|
|
349281
|
+
}
|
|
349282
|
+
if (entry.result.output !== undefined && unscopedOutput === undefined) {
|
|
348578
349283
|
output = entry.result.output;
|
|
348579
349284
|
}
|
|
348580
349285
|
}
|
|
349286
|
+
output = unscopedOutput !== undefined ? unscopedOutput : output;
|
|
348581
349287
|
content = contents.join('\n');
|
|
348582
349288
|
}
|
|
348583
349289
|
else {
|
|
348584
|
-
// For non-forEach or single-entry forEach, take the latest entry
|
|
349290
|
+
// For non-forEach or single-entry forEach, take the latest entry.
|
|
349291
|
+
// For forEach consumers (aggregated results from executeCheckWithForEachItems),
|
|
349292
|
+
// the aggregated result stores per-item outputs in .forEachItems instead of .output.
|
|
348585
349293
|
const latestEntry = entries[entries.length - 1];
|
|
348586
349294
|
if (latestEntry) {
|
|
348587
349295
|
content = latestEntry.result.content || '';
|
|
348588
349296
|
output = latestEntry.result.output;
|
|
349297
|
+
// Fall back to forEachItems for aggregated forEach consumer results
|
|
349298
|
+
if (output === undefined && latestEntry.result.forEachItems) {
|
|
349299
|
+
output = { forEachItems: latestEntry.result.forEachItems };
|
|
349300
|
+
}
|
|
348589
349301
|
if (latestEntry.result.issues) {
|
|
348590
349302
|
allIssues.push(...latestEntry.result.issues);
|
|
348591
349303
|
}
|
|
@@ -349506,11 +350218,12 @@ async function executeCheckWithForEachItems(checkId, forEachParent, forEachItems
|
|
|
349506
350218
|
logger_1.logger.info(`[LevelDispatch] webhookContext: ${webhookCtx ? 'present' : 'absent'}, webhookData size: ${webhookData?.size || 0}`);
|
|
349507
350219
|
}
|
|
349508
350220
|
if (webhookData && webhookData.size > 0) {
|
|
349509
|
-
// Find the payload with slack_conversation or
|
|
350221
|
+
// Find the payload with slack_conversation, telegram_conversation, or mcp_conversation
|
|
349510
350222
|
for (const payload of webhookData.values()) {
|
|
349511
350223
|
const slackConv = payload?.slack_conversation;
|
|
349512
350224
|
const telegramConv = payload?.telegram_conversation;
|
|
349513
|
-
const
|
|
350225
|
+
const mcpConv = payload?.mcp_conversation;
|
|
350226
|
+
const conv = slackConv || telegramConv || mcpConv;
|
|
349514
350227
|
if (conv) {
|
|
349515
350228
|
const event = payload?.event;
|
|
349516
350229
|
const messageCount = Array.isArray(conv?.messages) ? conv.messages.length : 0;
|
|
@@ -349520,10 +350233,12 @@ async function executeCheckWithForEachItems(checkId, forEachParent, forEachItems
|
|
|
349520
350233
|
// Build transport-specific context
|
|
349521
350234
|
const transportCtx = slackConv
|
|
349522
350235
|
? { slack: { event: event || {}, conversation: slackConv } }
|
|
349523
|
-
:
|
|
349524
|
-
|
|
349525
|
-
|
|
349526
|
-
|
|
350236
|
+
: telegramConv
|
|
350237
|
+
? {
|
|
350238
|
+
telegram: { event: event || {}, conversation: telegramConv },
|
|
350239
|
+
webhook: payload,
|
|
350240
|
+
}
|
|
350241
|
+
: { mcp: { event: event || {}, conversation: mcpConv }, webhook: payload };
|
|
349527
350242
|
providerConfig.eventContext = {
|
|
349528
350243
|
...providerConfig.eventContext,
|
|
349529
350244
|
...transportCtx,
|
|
@@ -350744,11 +351459,12 @@ async function executeSingleCheck(checkId, context, state, emitEvent, transition
|
|
|
350744
351459
|
logger_1.logger.info(`[LevelDispatch] webhookContext: ${webhookCtx ? 'present' : 'absent'}, webhookData size: ${webhookData?.size || 0}`);
|
|
350745
351460
|
}
|
|
350746
351461
|
if (webhookData && webhookData.size > 0) {
|
|
350747
|
-
// Find the payload with slack_conversation or
|
|
351462
|
+
// Find the payload with slack_conversation, telegram_conversation, or mcp_conversation
|
|
350748
351463
|
for (const payload of webhookData.values()) {
|
|
350749
351464
|
const slackConv = payload?.slack_conversation;
|
|
350750
351465
|
const telegramConv = payload?.telegram_conversation;
|
|
350751
|
-
const
|
|
351466
|
+
const mcpConv = payload?.mcp_conversation;
|
|
351467
|
+
const conv = slackConv || telegramConv || mcpConv;
|
|
350752
351468
|
if (conv) {
|
|
350753
351469
|
const event = payload?.event;
|
|
350754
351470
|
const messageCount = Array.isArray(conv?.messages) ? conv.messages.length : 0;
|
|
@@ -354699,6 +355415,7 @@ const client_1 = __nccwpck_require__(55391);
|
|
|
354699
355415
|
const adapter_1 = __nccwpck_require__(87917);
|
|
354700
355416
|
const workspace_manager_1 = __nccwpck_require__(6134);
|
|
354701
355417
|
class TeamsWebhookRunner {
|
|
355418
|
+
name = 'teams';
|
|
354702
355419
|
client;
|
|
354703
355420
|
adapter;
|
|
354704
355421
|
engine;
|
|
@@ -355446,6 +356163,7 @@ const crypto_1 = __nccwpck_require__(76982);
|
|
|
355446
356163
|
const runner_1 = __nccwpck_require__(23575);
|
|
355447
356164
|
const workspace_manager_1 = __nccwpck_require__(6134);
|
|
355448
356165
|
class TelegramPollingRunner {
|
|
356166
|
+
name = 'telegram';
|
|
355449
356167
|
client;
|
|
355450
356168
|
adapter;
|
|
355451
356169
|
engine;
|
|
@@ -372780,6 +373498,7 @@ const client_1 = __nccwpck_require__(73407);
|
|
|
372780
373498
|
const adapter_1 = __nccwpck_require__(1421);
|
|
372781
373499
|
const workspace_manager_1 = __nccwpck_require__(6134);
|
|
372782
373500
|
class WhatsAppWebhookRunner {
|
|
373501
|
+
name = 'whatsapp';
|
|
372783
373502
|
client;
|
|
372784
373503
|
adapter;
|
|
372785
373504
|
engine;
|
|
@@ -494638,7 +495357,22 @@ function mapFlowchartParserError(err, text) {
|
|
|
494638
495357
|
const lineContent = allLines[Math.max(0, line - 1)] || "";
|
|
494639
495358
|
const beforeQuote = lineContent.slice(0, Math.max(0, column - 1));
|
|
494640
495359
|
const hasLinkBefore = beforeQuote.match(/--\s*$|==\s*$|-\.\s*$|-\.-\s*$|\[\s*$/);
|
|
495360
|
+
const caret0 = Math.max(0, column - 1);
|
|
495361
|
+
const firstBar = lineContent.lastIndexOf("|", caret0);
|
|
495362
|
+
const secondBar = firstBar >= 0 ? lineContent.indexOf("|", caret0 + 1) : -1;
|
|
495363
|
+
const inPipeLabel = firstBar >= 0 && secondBar > firstBar && firstBar < caret0 && secondBar > caret0;
|
|
494641
495364
|
if (inLinkRule || hasLinkBefore) {
|
|
495365
|
+
if (tokType === "QuotedString" && inPipeLabel) {
|
|
495366
|
+
return {
|
|
495367
|
+
line,
|
|
495368
|
+
column,
|
|
495369
|
+
severity: "error",
|
|
495370
|
+
code: "FL-EDGE-LABEL-QUOTE-IN-PIPES",
|
|
495371
|
+
message: "Quotes are not supported inside pipe-delimited edge labels.",
|
|
495372
|
+
hint: "Use " inside |...|, e.g., --|e.g. "navigate to example.com"|-->",
|
|
495373
|
+
length: len
|
|
495374
|
+
};
|
|
495375
|
+
}
|
|
494642
495376
|
if (tokType === "DiamondOpen" || tokType === "DiamondClose") {
|
|
494643
495377
|
return {
|
|
494644
495378
|
line,
|
|
@@ -495240,17 +495974,6 @@ ${br.example}`,
|
|
|
495240
495974
|
if (inRule("arrow") && err.name === "NoViableAltException") {
|
|
495241
495975
|
return { line, column, severity: "error", code: "SE-ARROW-INVALID", message: `Invalid sequence arrow near '${found}'.`, hint: "Use ->, -->, ->>, -->>, -x, --x, -), --), <<->>, or <<-->>", length: len };
|
|
495242
495976
|
}
|
|
495243
|
-
if ((err.name === "NoViableAltException" || err.name === "MismatchedTokenException") && tokType === "Minus") {
|
|
495244
|
-
return {
|
|
495245
|
-
line,
|
|
495246
|
-
column,
|
|
495247
|
-
severity: "error",
|
|
495248
|
-
code: "SE-BULLET-LINE-UNSUPPORTED",
|
|
495249
|
-
message: "Bullet list lines starting with '-' are not supported in sequence diagrams.",
|
|
495250
|
-
hint: "Wrap free\u2011form text in a note block instead, for example:\nNote over A : Item 1\nNote over A\n - Item 1\n - Item 2\nend note",
|
|
495251
|
-
length: len
|
|
495252
|
-
};
|
|
495253
|
-
}
|
|
495254
495977
|
if (inRule("noteStmt")) {
|
|
495255
495978
|
if (err.name === "MismatchedTokenException" && exp("Colon")) {
|
|
495256
495979
|
return { line, column, severity: "error", code: "SE-NOTE-MALFORMED", message: "Malformed note: missing colon before the note text.", hint: "Example: Note right of Alice: Hello", length: len };
|
|
@@ -495259,6 +495982,22 @@ ${br.example}`,
|
|
|
495259
495982
|
return { line, column, severity: "error", code: "SE-NOTE-MALFORMED", message: "Malformed note statement. Use left|right of X or over X[,Y]: text", hint: "Examples: Note over A,B: hi", length: len };
|
|
495260
495983
|
}
|
|
495261
495984
|
}
|
|
495985
|
+
if ((err.name === "NoViableAltException" || err.name === "MismatchedTokenException") && tokType === "Minus") {
|
|
495986
|
+
const nonWs = ltxt.search(/\S/);
|
|
495987
|
+
const minusAtLineStart = nonWs >= 0 && ltxt[nonWs] === "-" && column === nonWs + 1;
|
|
495988
|
+
if (!minusAtLineStart) {
|
|
495989
|
+
} else {
|
|
495990
|
+
return {
|
|
495991
|
+
line,
|
|
495992
|
+
column,
|
|
495993
|
+
severity: "error",
|
|
495994
|
+
code: "SE-BULLET-LINE-UNSUPPORTED",
|
|
495995
|
+
message: "Bullet list lines starting with '-' are not supported in sequence diagrams.",
|
|
495996
|
+
hint: "Wrap free\u2011form text in a note block instead, for example:\nNote over A : Item 1\nNote over A\n - Item 1\n - Item 2\nend note",
|
|
495997
|
+
length: len
|
|
495998
|
+
};
|
|
495999
|
+
}
|
|
496000
|
+
}
|
|
495262
496001
|
if (tokType === "ElseKeyword" && isInRule(err, "criticalBlock")) {
|
|
495263
496002
|
return {
|
|
495264
496003
|
line,
|
|
@@ -496058,7 +496797,7 @@ var Identifier2, NumberLiteral3, SequenceKeyword, ParticipantKeyword, ActorKeywo
|
|
|
496058
496797
|
var init_lexer4 = __esm({
|
|
496059
496798
|
"node_modules/@probelabs/maid/out/diagrams/sequence/lexer.js"() {
|
|
496060
496799
|
init_api6();
|
|
496061
|
-
Identifier2 = createToken({ name: "Identifier", pattern: /[A-Za-z_][A-Za-z0-9_]*/ });
|
|
496800
|
+
Identifier2 = createToken({ name: "Identifier", pattern: /[A-Za-z_][A-Za-z0-9_.]*(?:-(?![>x)\s])[A-Za-z0-9_.]+)*/ });
|
|
496062
496801
|
NumberLiteral3 = createToken({ name: "NumberLiteral", pattern: /[0-9]+/ });
|
|
496063
496802
|
SequenceKeyword = createToken({ name: "SequenceKeyword", pattern: /sequenceDiagram/, longer_alt: Identifier2 });
|
|
496064
496803
|
ParticipantKeyword = createToken({ name: "ParticipantKeyword", pattern: /participant/i, longer_alt: Identifier2 });
|
|
@@ -497878,6 +498617,135 @@ var init_validate5 = __esm({
|
|
|
497878
498617
|
}
|
|
497879
498618
|
});
|
|
497880
498619
|
|
|
498620
|
+
// node_modules/@probelabs/maid/out/core/frontmatter.js
|
|
498621
|
+
function parseFrontmatter(input) {
|
|
498622
|
+
const text = input.startsWith("\uFEFF") ? input.slice(1) : input;
|
|
498623
|
+
const lines = text.split(/\r?\n/);
|
|
498624
|
+
if (lines.length < 3 || lines[0].trim() !== "---")
|
|
498625
|
+
return null;
|
|
498626
|
+
let i = 1;
|
|
498627
|
+
const block = [];
|
|
498628
|
+
while (i < lines.length && lines[i].trim() !== "---") {
|
|
498629
|
+
block.push(lines[i]);
|
|
498630
|
+
i++;
|
|
498631
|
+
}
|
|
498632
|
+
if (i >= lines.length)
|
|
498633
|
+
return null;
|
|
498634
|
+
const body = lines.slice(i + 1).join("\n");
|
|
498635
|
+
const bodyStartLine = i + 2;
|
|
498636
|
+
const raw = block.join("\n");
|
|
498637
|
+
const config2 = {};
|
|
498638
|
+
const themeVars = {};
|
|
498639
|
+
let themeUnderConfig = false;
|
|
498640
|
+
let ctx = "root";
|
|
498641
|
+
for (const line of block) {
|
|
498642
|
+
if (!line.trim())
|
|
498643
|
+
continue;
|
|
498644
|
+
const indent = line.match(/^\s*/)?.[0].length ?? 0;
|
|
498645
|
+
const mKey = line.match(/^\s*([A-Za-z0-9_\-]+):\s*(.*)$/);
|
|
498646
|
+
if (!mKey)
|
|
498647
|
+
continue;
|
|
498648
|
+
const key = mKey[1];
|
|
498649
|
+
let value = mKey[2] || "";
|
|
498650
|
+
if (indent === 0) {
|
|
498651
|
+
if (key === "config") {
|
|
498652
|
+
ctx = "config";
|
|
498653
|
+
continue;
|
|
498654
|
+
}
|
|
498655
|
+
if (key === "themeVariables") {
|
|
498656
|
+
ctx = "theme";
|
|
498657
|
+
continue;
|
|
498658
|
+
}
|
|
498659
|
+
ctx = "root";
|
|
498660
|
+
continue;
|
|
498661
|
+
}
|
|
498662
|
+
if (ctx === "config") {
|
|
498663
|
+
if (indent <= 2 && key !== "pie" && key !== "themeVariables")
|
|
498664
|
+
continue;
|
|
498665
|
+
if (key === "pie") {
|
|
498666
|
+
ctx = "config.pie";
|
|
498667
|
+
ensure(config2, "pie", {});
|
|
498668
|
+
continue;
|
|
498669
|
+
}
|
|
498670
|
+
if (key === "themeVariables") {
|
|
498671
|
+
ctx = "theme";
|
|
498672
|
+
themeUnderConfig = true;
|
|
498673
|
+
continue;
|
|
498674
|
+
}
|
|
498675
|
+
continue;
|
|
498676
|
+
}
|
|
498677
|
+
if (ctx === "config.pie") {
|
|
498678
|
+
if (indent < 4) {
|
|
498679
|
+
if (key === "pie") {
|
|
498680
|
+
ctx = "config.pie";
|
|
498681
|
+
ensure(config2, "pie", {});
|
|
498682
|
+
continue;
|
|
498683
|
+
}
|
|
498684
|
+
if (key === "themeVariables") {
|
|
498685
|
+
ctx = "theme";
|
|
498686
|
+
themeUnderConfig = true;
|
|
498687
|
+
continue;
|
|
498688
|
+
}
|
|
498689
|
+
ctx = "config";
|
|
498690
|
+
continue;
|
|
498691
|
+
}
|
|
498692
|
+
setKV(config2.pie, key, value);
|
|
498693
|
+
continue;
|
|
498694
|
+
}
|
|
498695
|
+
if (ctx === "theme") {
|
|
498696
|
+
if (indent < 2) {
|
|
498697
|
+
ctx = "root";
|
|
498698
|
+
continue;
|
|
498699
|
+
}
|
|
498700
|
+
setKV(themeVars, key, value);
|
|
498701
|
+
continue;
|
|
498702
|
+
}
|
|
498703
|
+
}
|
|
498704
|
+
if (themeUnderConfig && Object.keys(themeVars).length) {
|
|
498705
|
+
ensure(config2, "themeVariables", {});
|
|
498706
|
+
Object.assign(config2.themeVariables, themeVars);
|
|
498707
|
+
}
|
|
498708
|
+
return {
|
|
498709
|
+
raw,
|
|
498710
|
+
body,
|
|
498711
|
+
bodyStartLine,
|
|
498712
|
+
config: Object.keys(config2).length ? config2 : void 0,
|
|
498713
|
+
themeVariables: Object.keys(themeVars).length ? themeVars : void 0
|
|
498714
|
+
};
|
|
498715
|
+
}
|
|
498716
|
+
function ensure(obj, key, def) {
|
|
498717
|
+
if (obj[key] == null)
|
|
498718
|
+
obj[key] = def;
|
|
498719
|
+
}
|
|
498720
|
+
function unquote(val) {
|
|
498721
|
+
const v = val.trim();
|
|
498722
|
+
if (v.startsWith('"') && v.endsWith('"') || v.startsWith("'") && v.endsWith("'")) {
|
|
498723
|
+
return v.slice(1, -1);
|
|
498724
|
+
}
|
|
498725
|
+
return v;
|
|
498726
|
+
}
|
|
498727
|
+
function setKV(target, key, rawValue) {
|
|
498728
|
+
const v = unquote(rawValue);
|
|
498729
|
+
if (v === "") {
|
|
498730
|
+
target[key] = "";
|
|
498731
|
+
return;
|
|
498732
|
+
}
|
|
498733
|
+
const num = Number(v);
|
|
498734
|
+
if (!Number.isNaN(num) && /^-?[0-9]+(\.[0-9]+)?$/.test(v)) {
|
|
498735
|
+
target[key] = num;
|
|
498736
|
+
return;
|
|
498737
|
+
}
|
|
498738
|
+
if (/^(true|false)$/i.test(v)) {
|
|
498739
|
+
target[key] = /^true$/i.test(v);
|
|
498740
|
+
return;
|
|
498741
|
+
}
|
|
498742
|
+
target[key] = v;
|
|
498743
|
+
}
|
|
498744
|
+
var init_frontmatter = __esm({
|
|
498745
|
+
"node_modules/@probelabs/maid/out/core/frontmatter.js"() {
|
|
498746
|
+
}
|
|
498747
|
+
});
|
|
498748
|
+
|
|
497881
498749
|
// node_modules/@probelabs/maid/out/core/router.js
|
|
497882
498750
|
function firstNonCommentLine(text) {
|
|
497883
498751
|
const lines = text.split(/\r?\n/);
|
|
@@ -497892,7 +498760,8 @@ function firstNonCommentLine(text) {
|
|
|
497892
498760
|
return void 0;
|
|
497893
498761
|
}
|
|
497894
498762
|
function detectDiagramType(text) {
|
|
497895
|
-
const
|
|
498763
|
+
const { content } = stripFrontmatter(text);
|
|
498764
|
+
const header = firstNonCommentLine(content);
|
|
497896
498765
|
if (!header)
|
|
497897
498766
|
return "unknown";
|
|
497898
498767
|
if (/^(flowchart|graph)\b/i.test(header))
|
|
@@ -497944,20 +498813,26 @@ function isOtherMermaidDiagram(headerLine) {
|
|
|
497944
498813
|
return OTHER.has(t);
|
|
497945
498814
|
}
|
|
497946
498815
|
function validate(text, options = {}) {
|
|
497947
|
-
const
|
|
498816
|
+
const { content, lineOffset } = stripFrontmatter(text);
|
|
498817
|
+
const type = detectDiagramType(content);
|
|
498818
|
+
const withOffset = (errors) => {
|
|
498819
|
+
if (lineOffset === 0)
|
|
498820
|
+
return errors;
|
|
498821
|
+
return errors.map((e) => ({ ...e, line: Math.max(1, (e.line || 1) + lineOffset) }));
|
|
498822
|
+
};
|
|
497948
498823
|
switch (type) {
|
|
497949
498824
|
case "flowchart":
|
|
497950
|
-
return { type, errors: validateFlowchart(
|
|
498825
|
+
return { type, errors: withOffset(validateFlowchart(content, options)) };
|
|
497951
498826
|
case "pie":
|
|
497952
|
-
return { type, errors: validatePie(
|
|
498827
|
+
return { type, errors: withOffset(validatePie(content, options)) };
|
|
497953
498828
|
case "sequence":
|
|
497954
|
-
return { type, errors: validateSequence(
|
|
498829
|
+
return { type, errors: withOffset(validateSequence(content, options)) };
|
|
497955
498830
|
case "class":
|
|
497956
|
-
return { type, errors: validateClass(
|
|
498831
|
+
return { type, errors: withOffset(validateClass(content, options)) };
|
|
497957
498832
|
case "state":
|
|
497958
|
-
return { type, errors: validateState(
|
|
498833
|
+
return { type, errors: withOffset(validateState(content, options)) };
|
|
497959
498834
|
default:
|
|
497960
|
-
const header = firstNonCommentLine(
|
|
498835
|
+
const header = firstNonCommentLine(content);
|
|
497961
498836
|
if (isOtherMermaidDiagram(header)) {
|
|
497962
498837
|
return { type, errors: [] };
|
|
497963
498838
|
}
|
|
@@ -497965,7 +498840,7 @@ function validate(text, options = {}) {
|
|
|
497965
498840
|
type,
|
|
497966
498841
|
errors: [
|
|
497967
498842
|
{
|
|
497968
|
-
line: 1,
|
|
498843
|
+
line: lineOffset + 1,
|
|
497969
498844
|
column: 1,
|
|
497970
498845
|
message: 'Diagram must start with "graph", "flowchart", "pie", "sequenceDiagram", "classDiagram" or "stateDiagram[-v2]"',
|
|
497971
498846
|
severity: "error",
|
|
@@ -497976,6 +498851,12 @@ function validate(text, options = {}) {
|
|
|
497976
498851
|
};
|
|
497977
498852
|
}
|
|
497978
498853
|
}
|
|
498854
|
+
function stripFrontmatter(text) {
|
|
498855
|
+
const fm = parseFrontmatter(text);
|
|
498856
|
+
if (!fm)
|
|
498857
|
+
return { content: text, lineOffset: 0 };
|
|
498858
|
+
return { content: fm.body, lineOffset: fm.bodyStartLine - 1 };
|
|
498859
|
+
}
|
|
497979
498860
|
var init_router = __esm({
|
|
497980
498861
|
"node_modules/@probelabs/maid/out/core/router.js"() {
|
|
497981
498862
|
init_validate();
|
|
@@ -497983,6 +498864,7 @@ var init_router = __esm({
|
|
|
497983
498864
|
init_validate3();
|
|
497984
498865
|
init_validate4();
|
|
497985
498866
|
init_validate5();
|
|
498867
|
+
init_frontmatter();
|
|
497986
498868
|
}
|
|
497987
498869
|
});
|
|
497988
498870
|
|
|
@@ -498194,16 +499076,18 @@ function computeFixes(text, errors, level = "safe") {
|
|
|
498194
499076
|
}
|
|
498195
499077
|
continue;
|
|
498196
499078
|
}
|
|
498197
|
-
if (is("FL-EDGE-LABEL-BRACKET", e) || is("FL-EDGE-LABEL-CURLY-IN-PIPES", e)) {
|
|
499079
|
+
if (is("FL-EDGE-LABEL-BRACKET", e) || is("FL-EDGE-LABEL-CURLY-IN-PIPES", e) || is("FL-EDGE-LABEL-QUOTE-IN-PIPES", e)) {
|
|
498198
499080
|
const lineText = lineTextAt(text, e.line);
|
|
498199
|
-
const
|
|
498200
|
-
const
|
|
499081
|
+
const col = Math.max(0, e.column - 1);
|
|
499082
|
+
const firstBar = lineText.lastIndexOf("|", col);
|
|
499083
|
+
const secondBar = firstBar >= 0 ? lineText.indexOf("|", col + 1) : -1;
|
|
498201
499084
|
if (firstBar >= 0 && secondBar > firstBar) {
|
|
498202
499085
|
const before = lineText.slice(0, firstBar + 1);
|
|
498203
499086
|
const label = lineText.slice(firstBar + 1, secondBar);
|
|
498204
499087
|
const after = lineText.slice(secondBar);
|
|
498205
499088
|
let fixedLabel = label.replace(/\[/g, "[").replace(/\]/g, "]");
|
|
498206
499089
|
fixedLabel = fixedLabel.replace(/\{/g, "{").replace(/\}/g, "}");
|
|
499090
|
+
fixedLabel = fixedLabel.replace(/\\"/g, """).replace(/"/g, """);
|
|
498207
499091
|
const fixedLine = before + fixedLabel + after;
|
|
498208
499092
|
const finalLine = fixedLine.replace(/\[([^\]]*)\]/g, (m, seg) => "[" + String(seg).replace(/`/g, "") + "]");
|
|
498209
499093
|
edits.push({ start: { line: e.line, column: 1 }, end: { line: e.line, column: lineText.length + 1 }, newText: finalLine });
|
|
@@ -509593,7 +510477,7 @@ ${overlay}</g>`;
|
|
|
509593
510477
|
});
|
|
509594
510478
|
|
|
509595
510479
|
// node_modules/@probelabs/maid/out/renderer/pie-builder.js
|
|
509596
|
-
function
|
|
510480
|
+
function unquote2(s) {
|
|
509597
510481
|
if (!s)
|
|
509598
510482
|
return s;
|
|
509599
510483
|
const first2 = s.charAt(0);
|
|
@@ -509643,7 +510527,7 @@ function buildPieModel(text) {
|
|
|
509643
510527
|
const collect = (k) => {
|
|
509644
510528
|
const arr = tnode.children?.[k] ?? [];
|
|
509645
510529
|
for (const tok of arr)
|
|
509646
|
-
parts.push(
|
|
510530
|
+
parts.push(unquote2(tok.image));
|
|
509647
510531
|
};
|
|
509648
510532
|
collect("QuotedString");
|
|
509649
510533
|
collect("Text");
|
|
@@ -509656,7 +510540,7 @@ function buildPieModel(text) {
|
|
|
509656
510540
|
const labelTok = snode.children?.sliceLabel?.[0]?.children?.QuotedString?.[0];
|
|
509657
510541
|
const numTok = snode.children?.NumberLiteral?.[0];
|
|
509658
510542
|
if (labelTok && numTok) {
|
|
509659
|
-
const label =
|
|
510543
|
+
const label = unquote2(labelTok.image).trim();
|
|
509660
510544
|
const value = Number(numTok.image);
|
|
509661
510545
|
if (!Number.isNaN(value)) {
|
|
509662
510546
|
model.slices.push({ label, value });
|
|
@@ -510812,128 +511696,6 @@ var init_state_renderer = __esm({
|
|
|
510812
511696
|
}
|
|
510813
511697
|
});
|
|
510814
511698
|
|
|
510815
|
-
// node_modules/@probelabs/maid/out/core/frontmatter.js
|
|
510816
|
-
function parseFrontmatter(input) {
|
|
510817
|
-
const text = input.startsWith("\uFEFF") ? input.slice(1) : input;
|
|
510818
|
-
const lines = text.split(/\r?\n/);
|
|
510819
|
-
if (lines.length < 3 || lines[0].trim() !== "---")
|
|
510820
|
-
return null;
|
|
510821
|
-
let i = 1;
|
|
510822
|
-
const block = [];
|
|
510823
|
-
while (i < lines.length && lines[i].trim() !== "---") {
|
|
510824
|
-
block.push(lines[i]);
|
|
510825
|
-
i++;
|
|
510826
|
-
}
|
|
510827
|
-
if (i >= lines.length)
|
|
510828
|
-
return null;
|
|
510829
|
-
const body = lines.slice(i + 1).join("\n");
|
|
510830
|
-
const raw = block.join("\n");
|
|
510831
|
-
const config2 = {};
|
|
510832
|
-
const themeVars = {};
|
|
510833
|
-
let themeUnderConfig = false;
|
|
510834
|
-
let ctx = "root";
|
|
510835
|
-
for (const line of block) {
|
|
510836
|
-
if (!line.trim())
|
|
510837
|
-
continue;
|
|
510838
|
-
const indent = line.match(/^\s*/)?.[0].length ?? 0;
|
|
510839
|
-
const mKey = line.match(/^\s*([A-Za-z0-9_\-]+):\s*(.*)$/);
|
|
510840
|
-
if (!mKey)
|
|
510841
|
-
continue;
|
|
510842
|
-
const key = mKey[1];
|
|
510843
|
-
let value = mKey[2] || "";
|
|
510844
|
-
if (indent === 0) {
|
|
510845
|
-
if (key === "config") {
|
|
510846
|
-
ctx = "config";
|
|
510847
|
-
continue;
|
|
510848
|
-
}
|
|
510849
|
-
if (key === "themeVariables") {
|
|
510850
|
-
ctx = "theme";
|
|
510851
|
-
continue;
|
|
510852
|
-
}
|
|
510853
|
-
ctx = "root";
|
|
510854
|
-
continue;
|
|
510855
|
-
}
|
|
510856
|
-
if (ctx === "config") {
|
|
510857
|
-
if (indent <= 2 && key !== "pie" && key !== "themeVariables")
|
|
510858
|
-
continue;
|
|
510859
|
-
if (key === "pie") {
|
|
510860
|
-
ctx = "config.pie";
|
|
510861
|
-
ensure(config2, "pie", {});
|
|
510862
|
-
continue;
|
|
510863
|
-
}
|
|
510864
|
-
if (key === "themeVariables") {
|
|
510865
|
-
ctx = "theme";
|
|
510866
|
-
themeUnderConfig = true;
|
|
510867
|
-
continue;
|
|
510868
|
-
}
|
|
510869
|
-
continue;
|
|
510870
|
-
}
|
|
510871
|
-
if (ctx === "config.pie") {
|
|
510872
|
-
if (indent < 4) {
|
|
510873
|
-
if (key === "pie") {
|
|
510874
|
-
ctx = "config.pie";
|
|
510875
|
-
ensure(config2, "pie", {});
|
|
510876
|
-
continue;
|
|
510877
|
-
}
|
|
510878
|
-
if (key === "themeVariables") {
|
|
510879
|
-
ctx = "theme";
|
|
510880
|
-
themeUnderConfig = true;
|
|
510881
|
-
continue;
|
|
510882
|
-
}
|
|
510883
|
-
ctx = "config";
|
|
510884
|
-
continue;
|
|
510885
|
-
}
|
|
510886
|
-
setKV(config2.pie, key, value);
|
|
510887
|
-
continue;
|
|
510888
|
-
}
|
|
510889
|
-
if (ctx === "theme") {
|
|
510890
|
-
if (indent < 2) {
|
|
510891
|
-
ctx = "root";
|
|
510892
|
-
continue;
|
|
510893
|
-
}
|
|
510894
|
-
setKV(themeVars, key, value);
|
|
510895
|
-
continue;
|
|
510896
|
-
}
|
|
510897
|
-
}
|
|
510898
|
-
if (themeUnderConfig && Object.keys(themeVars).length) {
|
|
510899
|
-
ensure(config2, "themeVariables", {});
|
|
510900
|
-
Object.assign(config2.themeVariables, themeVars);
|
|
510901
|
-
}
|
|
510902
|
-
return { raw, body, config: Object.keys(config2).length ? config2 : void 0, themeVariables: Object.keys(themeVars).length ? themeVars : void 0 };
|
|
510903
|
-
}
|
|
510904
|
-
function ensure(obj, key, def) {
|
|
510905
|
-
if (obj[key] == null)
|
|
510906
|
-
obj[key] = def;
|
|
510907
|
-
}
|
|
510908
|
-
function unquote2(val) {
|
|
510909
|
-
const v = val.trim();
|
|
510910
|
-
if (v.startsWith('"') && v.endsWith('"') || v.startsWith("'") && v.endsWith("'")) {
|
|
510911
|
-
return v.slice(1, -1);
|
|
510912
|
-
}
|
|
510913
|
-
return v;
|
|
510914
|
-
}
|
|
510915
|
-
function setKV(target, key, rawValue) {
|
|
510916
|
-
const v = unquote2(rawValue);
|
|
510917
|
-
if (v === "") {
|
|
510918
|
-
target[key] = "";
|
|
510919
|
-
return;
|
|
510920
|
-
}
|
|
510921
|
-
const num = Number(v);
|
|
510922
|
-
if (!Number.isNaN(num) && /^-?[0-9]+(\.[0-9]+)?$/.test(v)) {
|
|
510923
|
-
target[key] = num;
|
|
510924
|
-
return;
|
|
510925
|
-
}
|
|
510926
|
-
if (/^(true|false)$/i.test(v)) {
|
|
510927
|
-
target[key] = /^true$/i.test(v);
|
|
510928
|
-
return;
|
|
510929
|
-
}
|
|
510930
|
-
target[key] = v;
|
|
510931
|
-
}
|
|
510932
|
-
var init_frontmatter = __esm({
|
|
510933
|
-
"node_modules/@probelabs/maid/out/core/frontmatter.js"() {
|
|
510934
|
-
}
|
|
510935
|
-
});
|
|
510936
|
-
|
|
510937
511699
|
// node_modules/@probelabs/maid/out/renderer/class-builder.js
|
|
510938
511700
|
function textFromTokens3(tokens) {
|
|
510939
511701
|
if (!tokens || tokens.length === 0)
|
|
@@ -520256,6 +521018,7 @@ var init_client = __esm({
|
|
|
520256
521018
|
this.debug = options.debug || process.env.DEBUG_MCP === "1";
|
|
520257
521019
|
this.config = null;
|
|
520258
521020
|
this.tracer = options.tracer || null;
|
|
521021
|
+
this.agentEvents = options.agentEvents || null;
|
|
520259
521022
|
}
|
|
520260
521023
|
/**
|
|
520261
521024
|
* Record an MCP telemetry event if tracer is available
|
|
@@ -520483,11 +521246,21 @@ var init_client = __esm({
|
|
|
520483
521246
|
throw new Error(`Server ${tool6.serverName} not connected`);
|
|
520484
521247
|
}
|
|
520485
521248
|
const startTime = Date.now();
|
|
521249
|
+
const toolCallId = `mcp-${toolName}-${startTime}`;
|
|
520486
521250
|
this.recordMcpEvent("tool.call_started", {
|
|
520487
521251
|
toolName,
|
|
520488
521252
|
serverName: tool6.serverName,
|
|
520489
521253
|
originalToolName: tool6.originalName
|
|
520490
521254
|
});
|
|
521255
|
+
if (this.agentEvents) {
|
|
521256
|
+
this.agentEvents.emit("toolCall", {
|
|
521257
|
+
toolCallId,
|
|
521258
|
+
name: toolName,
|
|
521259
|
+
args,
|
|
521260
|
+
status: "started",
|
|
521261
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
521262
|
+
});
|
|
521263
|
+
}
|
|
520491
521264
|
try {
|
|
520492
521265
|
if (this.debug) {
|
|
520493
521266
|
console.error(`[MCP DEBUG] Calling ${toolName} with args:`, JSON.stringify(args, null, 2));
|
|
@@ -520517,6 +521290,14 @@ var init_client = __esm({
|
|
|
520517
521290
|
originalToolName: tool6.originalName,
|
|
520518
521291
|
durationMs
|
|
520519
521292
|
});
|
|
521293
|
+
if (this.agentEvents) {
|
|
521294
|
+
this.agentEvents.emit("toolCall", {
|
|
521295
|
+
toolCallId,
|
|
521296
|
+
name: toolName,
|
|
521297
|
+
status: "completed",
|
|
521298
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
521299
|
+
});
|
|
521300
|
+
}
|
|
520520
521301
|
return result;
|
|
520521
521302
|
} catch (error40) {
|
|
520522
521303
|
const durationMs = Date.now() - startTime;
|
|
@@ -520532,6 +521313,14 @@ var init_client = __esm({
|
|
|
520532
521313
|
durationMs,
|
|
520533
521314
|
isTimeout: error40.message.includes("timeout")
|
|
520534
521315
|
});
|
|
521316
|
+
if (this.agentEvents) {
|
|
521317
|
+
this.agentEvents.emit("toolCall", {
|
|
521318
|
+
toolCallId,
|
|
521319
|
+
name: toolName,
|
|
521320
|
+
status: "error",
|
|
521321
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
521322
|
+
});
|
|
521323
|
+
}
|
|
520535
521324
|
throw error40;
|
|
520536
521325
|
}
|
|
520537
521326
|
}
|
|
@@ -520717,6 +521506,7 @@ var init_xmlBridge = __esm({
|
|
|
520717
521506
|
constructor(options = {}) {
|
|
520718
521507
|
this.debug = options.debug || false;
|
|
520719
521508
|
this.tracer = options.tracer || null;
|
|
521509
|
+
this.agentEvents = options.agentEvents || null;
|
|
520720
521510
|
this.mcpTools = {};
|
|
520721
521511
|
this.mcpManager = null;
|
|
520722
521512
|
this.toolDescriptions = {};
|
|
@@ -520759,7 +521549,7 @@ var init_xmlBridge = __esm({
|
|
|
520759
521549
|
if (this.debug) {
|
|
520760
521550
|
console.error("[MCP DEBUG] Initializing MCP client manager...");
|
|
520761
521551
|
}
|
|
520762
|
-
this.mcpManager = new MCPClientManager({ debug: this.debug, tracer: this.tracer });
|
|
521552
|
+
this.mcpManager = new MCPClientManager({ debug: this.debug, tracer: this.tracer, agentEvents: this.agentEvents });
|
|
520763
521553
|
const result = await this.mcpManager.initialize(mcpConfigs);
|
|
520764
521554
|
const vercelTools = this.mcpManager.getVercelTools();
|
|
520765
521555
|
this.mcpTools = vercelTools;
|
|
@@ -528206,7 +528996,7 @@ function deriveDescription(rawDescription, body) {
|
|
|
528206
528996
|
}
|
|
528207
528997
|
return truncateDescription(description);
|
|
528208
528998
|
}
|
|
528209
|
-
function
|
|
528999
|
+
function stripFrontmatter2(content) {
|
|
528210
529000
|
const { body } = extractFrontmatter(content);
|
|
528211
529001
|
return body.trim();
|
|
528212
529002
|
}
|
|
@@ -528347,7 +529137,7 @@ var init_registry = __esm({
|
|
|
528347
529137
|
const skill = this.skillsByName.get(name15);
|
|
528348
529138
|
if (!skill) return null;
|
|
528349
529139
|
const content = await (0, import_promises3.readFile)(skill.skillFilePath, "utf8");
|
|
528350
|
-
return
|
|
529140
|
+
return stripFrontmatter2(content);
|
|
528351
529141
|
}
|
|
528352
529142
|
async _resolveRealPath(target) {
|
|
528353
529143
|
try {
|
|
@@ -545368,7 +546158,7 @@ var init_ProbeAgent = __esm({
|
|
|
545368
546158
|
}
|
|
545369
546159
|
mcpConfig = null;
|
|
545370
546160
|
}
|
|
545371
|
-
this.mcpBridge = new MCPXmlBridge({ debug: this.debug });
|
|
546161
|
+
this.mcpBridge = new MCPXmlBridge({ debug: this.debug, agentEvents: this.events });
|
|
545372
546162
|
await this.mcpBridge.initialize(mcpConfig);
|
|
545373
546163
|
const mcpToolNames = this.mcpBridge.getToolNames();
|
|
545374
546164
|
const mcpToolCount = mcpToolNames.length;
|
|
@@ -546244,6 +547034,14 @@ or
|
|
|
546244
547034
|
active_tools_count: activeToolsList.length
|
|
546245
547035
|
});
|
|
546246
547036
|
}
|
|
547037
|
+
this.events.emit("timeout.extended", {
|
|
547038
|
+
grantedMs,
|
|
547039
|
+
reason: decision.reason || "work in progress",
|
|
547040
|
+
extensionsUsed: negotiatedTimeoutState.extensionsUsed,
|
|
547041
|
+
extensionsRemaining: negotiatedTimeoutState.maxRequests - negotiatedTimeoutState.extensionsUsed,
|
|
547042
|
+
totalExtraTimeMs: negotiatedTimeoutState.totalExtraTimeMs,
|
|
547043
|
+
budgetRemainingMs: remainingBudgetMs - grantedMs
|
|
547044
|
+
});
|
|
546247
547045
|
} else {
|
|
546248
547046
|
if (this.debug) {
|
|
546249
547047
|
console.log(`[DEBUG] Timeout observer: declined extension (reason: ${decision.reason}). Initiating graceful stop.`);
|
|
@@ -546257,6 +547055,11 @@ or
|
|
|
546257
547055
|
active_tools: activeToolsList.map((t) => t.name)
|
|
546258
547056
|
});
|
|
546259
547057
|
}
|
|
547058
|
+
this.events.emit("timeout.windingDown", {
|
|
547059
|
+
reason: decision.reason || "observer declined",
|
|
547060
|
+
extensionsUsed: negotiatedTimeoutState.extensionsUsed,
|
|
547061
|
+
totalExtraTimeMs: negotiatedTimeoutState.totalExtraTimeMs
|
|
547062
|
+
});
|
|
546260
547063
|
await this._initiateGracefulStop(gracefulTimeoutState, `observer declined: ${decision.reason}`);
|
|
546261
547064
|
}
|
|
546262
547065
|
};
|
|
@@ -619797,7 +620600,7 @@ module.exports = /*#__PURE__*/JSON.parse('["aaa","aarp","abb","abbott","abbvie",
|
|
|
619797
620600
|
/***/ ((module) => {
|
|
619798
620601
|
|
|
619799
620602
|
"use strict";
|
|
619800
|
-
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","@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-
|
|
620603
|
+
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","@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-rc297","@types/commander":"^2.12.0","@types/uuid":"^10.0.0","@utcp/file":"^1.1.0","@utcp/http":"^1.1.0","@utcp/sdk":"^1.1.0","@utcp/text":"^1.1.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"]}}');
|
|
619801
620604
|
|
|
619802
620605
|
/***/ })
|
|
619803
620606
|
|