@probelabs/visor 0.1.79 → 0.1.81
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/check-execution-engine.d.ts.map +1 -1
- package/dist/cli-main.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +256 -147
- package/dist/providers/ai-check-provider.d.ts +0 -4
- package/dist/providers/ai-check-provider.d.ts.map +1 -1
- package/dist/providers/claude-code-check-provider.d.ts +0 -4
- package/dist/providers/claude-code-check-provider.d.ts.map +1 -1
- package/dist/providers/command-check-provider.d.ts +6 -0
- package/dist/providers/command-check-provider.d.ts.map +1 -1
- package/dist/sdk/{check-execution-engine-XBKOCBEK.mjs → check-execution-engine-47OZJFUV.mjs} +2 -2
- package/dist/sdk/{chunk-HDGNSOMS.mjs → chunk-V5PUTL5N.mjs} +186 -140
- package/dist/sdk/chunk-V5PUTL5N.mjs.map +1 -0
- package/dist/sdk/sdk.js +187 -142
- package/dist/sdk/sdk.js.map +1 -1
- package/dist/sdk/sdk.mjs +1 -1
- package/dist/session-registry.d.ts +5 -0
- package/dist/session-registry.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/sdk/chunk-HDGNSOMS.mjs.map +0 -1
- /package/dist/sdk/{check-execution-engine-XBKOCBEK.mjs.map → check-execution-engine-47OZJFUV.mjs.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
process.env.VISOR_VERSION = '0.1.
|
|
2
|
+
process.env.VISOR_VERSION = '0.1.81';
|
|
3
3
|
process.env.PROBE_VERSION = '0.6.0-rc122';
|
|
4
4
|
/******/ (() => { // webpackBootstrap
|
|
5
5
|
/******/ var __webpack_modules__ = ({
|
|
@@ -102520,21 +102520,30 @@ class CheckExecutionEngine {
|
|
|
102520
102520
|
dependencyResults.set(depId, depResult);
|
|
102521
102521
|
}
|
|
102522
102522
|
}
|
|
102523
|
-
// If any direct dependency failed
|
|
102523
|
+
// If any direct dependency failed or was skipped, skip this check
|
|
102524
102524
|
const directDeps = checkConfig.depends_on || [];
|
|
102525
102525
|
const failedDeps = [];
|
|
102526
102526
|
for (const depId of directDeps) {
|
|
102527
102527
|
const depRes = results.get(depId);
|
|
102528
102528
|
if (!depRes)
|
|
102529
102529
|
continue;
|
|
102530
|
-
//
|
|
102531
|
-
const
|
|
102530
|
+
// Check if dependency was skipped
|
|
102531
|
+
const wasSkipped = (depRes.issues || []).some(issue => {
|
|
102532
102532
|
const id = issue.ruleId || '';
|
|
102533
|
-
return
|
|
102533
|
+
return id.endsWith('/__skipped');
|
|
102534
|
+
});
|
|
102535
|
+
// Check for fatal failures: command provider execution/transform failures and forEach iteration errors
|
|
102536
|
+
const hasFatalFailure = (depRes.issues || []).some(issue => {
|
|
102537
|
+
const id = issue.ruleId || '';
|
|
102538
|
+
return (id === 'command/execution_error' ||
|
|
102539
|
+
id.endsWith('/command/execution_error') ||
|
|
102540
|
+
id === 'command/transform_js_error' ||
|
|
102534
102541
|
id.endsWith('/command/transform_js_error') ||
|
|
102535
|
-
id
|
|
102542
|
+
id === 'command/transform_error' ||
|
|
102543
|
+
id.endsWith('/command/transform_error') ||
|
|
102544
|
+
id.endsWith('/forEach/iteration_error'));
|
|
102536
102545
|
});
|
|
102537
|
-
if (
|
|
102546
|
+
if (wasSkipped || hasFatalFailure)
|
|
102538
102547
|
failedDeps.push(depId);
|
|
102539
102548
|
}
|
|
102540
102549
|
if (failedDeps.length > 0) {
|
|
@@ -102606,8 +102615,8 @@ class CheckExecutionEngine {
|
|
|
102606
102615
|
if (debug) {
|
|
102607
102616
|
log(`🔄 Debug: Check "${checkName}" depends on forEach check "${forEachParentName}", executing ${forEachItems.length} times`);
|
|
102608
102617
|
}
|
|
102609
|
-
// Log forEach processing start
|
|
102610
|
-
logger_1.logger.info(`
|
|
102618
|
+
// Log forEach processing start (non-debug)
|
|
102619
|
+
logger_1.logger.info(` forEach: processing ${forEachItems.length} items from "${forEachParentName}"...`);
|
|
102611
102620
|
const allIssues = [];
|
|
102612
102621
|
const allOutputs = [];
|
|
102613
102622
|
const aggregatedContents = [];
|
|
@@ -102678,8 +102687,19 @@ class CheckExecutionEngine {
|
|
|
102678
102687
|
parent: forEachParentName,
|
|
102679
102688
|
});
|
|
102680
102689
|
// Record iteration completion
|
|
102690
|
+
// Check if this iteration had fatal errors
|
|
102691
|
+
const hadFatalError = (itemResult.issues || []).some(issue => {
|
|
102692
|
+
const id = issue.ruleId || '';
|
|
102693
|
+
return (id === 'command/execution_error' ||
|
|
102694
|
+
id.endsWith('/command/execution_error') ||
|
|
102695
|
+
id === 'command/transform_js_error' ||
|
|
102696
|
+
id.endsWith('/command/transform_js_error') ||
|
|
102697
|
+
id === 'command/transform_error' ||
|
|
102698
|
+
id.endsWith('/command/transform_error'));
|
|
102699
|
+
});
|
|
102681
102700
|
const iterationDuration = (Date.now() - iterationStart) / 1000;
|
|
102682
|
-
this.recordIterationComplete(checkName, iterationStart,
|
|
102701
|
+
this.recordIterationComplete(checkName, iterationStart, !hadFatalError, // Success if no fatal errors
|
|
102702
|
+
itemResult.issues || [], itemResult.output);
|
|
102683
102703
|
// Log iteration progress
|
|
102684
102704
|
logger_1.logger.info(` ✔ ${itemIndex + 1}/${forEachItems.length} (${iterationDuration.toFixed(1)}s)`);
|
|
102685
102705
|
return { index: itemIndex, itemResult };
|
|
@@ -102691,7 +102711,22 @@ class CheckExecutionEngine {
|
|
|
102691
102711
|
const forEachResults = await this.executeWithLimitedParallelism(itemTasks, forEachConcurrency, false);
|
|
102692
102712
|
for (const result of forEachResults) {
|
|
102693
102713
|
if (result.status === 'rejected') {
|
|
102694
|
-
|
|
102714
|
+
// Instead of throwing, record the failure and continue with other iterations
|
|
102715
|
+
const error = result.reason;
|
|
102716
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
102717
|
+
// Create an error issue for this failed iteration
|
|
102718
|
+
allIssues.push({
|
|
102719
|
+
ruleId: `${checkName}/forEach/iteration_error`,
|
|
102720
|
+
severity: 'error',
|
|
102721
|
+
category: 'logic',
|
|
102722
|
+
message: `forEach iteration failed: ${errorMessage}`,
|
|
102723
|
+
file: '',
|
|
102724
|
+
line: 0,
|
|
102725
|
+
});
|
|
102726
|
+
if (debug) {
|
|
102727
|
+
log(`🔄 Debug: forEach iteration for check "${checkName}" failed: ${errorMessage}`);
|
|
102728
|
+
}
|
|
102729
|
+
continue;
|
|
102695
102730
|
}
|
|
102696
102731
|
// Skip results from skipped items (those that failed if condition)
|
|
102697
102732
|
if (result.value.skipped) {
|
|
@@ -102749,7 +102784,18 @@ class CheckExecutionEngine {
|
|
|
102749
102784
|
// Execute with retry/routing semantics
|
|
102750
102785
|
finalResult = await this.executeWithRouting(checkName, checkConfig, provider, providerConfig, prInfo, dependencyResults, sessionInfo, config, dependencyGraph, debug, results);
|
|
102751
102786
|
// Record normal (non-forEach) execution
|
|
102752
|
-
|
|
102787
|
+
// Check if this check had fatal errors
|
|
102788
|
+
const hadFatalError = (finalResult.issues || []).some(issue => {
|
|
102789
|
+
const id = issue.ruleId || '';
|
|
102790
|
+
return (id === 'command/execution_error' ||
|
|
102791
|
+
id.endsWith('/command/execution_error') ||
|
|
102792
|
+
id === 'command/transform_js_error' ||
|
|
102793
|
+
id.endsWith('/command/transform_js_error') ||
|
|
102794
|
+
id === 'command/transform_error' ||
|
|
102795
|
+
id.endsWith('/command/transform_error'));
|
|
102796
|
+
});
|
|
102797
|
+
this.recordIterationComplete(checkName, checkStartTime, !hadFatalError, // Success if no fatal errors
|
|
102798
|
+
finalResult.issues || [], finalResult.output);
|
|
102753
102799
|
if (checkConfig.forEach) {
|
|
102754
102800
|
try {
|
|
102755
102801
|
const finalResultWithOutput = finalResult;
|
|
@@ -102830,11 +102876,24 @@ class CheckExecutionEngine {
|
|
|
102830
102876
|
const result = levelResults[i];
|
|
102831
102877
|
const checkConfig = config.checks[checkName];
|
|
102832
102878
|
if (result.status === 'fulfilled' && result.value.result && !result.value.error) {
|
|
102833
|
-
//
|
|
102879
|
+
// For skipped checks, store a marker so dependent checks can detect the skip
|
|
102834
102880
|
if (result.value.skipped) {
|
|
102835
102881
|
if (debug) {
|
|
102836
|
-
log(`🔧 Debug:
|
|
102882
|
+
log(`🔧 Debug: Storing skip marker for skipped check "${checkName}"`);
|
|
102837
102883
|
}
|
|
102884
|
+
// Store a special marker result with a skip issue so dependencies can detect it
|
|
102885
|
+
results.set(checkName, {
|
|
102886
|
+
issues: [
|
|
102887
|
+
{
|
|
102888
|
+
ruleId: `${checkName}/__skipped`,
|
|
102889
|
+
severity: 'info',
|
|
102890
|
+
category: 'logic',
|
|
102891
|
+
message: 'Check was skipped',
|
|
102892
|
+
file: '',
|
|
102893
|
+
line: 0,
|
|
102894
|
+
},
|
|
102895
|
+
],
|
|
102896
|
+
});
|
|
102838
102897
|
continue;
|
|
102839
102898
|
}
|
|
102840
102899
|
const reviewResult = result.value.result;
|
|
@@ -102864,6 +102923,8 @@ class CheckExecutionEngine {
|
|
|
102864
102923
|
else {
|
|
102865
102924
|
normalizedOutput = [rawOutput];
|
|
102866
102925
|
}
|
|
102926
|
+
// Log forEach items found (non-debug)
|
|
102927
|
+
logger_1.logger.info(` Found ${normalizedOutput.length} items for forEach iteration`);
|
|
102867
102928
|
try {
|
|
102868
102929
|
const preview = JSON.stringify(normalizedOutput);
|
|
102869
102930
|
logger_1.logger.debug(`🔧 Debug: Check "${checkName}" forEach output: ${preview?.slice(0, 200) || '(empty)'}`);
|
|
@@ -102928,19 +102989,6 @@ class CheckExecutionEngine {
|
|
|
102928
102989
|
}
|
|
102929
102990
|
}
|
|
102930
102991
|
}
|
|
102931
|
-
// Build and log final execution summary
|
|
102932
|
-
const executionStatistics = this.buildExecutionStatistics();
|
|
102933
|
-
// Show detailed summary table (only if logFn outputs to console)
|
|
102934
|
-
// Skip when output format is JSON/SARIF to avoid polluting structured output
|
|
102935
|
-
// Check if logFn is console.log (not a no-op or console.error)
|
|
102936
|
-
if (logFn === console.log) {
|
|
102937
|
-
this.logExecutionSummary(executionStatistics);
|
|
102938
|
-
}
|
|
102939
|
-
// Add warning if execution stopped early
|
|
102940
|
-
if (shouldStopExecution) {
|
|
102941
|
-
logger_1.logger.info('');
|
|
102942
|
-
logger_1.logger.warn(`⚠️ Execution stopped early due to fail-fast`);
|
|
102943
|
-
}
|
|
102944
102992
|
if (debug) {
|
|
102945
102993
|
if (shouldStopExecution) {
|
|
102946
102994
|
log(`🛑 Execution stopped early due to fail-fast after processing ${results.size} of ${checks.length} checks`);
|
|
@@ -102949,7 +102997,7 @@ class CheckExecutionEngine {
|
|
|
102949
102997
|
log(`✅ Dependency-aware execution completed successfully for all ${results.size} checks`);
|
|
102950
102998
|
}
|
|
102951
102999
|
}
|
|
102952
|
-
// Cleanup sessions
|
|
103000
|
+
// Cleanup sessions BEFORE printing summary to avoid mixing debug logs with table output
|
|
102953
103001
|
if (sessionIds.size > 0 && debug) {
|
|
102954
103002
|
log(`🧹 Cleaning up ${sessionIds.size} AI sessions...`);
|
|
102955
103003
|
for (const [checkName, sessionId] of sessionIds) {
|
|
@@ -102962,6 +103010,19 @@ class CheckExecutionEngine {
|
|
|
102962
103010
|
}
|
|
102963
103011
|
}
|
|
102964
103012
|
}
|
|
103013
|
+
// Build and log final execution summary
|
|
103014
|
+
const executionStatistics = this.buildExecutionStatistics();
|
|
103015
|
+
// Show detailed summary table (only if logFn outputs to console)
|
|
103016
|
+
// Skip when output format is JSON/SARIF to avoid polluting structured output
|
|
103017
|
+
// Check if logFn is console.log (not a no-op or console.error)
|
|
103018
|
+
if (logFn === console.log) {
|
|
103019
|
+
this.logExecutionSummary(executionStatistics);
|
|
103020
|
+
}
|
|
103021
|
+
// Add warning if execution stopped early
|
|
103022
|
+
if (shouldStopExecution) {
|
|
103023
|
+
logger_1.logger.info('');
|
|
103024
|
+
logger_1.logger.warn(`⚠️ Execution stopped early due to fail-fast`);
|
|
103025
|
+
}
|
|
102965
103026
|
// Aggregate all results
|
|
102966
103027
|
return this.aggregateDependencyAwareResults(results, dependencyGraph, debug, shouldStopExecution);
|
|
102967
103028
|
}
|
|
@@ -103166,7 +103227,9 @@ class CheckExecutionEngine {
|
|
|
103166
103227
|
debugInfo.push(`✅ Check "${checkName}" completed: ${(result.issues || []).length} issues found (level ${executionGroup.level})`);
|
|
103167
103228
|
}
|
|
103168
103229
|
// Issues are already prefixed and enriched with group/schema info
|
|
103169
|
-
|
|
103230
|
+
// Filter out internal __skipped markers
|
|
103231
|
+
const nonInternalIssues = (result.issues || []).filter(issue => !issue.ruleId?.endsWith('/__skipped'));
|
|
103232
|
+
aggregatedIssues.push(...nonInternalIssues);
|
|
103170
103233
|
const resultSummary = result;
|
|
103171
103234
|
const resultContent = resultSummary.content;
|
|
103172
103235
|
if (typeof resultContent === 'string' && resultContent.trim()) {
|
|
@@ -104514,6 +104577,13 @@ async function main() {
|
|
|
104514
104577
|
const hasRepositoryError = allResults.some((result) => {
|
|
104515
104578
|
return result.content.includes('Not a git repository');
|
|
104516
104579
|
});
|
|
104580
|
+
// Cleanup AI sessions before exit to prevent process hanging
|
|
104581
|
+
const { SessionRegistry } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(46059)));
|
|
104582
|
+
const sessionRegistry = SessionRegistry.getInstance();
|
|
104583
|
+
if (sessionRegistry.getActiveSessionIds().length > 0) {
|
|
104584
|
+
logger_1.logger.debug(`🧹 Cleaning up ${sessionRegistry.getActiveSessionIds().length} active AI sessions...`);
|
|
104585
|
+
sessionRegistry.clearAllSessions();
|
|
104586
|
+
}
|
|
104517
104587
|
if (criticalCount > 0 || hasRepositoryError) {
|
|
104518
104588
|
process.exit(1);
|
|
104519
104589
|
}
|
|
@@ -108970,6 +109040,15 @@ async function run() {
|
|
|
108970
109040
|
(0, core_1.setFailed)(error instanceof Error ? error.message : 'Unknown error');
|
|
108971
109041
|
}
|
|
108972
109042
|
}
|
|
109043
|
+
finally {
|
|
109044
|
+
// Cleanup AI sessions before GitHub Action exits to prevent process hanging
|
|
109045
|
+
const { SessionRegistry } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(46059)));
|
|
109046
|
+
const sessionRegistry = SessionRegistry.getInstance();
|
|
109047
|
+
if (sessionRegistry.getActiveSessionIds().length > 0) {
|
|
109048
|
+
console.log(`🧹 Cleaning up ${sessionRegistry.getActiveSessionIds().length} active AI sessions...`);
|
|
109049
|
+
sessionRegistry.clearAllSessions();
|
|
109050
|
+
}
|
|
109051
|
+
}
|
|
108973
109052
|
}
|
|
108974
109053
|
function mapGitHubEventToTrigger(eventName, action) {
|
|
108975
109054
|
if (!eventName)
|
|
@@ -111193,7 +111272,6 @@ const issue_filter_1 = __nccwpck_require__(36879);
|
|
|
111193
111272
|
const liquid_extensions_1 = __nccwpck_require__(33042);
|
|
111194
111273
|
const promises_1 = __importDefault(__nccwpck_require__(91943));
|
|
111195
111274
|
const path_1 = __importDefault(__nccwpck_require__(16928));
|
|
111196
|
-
const claude_code_types_1 = __nccwpck_require__(21710);
|
|
111197
111275
|
/**
|
|
111198
111276
|
* AI-powered check provider using probe agent
|
|
111199
111277
|
*/
|
|
@@ -111520,53 +111598,6 @@ class AICheckProvider extends check_provider_interface_1.CheckProvider {
|
|
|
111520
111598
|
throw new Error(`Failed to render prompt template: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
111521
111599
|
}
|
|
111522
111600
|
}
|
|
111523
|
-
/**
|
|
111524
|
-
* Setup MCP tools based on AI configuration
|
|
111525
|
-
*/
|
|
111526
|
-
async setupMcpTools(aiConfig) {
|
|
111527
|
-
const tools = [];
|
|
111528
|
-
// Setup custom MCP servers if configured
|
|
111529
|
-
if (aiConfig.mcpServers) {
|
|
111530
|
-
try {
|
|
111531
|
-
// Import MCP SDK for custom server creation using safe import
|
|
111532
|
-
const mcpModule = await (0, claude_code_types_1.safeImport)('@modelcontextprotocol/sdk');
|
|
111533
|
-
if (!mcpModule) {
|
|
111534
|
-
console.warn('@modelcontextprotocol/sdk package not found. MCP servers disabled.');
|
|
111535
|
-
return tools;
|
|
111536
|
-
}
|
|
111537
|
-
const createSdkMcpServer = mcpModule.createSdkMcpServer || mcpModule.default?.createSdkMcpServer;
|
|
111538
|
-
if (typeof createSdkMcpServer === 'function') {
|
|
111539
|
-
for (const [serverName, serverConfig] of Object.entries(aiConfig.mcpServers)) {
|
|
111540
|
-
try {
|
|
111541
|
-
// Create MCP server instance
|
|
111542
|
-
const server = await createSdkMcpServer({
|
|
111543
|
-
name: serverName,
|
|
111544
|
-
command: serverConfig.command,
|
|
111545
|
-
args: serverConfig.args || [],
|
|
111546
|
-
env: { ...process.env, ...serverConfig.env },
|
|
111547
|
-
});
|
|
111548
|
-
// Add server tools to available tools
|
|
111549
|
-
const serverTools = (await server.listTools());
|
|
111550
|
-
tools.push(...serverTools.map(tool => ({
|
|
111551
|
-
name: tool.name,
|
|
111552
|
-
server: serverName,
|
|
111553
|
-
})));
|
|
111554
|
-
}
|
|
111555
|
-
catch (serverError) {
|
|
111556
|
-
console.warn(`Failed to setup MCP server ${serverName}: ${serverError instanceof Error ? serverError.message : 'Unknown error'}`);
|
|
111557
|
-
}
|
|
111558
|
-
}
|
|
111559
|
-
}
|
|
111560
|
-
else {
|
|
111561
|
-
console.warn('createSdkMcpServer function not found in @modelcontextprotocol/sdk. MCP servers disabled.');
|
|
111562
|
-
}
|
|
111563
|
-
}
|
|
111564
|
-
catch (error) {
|
|
111565
|
-
console.warn(`Failed to import MCP SDK: ${error instanceof Error ? error.message : 'Unknown error'}. MCP servers disabled.`);
|
|
111566
|
-
}
|
|
111567
|
-
}
|
|
111568
|
-
return tools;
|
|
111569
|
-
}
|
|
111570
111601
|
async execute(prInfo, config, _dependencyResults, sessionInfo) {
|
|
111571
111602
|
// Apply environment configuration if present
|
|
111572
111603
|
if (config.env) {
|
|
@@ -111630,15 +111661,12 @@ class AICheckProvider extends check_provider_interface_1.CheckProvider {
|
|
|
111630
111661
|
if (config.ai?.mcpServers) {
|
|
111631
111662
|
Object.assign(mcpServers, config.ai.mcpServers);
|
|
111632
111663
|
}
|
|
111633
|
-
//
|
|
111664
|
+
// Pass MCP server config directly to AI service
|
|
111634
111665
|
if (Object.keys(mcpServers).length > 0) {
|
|
111635
|
-
//
|
|
111666
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
111636
111667
|
aiConfig.mcpServers = mcpServers;
|
|
111637
|
-
// Optional: attempt to enumerate tools for debug visibility (not required for functionality)
|
|
111638
|
-
const mcpConfig = { mcpServers };
|
|
111639
|
-
const mcpTools = await this.setupMcpTools(mcpConfig);
|
|
111640
111668
|
if (aiConfig.debug) {
|
|
111641
|
-
console.error(`🔧 Debug: AI check MCP configured with ${Object.keys(mcpServers).length} servers
|
|
111669
|
+
console.error(`🔧 Debug: AI check MCP configured with ${Object.keys(mcpServers).length} servers`);
|
|
111642
111670
|
}
|
|
111643
111671
|
}
|
|
111644
111672
|
// Process prompt with Liquid templates and file loading
|
|
@@ -112052,59 +112080,6 @@ class ClaudeCodeCheckProvider extends check_provider_interface_1.CheckProvider {
|
|
|
112052
112080
|
throw new Error(`Failed to initialize Claude Code SDK: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
112053
112081
|
}
|
|
112054
112082
|
}
|
|
112055
|
-
/**
|
|
112056
|
-
* Setup MCP tools based on configuration
|
|
112057
|
-
*/
|
|
112058
|
-
async setupMcpTools(config) {
|
|
112059
|
-
const tools = [];
|
|
112060
|
-
// Add allowed tools
|
|
112061
|
-
if (config.allowedTools) {
|
|
112062
|
-
for (const toolName of config.allowedTools) {
|
|
112063
|
-
tools.push({ name: toolName });
|
|
112064
|
-
}
|
|
112065
|
-
}
|
|
112066
|
-
// Setup custom MCP servers if configured
|
|
112067
|
-
if (config.mcpServers) {
|
|
112068
|
-
try {
|
|
112069
|
-
// Import MCP SDK for custom server creation using safe import
|
|
112070
|
-
const mcpModule = await (0, claude_code_types_1.safeImport)('@modelcontextprotocol/sdk');
|
|
112071
|
-
if (!mcpModule) {
|
|
112072
|
-
console.warn('@modelcontextprotocol/sdk package not found. MCP servers disabled.');
|
|
112073
|
-
return tools;
|
|
112074
|
-
}
|
|
112075
|
-
const createSdkMcpServer = mcpModule.createSdkMcpServer || mcpModule.default?.createSdkMcpServer;
|
|
112076
|
-
if (typeof createSdkMcpServer === 'function') {
|
|
112077
|
-
for (const [serverName, serverConfig] of Object.entries(config.mcpServers)) {
|
|
112078
|
-
try {
|
|
112079
|
-
// Create MCP server instance
|
|
112080
|
-
const server = await createSdkMcpServer({
|
|
112081
|
-
name: serverName,
|
|
112082
|
-
command: serverConfig.command,
|
|
112083
|
-
args: serverConfig.args || [],
|
|
112084
|
-
env: { ...process.env, ...serverConfig.env },
|
|
112085
|
-
});
|
|
112086
|
-
// Add server tools to available tools
|
|
112087
|
-
const serverTools = (await server.listTools());
|
|
112088
|
-
tools.push(...serverTools.map(tool => ({
|
|
112089
|
-
name: tool.name,
|
|
112090
|
-
server: serverName,
|
|
112091
|
-
})));
|
|
112092
|
-
}
|
|
112093
|
-
catch (serverError) {
|
|
112094
|
-
console.warn(`Failed to setup MCP server ${serverName}: ${serverError instanceof Error ? serverError.message : 'Unknown error'}`);
|
|
112095
|
-
}
|
|
112096
|
-
}
|
|
112097
|
-
}
|
|
112098
|
-
else {
|
|
112099
|
-
console.warn('createSdkMcpServer function not found in @modelcontextprotocol/sdk. MCP servers disabled.');
|
|
112100
|
-
}
|
|
112101
|
-
}
|
|
112102
|
-
catch (error) {
|
|
112103
|
-
console.warn(`Failed to import MCP SDK: ${error instanceof Error ? error.message : 'Unknown error'}. MCP servers disabled.`);
|
|
112104
|
-
}
|
|
112105
|
-
}
|
|
112106
|
-
return tools;
|
|
112107
|
-
}
|
|
112108
112083
|
/**
|
|
112109
112084
|
* Group files by their file extension for template context
|
|
112110
112085
|
*/
|
|
@@ -112369,16 +112344,22 @@ class ClaudeCodeCheckProvider extends check_provider_interface_1.CheckProvider {
|
|
|
112369
112344
|
try {
|
|
112370
112345
|
// Initialize Claude Code client
|
|
112371
112346
|
const client = await this.initializeClaudeCodeClient();
|
|
112372
|
-
//
|
|
112373
|
-
const tools = await this.setupMcpTools(claudeCodeConfig);
|
|
112374
|
-
// Prepare query object
|
|
112347
|
+
// Prepare query object with MCP servers passed directly to SDK
|
|
112375
112348
|
const query = {
|
|
112376
112349
|
query: processedPrompt,
|
|
112377
|
-
tools: tools.length > 0 ? tools : undefined,
|
|
112378
112350
|
maxTurns: claudeCodeConfig.maxTurns || 5,
|
|
112379
112351
|
systemPrompt: claudeCodeConfig.systemPrompt,
|
|
112380
112352
|
subagent: claudeCodeConfig.subagent,
|
|
112381
112353
|
};
|
|
112354
|
+
// Add allowed tools if specified
|
|
112355
|
+
if (claudeCodeConfig.allowedTools && claudeCodeConfig.allowedTools.length > 0) {
|
|
112356
|
+
query.tools = claudeCodeConfig.allowedTools.map(name => ({ name }));
|
|
112357
|
+
}
|
|
112358
|
+
// Pass MCP servers directly to the SDK - let it handle spawning and tool discovery
|
|
112359
|
+
if (claudeCodeConfig.mcpServers && Object.keys(claudeCodeConfig.mcpServers).length > 0) {
|
|
112360
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
112361
|
+
query.mcpServers = claudeCodeConfig.mcpServers;
|
|
112362
|
+
}
|
|
112382
112363
|
// Execute query with Claude Code
|
|
112383
112364
|
let response;
|
|
112384
112365
|
if (sessionInfo?.reuseSession && sessionInfo.parentSessionId) {
|
|
@@ -112412,7 +112393,6 @@ class ClaudeCodeCheckProvider extends check_provider_interface_1.CheckProvider {
|
|
|
112412
112393
|
sessionId: response.session_id,
|
|
112413
112394
|
turnCount: response.turn_count,
|
|
112414
112395
|
usage: response.usage,
|
|
112415
|
-
toolsUsed: tools.map(t => t.name),
|
|
112416
112396
|
};
|
|
112417
112397
|
// Apply issue suppression filtering
|
|
112418
112398
|
const suppressionEnabled = config.suppressionEnabled !== false;
|
|
@@ -112708,8 +112688,22 @@ class CommandCheckProvider extends check_provider_interface_1.CheckProvider {
|
|
|
112708
112688
|
output = parsed;
|
|
112709
112689
|
}
|
|
112710
112690
|
catch {
|
|
112711
|
-
//
|
|
112712
|
-
|
|
112691
|
+
// Try to extract JSON from the end of output (for commands with debug logs)
|
|
112692
|
+
const extracted = this.extractJsonFromEnd(rawOutput);
|
|
112693
|
+
if (extracted) {
|
|
112694
|
+
try {
|
|
112695
|
+
output = JSON.parse(extracted);
|
|
112696
|
+
logger_1.logger.debug(`🔧 Debug: Extracted and parsed JSON from end of output (${extracted.length} chars from ${rawOutput.length} total)`);
|
|
112697
|
+
}
|
|
112698
|
+
catch {
|
|
112699
|
+
// Extraction found something but it's not valid JSON
|
|
112700
|
+
output = rawOutput;
|
|
112701
|
+
}
|
|
112702
|
+
}
|
|
112703
|
+
else {
|
|
112704
|
+
// Not JSON, keep as string
|
|
112705
|
+
output = rawOutput;
|
|
112706
|
+
}
|
|
112713
112707
|
}
|
|
112714
112708
|
// Apply transform if specified (Liquid or JavaScript)
|
|
112715
112709
|
let finalOutput = output;
|
|
@@ -112945,6 +112939,7 @@ class CommandCheckProvider extends check_provider_interface_1.CheckProvider {
|
|
|
112945
112939
|
* - If it's a JSON string, expose parsed properties via Proxy (e.g., value.key)
|
|
112946
112940
|
* - When coerced to string (toString/valueOf/Symbol.toPrimitive), return the original raw string
|
|
112947
112941
|
* - If parsing fails or value is not a string, return the value unchanged
|
|
112942
|
+
* - Attempts to extract JSON from the end of the output if full parse fails
|
|
112948
112943
|
*/
|
|
112949
112944
|
makeJsonSmart(value) {
|
|
112950
112945
|
if (typeof value !== 'string') {
|
|
@@ -112952,12 +112947,28 @@ class CommandCheckProvider extends check_provider_interface_1.CheckProvider {
|
|
|
112952
112947
|
}
|
|
112953
112948
|
const raw = value;
|
|
112954
112949
|
let parsed;
|
|
112950
|
+
// First try: parse the entire string as JSON
|
|
112955
112951
|
try {
|
|
112956
112952
|
parsed = JSON.parse(raw);
|
|
112957
112953
|
}
|
|
112958
112954
|
catch {
|
|
112959
|
-
//
|
|
112960
|
-
|
|
112955
|
+
// Second try: extract JSON from the end of the output
|
|
112956
|
+
// Look for { or [ at the start of a line and take everything after it
|
|
112957
|
+
const jsonMatch = this.extractJsonFromEnd(raw);
|
|
112958
|
+
if (jsonMatch) {
|
|
112959
|
+
try {
|
|
112960
|
+
parsed = JSON.parse(jsonMatch);
|
|
112961
|
+
logger_1.logger.debug(`🔧 Debug: Extracted JSON from end of output (${jsonMatch.length} chars from ${raw.length} total)`);
|
|
112962
|
+
}
|
|
112963
|
+
catch {
|
|
112964
|
+
// Not valid JSON even after extraction, return original string
|
|
112965
|
+
return raw;
|
|
112966
|
+
}
|
|
112967
|
+
}
|
|
112968
|
+
else {
|
|
112969
|
+
// Not JSON, return original string
|
|
112970
|
+
return raw;
|
|
112971
|
+
}
|
|
112961
112972
|
}
|
|
112962
112973
|
// Use a boxed string so string methods still work via Proxy fallback
|
|
112963
112974
|
const boxed = new String(raw);
|
|
@@ -113010,6 +113021,30 @@ class CommandCheckProvider extends check_provider_interface_1.CheckProvider {
|
|
|
113010
113021
|
};
|
|
113011
113022
|
return new Proxy(boxed, handler);
|
|
113012
113023
|
}
|
|
113024
|
+
/**
|
|
113025
|
+
* Extract JSON from the end of a string that may contain logs/debug output
|
|
113026
|
+
* Looks for the last occurrence of { or [ and tries to parse from there
|
|
113027
|
+
*/
|
|
113028
|
+
extractJsonFromEnd(text) {
|
|
113029
|
+
// Strategy: Find the last line that starts with { or [
|
|
113030
|
+
// Then try to parse from that point to the end
|
|
113031
|
+
const lines = text.split('\n');
|
|
113032
|
+
// Search backwards for a line starting with { or [
|
|
113033
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
113034
|
+
const trimmed = lines[i].trim();
|
|
113035
|
+
if (trimmed.startsWith('{') || trimmed.startsWith('[')) {
|
|
113036
|
+
// Found potential JSON start - take everything from here to the end
|
|
113037
|
+
const candidate = lines.slice(i).join('\n');
|
|
113038
|
+
// Quick validation: does it look like valid JSON structure?
|
|
113039
|
+
const trimmedCandidate = candidate.trim();
|
|
113040
|
+
if ((trimmedCandidate.startsWith('{') && trimmedCandidate.endsWith('}')) ||
|
|
113041
|
+
(trimmedCandidate.startsWith('[') && trimmedCandidate.endsWith(']'))) {
|
|
113042
|
+
return trimmedCandidate;
|
|
113043
|
+
}
|
|
113044
|
+
}
|
|
113045
|
+
}
|
|
113046
|
+
return null;
|
|
113047
|
+
}
|
|
113013
113048
|
/**
|
|
113014
113049
|
* Recursively apply JSON-smart wrapper to outputs object values
|
|
113015
113050
|
*/
|
|
@@ -114404,7 +114439,11 @@ exports.SessionRegistry = void 0;
|
|
|
114404
114439
|
class SessionRegistry {
|
|
114405
114440
|
static instance;
|
|
114406
114441
|
sessions = new Map();
|
|
114407
|
-
|
|
114442
|
+
exitHandlerRegistered = false;
|
|
114443
|
+
constructor() {
|
|
114444
|
+
// Register process exit handlers to cleanup sessions
|
|
114445
|
+
this.registerExitHandlers();
|
|
114446
|
+
}
|
|
114408
114447
|
/**
|
|
114409
114448
|
* Get the singleton instance of SessionRegistry
|
|
114410
114449
|
*/
|
|
@@ -114437,7 +114476,19 @@ class SessionRegistry {
|
|
|
114437
114476
|
unregisterSession(sessionId) {
|
|
114438
114477
|
if (this.sessions.has(sessionId)) {
|
|
114439
114478
|
console.error(`🗑️ Unregistering AI session: ${sessionId}`);
|
|
114479
|
+
const agent = this.sessions.get(sessionId);
|
|
114440
114480
|
this.sessions.delete(sessionId);
|
|
114481
|
+
// Cleanup the ProbeAgent instance to prevent hanging processes
|
|
114482
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
114483
|
+
if (agent && typeof agent.cleanup === 'function') {
|
|
114484
|
+
try {
|
|
114485
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
114486
|
+
agent.cleanup();
|
|
114487
|
+
}
|
|
114488
|
+
catch (error) {
|
|
114489
|
+
console.error(`⚠️ Warning: Failed to cleanup ProbeAgent: ${error}`);
|
|
114490
|
+
}
|
|
114491
|
+
}
|
|
114441
114492
|
}
|
|
114442
114493
|
}
|
|
114443
114494
|
/**
|
|
@@ -114445,6 +114496,19 @@ class SessionRegistry {
|
|
|
114445
114496
|
*/
|
|
114446
114497
|
clearAllSessions() {
|
|
114447
114498
|
console.error(`🧹 Clearing all AI sessions (${this.sessions.size} sessions)`);
|
|
114499
|
+
// Cleanup each ProbeAgent instance before clearing
|
|
114500
|
+
for (const [, agent] of this.sessions.entries()) {
|
|
114501
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
114502
|
+
if (agent && typeof agent.cleanup === 'function') {
|
|
114503
|
+
try {
|
|
114504
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
114505
|
+
agent.cleanup();
|
|
114506
|
+
}
|
|
114507
|
+
catch {
|
|
114508
|
+
// Silent fail during bulk cleanup
|
|
114509
|
+
}
|
|
114510
|
+
}
|
|
114511
|
+
}
|
|
114448
114512
|
this.sessions.clear();
|
|
114449
114513
|
}
|
|
114450
114514
|
/**
|
|
@@ -114459,6 +114523,51 @@ class SessionRegistry {
|
|
|
114459
114523
|
hasSession(sessionId) {
|
|
114460
114524
|
return this.sessions.has(sessionId);
|
|
114461
114525
|
}
|
|
114526
|
+
/**
|
|
114527
|
+
* Register process exit handlers to cleanup sessions on exit
|
|
114528
|
+
*/
|
|
114529
|
+
registerExitHandlers() {
|
|
114530
|
+
if (this.exitHandlerRegistered) {
|
|
114531
|
+
return;
|
|
114532
|
+
}
|
|
114533
|
+
const cleanupAndExit = (signal) => {
|
|
114534
|
+
if (this.sessions.size > 0) {
|
|
114535
|
+
console.error(`\n🧹 [${signal}] Cleaning up ${this.sessions.size} active AI sessions...`);
|
|
114536
|
+
this.clearAllSessions();
|
|
114537
|
+
}
|
|
114538
|
+
};
|
|
114539
|
+
// Handle normal process exit
|
|
114540
|
+
process.on('exit', () => {
|
|
114541
|
+
if (this.sessions.size > 0) {
|
|
114542
|
+
console.error(`🧹 [exit] Cleaning up ${this.sessions.size} active AI sessions...`);
|
|
114543
|
+
// Note: async operations won't complete here, but sync cleanup methods will
|
|
114544
|
+
for (const [, agent] of this.sessions.entries()) {
|
|
114545
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
114546
|
+
if (agent && typeof agent.cleanup === 'function') {
|
|
114547
|
+
try {
|
|
114548
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
114549
|
+
agent.cleanup();
|
|
114550
|
+
}
|
|
114551
|
+
catch {
|
|
114552
|
+
// Silent fail on exit
|
|
114553
|
+
}
|
|
114554
|
+
}
|
|
114555
|
+
}
|
|
114556
|
+
this.sessions.clear();
|
|
114557
|
+
}
|
|
114558
|
+
});
|
|
114559
|
+
// Handle SIGINT (Ctrl+C)
|
|
114560
|
+
process.on('SIGINT', () => {
|
|
114561
|
+
cleanupAndExit('SIGINT');
|
|
114562
|
+
process.exit(0);
|
|
114563
|
+
});
|
|
114564
|
+
// Handle SIGTERM
|
|
114565
|
+
process.on('SIGTERM', () => {
|
|
114566
|
+
cleanupAndExit('SIGTERM');
|
|
114567
|
+
process.exit(0);
|
|
114568
|
+
});
|
|
114569
|
+
this.exitHandlerRegistered = true;
|
|
114570
|
+
}
|
|
114462
114571
|
}
|
|
114463
114572
|
exports.SessionRegistry = SessionRegistry;
|
|
114464
114573
|
|
|
@@ -228692,7 +228801,7 @@ module.exports = /*#__PURE__*/JSON.parse('{"application/1d-interleaved-parityfec
|
|
|
228692
228801
|
/***/ ((module) => {
|
|
228693
228802
|
|
|
228694
228803
|
"use strict";
|
|
228695
|
-
module.exports = {"rE":"0.1.
|
|
228804
|
+
module.exports = {"rE":"0.1.81"};
|
|
228696
228805
|
|
|
228697
228806
|
/***/ })
|
|
228698
228807
|
|
|
@@ -35,10 +35,6 @@ export declare class AICheckProvider extends CheckProvider {
|
|
|
35
35
|
* Render Liquid template in prompt with comprehensive event context
|
|
36
36
|
*/
|
|
37
37
|
private renderPromptTemplate;
|
|
38
|
-
/**
|
|
39
|
-
* Setup MCP tools based on AI configuration
|
|
40
|
-
*/
|
|
41
|
-
private setupMcpTools;
|
|
42
38
|
execute(prInfo: PRInfo, config: CheckProviderConfig, _dependencyResults?: Map<string, ReviewSummary>, sessionInfo?: {
|
|
43
39
|
parentSessionId?: string;
|
|
44
40
|
reuseSession?: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ai-check-provider.d.ts","sourceRoot":"","sources":["file:///home/runner/work/visor/visor/src/providers/ai-check-provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAChF,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"ai-check-provider.d.ts","sourceRoot":"","sources":["file:///home/runner/work/visor/visor/src/providers/ai-check-provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAChF,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAS5C;;GAEG;AACH,qBAAa,eAAgB,SAAQ,aAAa;IAChD,OAAO,CAAC,eAAe,CAAkB;IACzC,OAAO,CAAC,YAAY,CAAS;;IAQ7B,OAAO,IAAI,MAAM;IAIjB,cAAc,IAAI,MAAM;IAIlB,cAAc,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAoDvD;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAqB1B;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAiB7B;;OAEG;YACW,aAAa;IAmB3B;;OAEG;YACW,UAAU;IAsExB;;OAEG;YACW,kBAAkB;IA0ChC;;OAEG;YACW,oBAAoB;IA0I5B,OAAO,CACX,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,mBAAmB,EAC3B,kBAAkB,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,EAC/C,WAAW,CAAC,EAAE;QAAE,eAAe,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,OAAO,CAAA;KAAE,GACjE,OAAO,CAAC,aAAa,CAAC;YAiBX,iBAAiB;IAoL/B,sBAAsB,IAAI,MAAM,EAAE;IAmB5B,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAYrC,eAAe,IAAI,MAAM,EAAE;CAQ5B"}
|
|
@@ -28,10 +28,6 @@ export declare class ClaudeCodeCheckProvider extends CheckProvider {
|
|
|
28
28
|
* Initialize Claude Code SDK client
|
|
29
29
|
*/
|
|
30
30
|
private initializeClaudeCodeClient;
|
|
31
|
-
/**
|
|
32
|
-
* Setup MCP tools based on configuration
|
|
33
|
-
*/
|
|
34
|
-
private setupMcpTools;
|
|
35
31
|
/**
|
|
36
32
|
* Group files by their file extension for template context
|
|
37
33
|
*/
|