@probelabs/visor 0.1.80 → 0.1.82

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- process.env.VISOR_VERSION = '0.1.80';
2
+ process.env.VISOR_VERSION = '0.1.82';
3
3
  process.env.PROBE_VERSION = '0.6.0-rc122';
4
4
  /******/ (() => { // webpackBootstrap
5
5
  /******/ var __webpack_modules__ = ({
@@ -102612,155 +102612,173 @@ class CheckExecutionEngine {
102612
102612
  if (isForEachDependent && forEachParentName) {
102613
102613
  // Record forEach preview items
102614
102614
  this.recordForEachPreview(checkName, forEachItems);
102615
- if (debug) {
102616
- log(`🔄 Debug: Check "${checkName}" depends on forEach check "${forEachParentName}", executing ${forEachItems.length} times`);
102615
+ // If the forEach parent returned an empty array, skip this check entirely
102616
+ if (forEachItems.length === 0) {
102617
+ if (debug) {
102618
+ log(`🔄 Debug: Skipping check "${checkName}" - forEach check "${forEachParentName}" returned 0 items`);
102619
+ }
102620
+ logger_1.logger.info(` forEach: no items from "${forEachParentName}", skipping check...`);
102621
+ // Return a special marker result so that dependent checks can detect the skip
102622
+ finalResult = {
102623
+ issues: [],
102624
+ output: [],
102625
+ };
102626
+ // Mark this result as forEach-capable but with empty items
102627
+ finalResult.isForEach = true;
102628
+ finalResult.forEachItems = [];
102629
+ // Skip to the end - don't execute this check
102617
102630
  }
102618
- // Log forEach processing start (non-debug)
102619
- logger_1.logger.info(` forEach: processing ${forEachItems.length} items from "${forEachParentName}"...`);
102620
- const allIssues = [];
102621
- const allOutputs = [];
102622
- const aggregatedContents = [];
102623
- // Create task functions (not executed yet) - these will be executed with controlled concurrency
102624
- // via executeWithLimitedParallelism to respect maxParallelism setting
102625
- const itemTasks = forEachItems.map((item, itemIndex) => async () => {
102626
- // Create modified dependency results with current item
102627
- // For forEach branching: unwrap ALL forEach parents to create isolated execution branch
102628
- const forEachDependencyResults = new Map();
102629
- for (const [depName, depResult] of dependencyResults) {
102630
- if (forEachParents.includes(depName)) {
102631
- // This is a forEach parent - unwrap its output for this iteration
102632
- const depForEachResult = depResult;
102633
- if (Array.isArray(depForEachResult.output) &&
102634
- depForEachResult.output[itemIndex] !== undefined) {
102635
- // Unwrap to the item at the current index
102636
- const modifiedResult = {
102637
- issues: [],
102638
- output: depForEachResult.output[itemIndex],
102639
- };
102640
- forEachDependencyResults.set(depName, modifiedResult);
102641
- // Also provide -raw access to the full array
102642
- const rawResult = {
102643
- issues: [],
102644
- output: depForEachResult.output,
102645
- };
102646
- forEachDependencyResults.set(`${depName}-raw`, rawResult);
102631
+ else {
102632
+ if (debug) {
102633
+ log(`🔄 Debug: Check "${checkName}" depends on forEach check "${forEachParentName}", executing ${forEachItems.length} times`);
102634
+ }
102635
+ // Log forEach processing start (non-debug)
102636
+ logger_1.logger.info(` forEach: processing ${forEachItems.length} items from "${forEachParentName}"...`);
102637
+ const allIssues = [];
102638
+ const allOutputs = [];
102639
+ const aggregatedContents = [];
102640
+ // Create task functions (not executed yet) - these will be executed with controlled concurrency
102641
+ // via executeWithLimitedParallelism to respect maxParallelism setting
102642
+ const itemTasks = forEachItems.map((item, itemIndex) => async () => {
102643
+ // Create modified dependency results with current item
102644
+ // For forEach branching: unwrap ALL forEach parents to create isolated execution branch
102645
+ const forEachDependencyResults = new Map();
102646
+ for (const [depName, depResult] of dependencyResults) {
102647
+ if (forEachParents.includes(depName)) {
102648
+ // This is a forEach parent - unwrap its output for this iteration
102649
+ const depForEachResult = depResult;
102650
+ if (Array.isArray(depForEachResult.output) &&
102651
+ depForEachResult.output[itemIndex] !== undefined) {
102652
+ // Unwrap to the item at the current index
102653
+ const modifiedResult = {
102654
+ issues: [],
102655
+ output: depForEachResult.output[itemIndex],
102656
+ };
102657
+ forEachDependencyResults.set(depName, modifiedResult);
102658
+ // Also provide -raw access to the full array
102659
+ const rawResult = {
102660
+ issues: [],
102661
+ output: depForEachResult.output,
102662
+ };
102663
+ forEachDependencyResults.set(`${depName}-raw`, rawResult);
102664
+ }
102665
+ else {
102666
+ // Fallback: use the result as-is
102667
+ forEachDependencyResults.set(depName, depResult);
102668
+ }
102647
102669
  }
102648
102670
  else {
102649
- // Fallback: use the result as-is
102650
102671
  forEachDependencyResults.set(depName, depResult);
102651
102672
  }
102652
102673
  }
102653
- else {
102654
- forEachDependencyResults.set(depName, depResult);
102674
+ // Evaluate if condition for this forEach item
102675
+ if (checkConfig.if) {
102676
+ // Merge current results with forEach-specific dependency results for condition evaluation
102677
+ const conditionResults = new Map(results);
102678
+ for (const [depName, depResult] of forEachDependencyResults) {
102679
+ conditionResults.set(depName, depResult);
102680
+ }
102681
+ const shouldRun = await this.evaluateCheckCondition(checkName, checkConfig.if, prInfo, conditionResults, debug);
102682
+ if (!shouldRun) {
102683
+ if (debug) {
102684
+ log(`🔄 Debug: Skipping forEach item ${itemIndex + 1} for check "${checkName}" (if condition evaluated to false)`);
102685
+ }
102686
+ // Return empty result for skipped items
102687
+ return {
102688
+ index: itemIndex,
102689
+ itemResult: { issues: [] },
102690
+ skipped: true,
102691
+ };
102692
+ }
102655
102693
  }
102656
- }
102657
- // Evaluate if condition for this forEach item
102658
- if (checkConfig.if) {
102659
- // Merge current results with forEach-specific dependency results for condition evaluation
102660
- const conditionResults = new Map(results);
102661
- for (const [depName, depResult] of forEachDependencyResults) {
102662
- conditionResults.set(depName, depResult);
102694
+ if (debug) {
102695
+ log(`🔄 Debug: Executing check "${checkName}" for item ${itemIndex + 1}/${forEachItems.length}`);
102663
102696
  }
102664
- const shouldRun = await this.evaluateCheckCondition(checkName, checkConfig.if, prInfo, conditionResults, debug);
102665
- if (!shouldRun) {
102697
+ // Track iteration start
102698
+ const iterationStart = this.recordIterationStart(checkName);
102699
+ // Execute with retry/routing semantics per item
102700
+ const itemResult = await this.executeWithRouting(checkName, checkConfig, provider, providerConfig, prInfo, forEachDependencyResults, sessionInfo, config, dependencyGraph, debug, results,
102701
+ /*foreachContext*/ {
102702
+ index: itemIndex,
102703
+ total: forEachItems.length,
102704
+ parent: forEachParentName,
102705
+ });
102706
+ // Record iteration completion
102707
+ // Check if this iteration had fatal errors
102708
+ const hadFatalError = (itemResult.issues || []).some(issue => {
102709
+ const id = issue.ruleId || '';
102710
+ return (id === 'command/execution_error' ||
102711
+ id.endsWith('/command/execution_error') ||
102712
+ id === 'command/transform_js_error' ||
102713
+ id.endsWith('/command/transform_js_error') ||
102714
+ id === 'command/transform_error' ||
102715
+ id.endsWith('/command/transform_error'));
102716
+ });
102717
+ const iterationDuration = (Date.now() - iterationStart) / 1000;
102718
+ this.recordIterationComplete(checkName, iterationStart, !hadFatalError, // Success if no fatal errors
102719
+ itemResult.issues || [], itemResult.output);
102720
+ // Log iteration progress
102721
+ logger_1.logger.info(` ✔ ${itemIndex + 1}/${forEachItems.length} (${iterationDuration.toFixed(1)}s)`);
102722
+ return { index: itemIndex, itemResult };
102723
+ });
102724
+ const forEachConcurrency = Math.max(1, Math.min(forEachItems.length, effectiveMaxParallelism));
102725
+ if (debug && forEachConcurrency > 1) {
102726
+ log(`🔄 Debug: Limiting forEach concurrency for check "${checkName}" to ${forEachConcurrency}`);
102727
+ }
102728
+ const forEachResults = await this.executeWithLimitedParallelism(itemTasks, forEachConcurrency, false);
102729
+ for (const result of forEachResults) {
102730
+ if (result.status === 'rejected') {
102731
+ // Instead of throwing, record the failure and continue with other iterations
102732
+ const error = result.reason;
102733
+ const errorMessage = error instanceof Error ? error.message : String(error);
102734
+ // Create an error issue for this failed iteration
102735
+ allIssues.push({
102736
+ ruleId: `${checkName}/forEach/iteration_error`,
102737
+ severity: 'error',
102738
+ category: 'logic',
102739
+ message: `forEach iteration failed: ${errorMessage}`,
102740
+ file: '',
102741
+ line: 0,
102742
+ });
102666
102743
  if (debug) {
102667
- log(`🔄 Debug: Skipping forEach item ${itemIndex + 1} for check "${checkName}" (if condition evaluated to false)`);
102744
+ log(`🔄 Debug: forEach iteration for check "${checkName}" failed: ${errorMessage}`);
102668
102745
  }
102669
- // Return empty result for skipped items
102670
- return {
102671
- index: itemIndex,
102672
- itemResult: { issues: [] },
102673
- skipped: true,
102674
- };
102746
+ continue;
102675
102747
  }
102676
- }
102677
- if (debug) {
102678
- log(`🔄 Debug: Executing check "${checkName}" for item ${itemIndex + 1}/${forEachItems.length}`);
102679
- }
102680
- // Track iteration start
102681
- const iterationStart = this.recordIterationStart(checkName);
102682
- // Execute with retry/routing semantics per item
102683
- const itemResult = await this.executeWithRouting(checkName, checkConfig, provider, providerConfig, prInfo, forEachDependencyResults, sessionInfo, config, dependencyGraph, debug, results,
102684
- /*foreachContext*/ {
102685
- index: itemIndex,
102686
- total: forEachItems.length,
102687
- parent: forEachParentName,
102688
- });
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
- });
102700
- const iterationDuration = (Date.now() - iterationStart) / 1000;
102701
- this.recordIterationComplete(checkName, iterationStart, !hadFatalError, // Success if no fatal errors
102702
- itemResult.issues || [], itemResult.output);
102703
- // Log iteration progress
102704
- logger_1.logger.info(` ✔ ${itemIndex + 1}/${forEachItems.length} (${iterationDuration.toFixed(1)}s)`);
102705
- return { index: itemIndex, itemResult };
102706
- });
102707
- const forEachConcurrency = Math.max(1, Math.min(forEachItems.length, effectiveMaxParallelism));
102708
- if (debug && forEachConcurrency > 1) {
102709
- log(`🔄 Debug: Limiting forEach concurrency for check "${checkName}" to ${forEachConcurrency}`);
102710
- }
102711
- const forEachResults = await this.executeWithLimitedParallelism(itemTasks, forEachConcurrency, false);
102712
- for (const result of forEachResults) {
102713
- if (result.status === 'rejected') {
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}`);
102748
+ // Skip results from skipped items (those that failed if condition)
102749
+ if (result.value.skipped) {
102750
+ continue;
102751
+ }
102752
+ const { itemResult } = result.value;
102753
+ if (itemResult.issues) {
102754
+ allIssues.push(...itemResult.issues);
102755
+ }
102756
+ const resultWithOutput = itemResult;
102757
+ if (resultWithOutput.output !== undefined) {
102758
+ allOutputs.push(resultWithOutput.output);
102759
+ }
102760
+ const itemContent = resultWithOutput.content;
102761
+ if (typeof itemContent === 'string' && itemContent.trim()) {
102762
+ aggregatedContents.push(itemContent.trim());
102728
102763
  }
102729
- continue;
102730
- }
102731
- // Skip results from skipped items (those that failed if condition)
102732
- if (result.value.skipped) {
102733
- continue;
102734
- }
102735
- const { itemResult } = result.value;
102736
- if (itemResult.issues) {
102737
- allIssues.push(...itemResult.issues);
102738
102764
  }
102739
- const resultWithOutput = itemResult;
102740
- if (resultWithOutput.output !== undefined) {
102741
- allOutputs.push(resultWithOutput.output);
102765
+ const finalOutput = allOutputs.length > 0 ? allOutputs : undefined;
102766
+ finalResult = {
102767
+ issues: allIssues,
102768
+ ...(finalOutput !== undefined ? { output: finalOutput } : {}),
102769
+ };
102770
+ // IMPORTANT: Mark this result as forEach-capable so that checks depending on it
102771
+ // will also iterate over the items (propagate forEach behavior down the chain)
102772
+ if (allOutputs.length > 0) {
102773
+ finalResult.isForEach = true;
102774
+ finalResult.forEachItems = allOutputs;
102742
102775
  }
102743
- const itemContent = resultWithOutput.content;
102744
- if (typeof itemContent === 'string' && itemContent.trim()) {
102745
- aggregatedContents.push(itemContent.trim());
102776
+ if (aggregatedContents.length > 0) {
102777
+ finalResult.content =
102778
+ aggregatedContents.join('\n');
102746
102779
  }
102747
- }
102748
- const finalOutput = allOutputs.length > 0 ? allOutputs : undefined;
102749
- finalResult = {
102750
- issues: allIssues,
102751
- ...(finalOutput !== undefined ? { output: finalOutput } : {}),
102752
- };
102753
- // IMPORTANT: Mark this result as forEach-capable so that checks depending on it
102754
- // will also iterate over the items (propagate forEach behavior down the chain)
102755
- if (allOutputs.length > 0) {
102756
- finalResult.isForEach = true;
102757
- finalResult.forEachItems = allOutputs;
102758
- }
102759
- if (aggregatedContents.length > 0) {
102760
- finalResult.content =
102761
- aggregatedContents.join('\n');
102762
- }
102763
- log(`🔄 Debug: Completed forEach execution for check "${checkName}", total issues: ${allIssues.length}`);
102780
+ log(`🔄 Debug: Completed forEach execution for check "${checkName}", total issues: ${allIssues.length}`);
102781
+ } // End of else block for forEachItems.length > 0
102764
102782
  }
102765
102783
  else {
102766
102784
  // Normal single execution
@@ -102989,19 +103007,6 @@ class CheckExecutionEngine {
102989
103007
  }
102990
103008
  }
102991
103009
  }
102992
- // Build and log final execution summary
102993
- const executionStatistics = this.buildExecutionStatistics();
102994
- // Show detailed summary table (only if logFn outputs to console)
102995
- // Skip when output format is JSON/SARIF to avoid polluting structured output
102996
- // Check if logFn is console.log (not a no-op or console.error)
102997
- if (logFn === console.log) {
102998
- this.logExecutionSummary(executionStatistics);
102999
- }
103000
- // Add warning if execution stopped early
103001
- if (shouldStopExecution) {
103002
- logger_1.logger.info('');
103003
- logger_1.logger.warn(`⚠️ Execution stopped early due to fail-fast`);
103004
- }
103005
103010
  if (debug) {
103006
103011
  if (shouldStopExecution) {
103007
103012
  log(`🛑 Execution stopped early due to fail-fast after processing ${results.size} of ${checks.length} checks`);
@@ -103010,7 +103015,7 @@ class CheckExecutionEngine {
103010
103015
  log(`✅ Dependency-aware execution completed successfully for all ${results.size} checks`);
103011
103016
  }
103012
103017
  }
103013
- // Cleanup sessions after execution
103018
+ // Cleanup sessions BEFORE printing summary to avoid mixing debug logs with table output
103014
103019
  if (sessionIds.size > 0 && debug) {
103015
103020
  log(`🧹 Cleaning up ${sessionIds.size} AI sessions...`);
103016
103021
  for (const [checkName, sessionId] of sessionIds) {
@@ -103023,6 +103028,19 @@ class CheckExecutionEngine {
103023
103028
  }
103024
103029
  }
103025
103030
  }
103031
+ // Build and log final execution summary
103032
+ const executionStatistics = this.buildExecutionStatistics();
103033
+ // Show detailed summary table (only if logFn outputs to console)
103034
+ // Skip when output format is JSON/SARIF to avoid polluting structured output
103035
+ // Check if logFn is console.log (not a no-op or console.error)
103036
+ if (logFn === console.log) {
103037
+ this.logExecutionSummary(executionStatistics);
103038
+ }
103039
+ // Add warning if execution stopped early
103040
+ if (shouldStopExecution) {
103041
+ logger_1.logger.info('');
103042
+ logger_1.logger.warn(`⚠️ Execution stopped early due to fail-fast`);
103043
+ }
103026
103044
  // Aggregate all results
103027
103045
  return this.aggregateDependencyAwareResults(results, dependencyGraph, debug, shouldStopExecution);
103028
103046
  }
@@ -104577,9 +104595,18 @@ async function main() {
104577
104595
  const hasRepositoryError = allResults.some((result) => {
104578
104596
  return result.content.includes('Not a git repository');
104579
104597
  });
104580
- if (criticalCount > 0 || hasRepositoryError) {
104581
- process.exit(1);
104598
+ // Cleanup AI sessions before exit to prevent process hanging
104599
+ const { SessionRegistry } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(46059)));
104600
+ const sessionRegistry = SessionRegistry.getInstance();
104601
+ if (sessionRegistry.getActiveSessionIds().length > 0) {
104602
+ logger_1.logger.debug(`🧹 Cleaning up ${sessionRegistry.getActiveSessionIds().length} active AI sessions...`);
104603
+ sessionRegistry.clearAllSessions();
104582
104604
  }
104605
+ // Force exit to prevent hanging from unclosed resources (MCP connections, etc.)
104606
+ // This is necessary because some async resources may not be properly cleaned up
104607
+ // and can keep the event loop alive indefinitely
104608
+ const exitCode = criticalCount > 0 || hasRepositoryError ? 1 : 0;
104609
+ process.exit(exitCode);
104583
104610
  }
104584
104611
  catch (error) {
104585
104612
  // Import error classes dynamically to avoid circular dependencies
@@ -109033,6 +109060,15 @@ async function run() {
109033
109060
  (0, core_1.setFailed)(error instanceof Error ? error.message : 'Unknown error');
109034
109061
  }
109035
109062
  }
109063
+ finally {
109064
+ // Cleanup AI sessions before GitHub Action exits to prevent process hanging
109065
+ const { SessionRegistry } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(46059)));
109066
+ const sessionRegistry = SessionRegistry.getInstance();
109067
+ if (sessionRegistry.getActiveSessionIds().length > 0) {
109068
+ console.log(`🧹 Cleaning up ${sessionRegistry.getActiveSessionIds().length} active AI sessions...`);
109069
+ sessionRegistry.clearAllSessions();
109070
+ }
109071
+ }
109036
109072
  }
109037
109073
  function mapGitHubEventToTrigger(eventName, action) {
109038
109074
  if (!eventName)
@@ -111256,7 +111292,6 @@ const issue_filter_1 = __nccwpck_require__(36879);
111256
111292
  const liquid_extensions_1 = __nccwpck_require__(33042);
111257
111293
  const promises_1 = __importDefault(__nccwpck_require__(91943));
111258
111294
  const path_1 = __importDefault(__nccwpck_require__(16928));
111259
- const claude_code_types_1 = __nccwpck_require__(21710);
111260
111295
  /**
111261
111296
  * AI-powered check provider using probe agent
111262
111297
  */
@@ -111583,53 +111618,6 @@ class AICheckProvider extends check_provider_interface_1.CheckProvider {
111583
111618
  throw new Error(`Failed to render prompt template: ${error instanceof Error ? error.message : 'Unknown error'}`);
111584
111619
  }
111585
111620
  }
111586
- /**
111587
- * Setup MCP tools based on AI configuration
111588
- */
111589
- async setupMcpTools(aiConfig) {
111590
- const tools = [];
111591
- // Setup custom MCP servers if configured
111592
- if (aiConfig.mcpServers) {
111593
- try {
111594
- // Import MCP SDK for custom server creation using safe import
111595
- const mcpModule = await (0, claude_code_types_1.safeImport)('@modelcontextprotocol/sdk');
111596
- if (!mcpModule) {
111597
- console.warn('@modelcontextprotocol/sdk package not found. MCP servers disabled.');
111598
- return tools;
111599
- }
111600
- const createSdkMcpServer = mcpModule.createSdkMcpServer || mcpModule.default?.createSdkMcpServer;
111601
- if (typeof createSdkMcpServer === 'function') {
111602
- for (const [serverName, serverConfig] of Object.entries(aiConfig.mcpServers)) {
111603
- try {
111604
- // Create MCP server instance
111605
- const server = await createSdkMcpServer({
111606
- name: serverName,
111607
- command: serverConfig.command,
111608
- args: serverConfig.args || [],
111609
- env: { ...process.env, ...serverConfig.env },
111610
- });
111611
- // Add server tools to available tools
111612
- const serverTools = (await server.listTools());
111613
- tools.push(...serverTools.map(tool => ({
111614
- name: tool.name,
111615
- server: serverName,
111616
- })));
111617
- }
111618
- catch (serverError) {
111619
- console.warn(`Failed to setup MCP server ${serverName}: ${serverError instanceof Error ? serverError.message : 'Unknown error'}`);
111620
- }
111621
- }
111622
- }
111623
- else {
111624
- console.warn('createSdkMcpServer function not found in @modelcontextprotocol/sdk. MCP servers disabled.');
111625
- }
111626
- }
111627
- catch (error) {
111628
- console.warn(`Failed to import MCP SDK: ${error instanceof Error ? error.message : 'Unknown error'}. MCP servers disabled.`);
111629
- }
111630
- }
111631
- return tools;
111632
- }
111633
111621
  async execute(prInfo, config, _dependencyResults, sessionInfo) {
111634
111622
  // Apply environment configuration if present
111635
111623
  if (config.env) {
@@ -111693,15 +111681,12 @@ class AICheckProvider extends check_provider_interface_1.CheckProvider {
111693
111681
  if (config.ai?.mcpServers) {
111694
111682
  Object.assign(mcpServers, config.ai.mcpServers);
111695
111683
  }
111696
- // Setup MCP tools if any servers are configured
111684
+ // Pass MCP server config directly to AI service
111697
111685
  if (Object.keys(mcpServers).length > 0) {
111698
- // Pass raw server config to AI service so it can enable MCP in ProbeAgent
111686
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
111699
111687
  aiConfig.mcpServers = mcpServers;
111700
- // Optional: attempt to enumerate tools for debug visibility (not required for functionality)
111701
- const mcpConfig = { mcpServers };
111702
- const mcpTools = await this.setupMcpTools(mcpConfig);
111703
111688
  if (aiConfig.debug) {
111704
- console.error(`🔧 Debug: AI check MCP configured with ${Object.keys(mcpServers).length} servers; discovered ${mcpTools.length} tools`);
111689
+ console.error(`🔧 Debug: AI check MCP configured with ${Object.keys(mcpServers).length} servers`);
111705
111690
  }
111706
111691
  }
111707
111692
  // Process prompt with Liquid templates and file loading
@@ -112115,59 +112100,6 @@ class ClaudeCodeCheckProvider extends check_provider_interface_1.CheckProvider {
112115
112100
  throw new Error(`Failed to initialize Claude Code SDK: ${error instanceof Error ? error.message : 'Unknown error'}`);
112116
112101
  }
112117
112102
  }
112118
- /**
112119
- * Setup MCP tools based on configuration
112120
- */
112121
- async setupMcpTools(config) {
112122
- const tools = [];
112123
- // Add allowed tools
112124
- if (config.allowedTools) {
112125
- for (const toolName of config.allowedTools) {
112126
- tools.push({ name: toolName });
112127
- }
112128
- }
112129
- // Setup custom MCP servers if configured
112130
- if (config.mcpServers) {
112131
- try {
112132
- // Import MCP SDK for custom server creation using safe import
112133
- const mcpModule = await (0, claude_code_types_1.safeImport)('@modelcontextprotocol/sdk');
112134
- if (!mcpModule) {
112135
- console.warn('@modelcontextprotocol/sdk package not found. MCP servers disabled.');
112136
- return tools;
112137
- }
112138
- const createSdkMcpServer = mcpModule.createSdkMcpServer || mcpModule.default?.createSdkMcpServer;
112139
- if (typeof createSdkMcpServer === 'function') {
112140
- for (const [serverName, serverConfig] of Object.entries(config.mcpServers)) {
112141
- try {
112142
- // Create MCP server instance
112143
- const server = await createSdkMcpServer({
112144
- name: serverName,
112145
- command: serverConfig.command,
112146
- args: serverConfig.args || [],
112147
- env: { ...process.env, ...serverConfig.env },
112148
- });
112149
- // Add server tools to available tools
112150
- const serverTools = (await server.listTools());
112151
- tools.push(...serverTools.map(tool => ({
112152
- name: tool.name,
112153
- server: serverName,
112154
- })));
112155
- }
112156
- catch (serverError) {
112157
- console.warn(`Failed to setup MCP server ${serverName}: ${serverError instanceof Error ? serverError.message : 'Unknown error'}`);
112158
- }
112159
- }
112160
- }
112161
- else {
112162
- console.warn('createSdkMcpServer function not found in @modelcontextprotocol/sdk. MCP servers disabled.');
112163
- }
112164
- }
112165
- catch (error) {
112166
- console.warn(`Failed to import MCP SDK: ${error instanceof Error ? error.message : 'Unknown error'}. MCP servers disabled.`);
112167
- }
112168
- }
112169
- return tools;
112170
- }
112171
112103
  /**
112172
112104
  * Group files by their file extension for template context
112173
112105
  */
@@ -112432,16 +112364,22 @@ class ClaudeCodeCheckProvider extends check_provider_interface_1.CheckProvider {
112432
112364
  try {
112433
112365
  // Initialize Claude Code client
112434
112366
  const client = await this.initializeClaudeCodeClient();
112435
- // Setup MCP tools
112436
- const tools = await this.setupMcpTools(claudeCodeConfig);
112437
- // Prepare query object
112367
+ // Prepare query object with MCP servers passed directly to SDK
112438
112368
  const query = {
112439
112369
  query: processedPrompt,
112440
- tools: tools.length > 0 ? tools : undefined,
112441
112370
  maxTurns: claudeCodeConfig.maxTurns || 5,
112442
112371
  systemPrompt: claudeCodeConfig.systemPrompt,
112443
112372
  subagent: claudeCodeConfig.subagent,
112444
112373
  };
112374
+ // Add allowed tools if specified
112375
+ if (claudeCodeConfig.allowedTools && claudeCodeConfig.allowedTools.length > 0) {
112376
+ query.tools = claudeCodeConfig.allowedTools.map(name => ({ name }));
112377
+ }
112378
+ // Pass MCP servers directly to the SDK - let it handle spawning and tool discovery
112379
+ if (claudeCodeConfig.mcpServers && Object.keys(claudeCodeConfig.mcpServers).length > 0) {
112380
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
112381
+ query.mcpServers = claudeCodeConfig.mcpServers;
112382
+ }
112445
112383
  // Execute query with Claude Code
112446
112384
  let response;
112447
112385
  if (sessionInfo?.reuseSession && sessionInfo.parentSessionId) {
@@ -112475,7 +112413,6 @@ class ClaudeCodeCheckProvider extends check_provider_interface_1.CheckProvider {
112475
112413
  sessionId: response.session_id,
112476
112414
  turnCount: response.turn_count,
112477
112415
  usage: response.usage,
112478
- toolsUsed: tools.map(t => t.name),
112479
112416
  };
112480
112417
  // Apply issue suppression filtering
112481
112418
  const suppressionEnabled = config.suppressionEnabled !== false;
@@ -114522,7 +114459,11 @@ exports.SessionRegistry = void 0;
114522
114459
  class SessionRegistry {
114523
114460
  static instance;
114524
114461
  sessions = new Map();
114525
- constructor() { }
114462
+ exitHandlerRegistered = false;
114463
+ constructor() {
114464
+ // Register process exit handlers to cleanup sessions
114465
+ this.registerExitHandlers();
114466
+ }
114526
114467
  /**
114527
114468
  * Get the singleton instance of SessionRegistry
114528
114469
  */
@@ -114555,7 +114496,19 @@ class SessionRegistry {
114555
114496
  unregisterSession(sessionId) {
114556
114497
  if (this.sessions.has(sessionId)) {
114557
114498
  console.error(`🗑️ Unregistering AI session: ${sessionId}`);
114499
+ const agent = this.sessions.get(sessionId);
114558
114500
  this.sessions.delete(sessionId);
114501
+ // Cleanup the ProbeAgent instance to prevent hanging processes
114502
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
114503
+ if (agent && typeof agent.cleanup === 'function') {
114504
+ try {
114505
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
114506
+ agent.cleanup();
114507
+ }
114508
+ catch (error) {
114509
+ console.error(`⚠️ Warning: Failed to cleanup ProbeAgent: ${error}`);
114510
+ }
114511
+ }
114559
114512
  }
114560
114513
  }
114561
114514
  /**
@@ -114563,6 +114516,19 @@ class SessionRegistry {
114563
114516
  */
114564
114517
  clearAllSessions() {
114565
114518
  console.error(`🧹 Clearing all AI sessions (${this.sessions.size} sessions)`);
114519
+ // Cleanup each ProbeAgent instance before clearing
114520
+ for (const [, agent] of this.sessions.entries()) {
114521
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
114522
+ if (agent && typeof agent.cleanup === 'function') {
114523
+ try {
114524
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
114525
+ agent.cleanup();
114526
+ }
114527
+ catch {
114528
+ // Silent fail during bulk cleanup
114529
+ }
114530
+ }
114531
+ }
114566
114532
  this.sessions.clear();
114567
114533
  }
114568
114534
  /**
@@ -114577,6 +114543,51 @@ class SessionRegistry {
114577
114543
  hasSession(sessionId) {
114578
114544
  return this.sessions.has(sessionId);
114579
114545
  }
114546
+ /**
114547
+ * Register process exit handlers to cleanup sessions on exit
114548
+ */
114549
+ registerExitHandlers() {
114550
+ if (this.exitHandlerRegistered) {
114551
+ return;
114552
+ }
114553
+ const cleanupAndExit = (signal) => {
114554
+ if (this.sessions.size > 0) {
114555
+ console.error(`\n🧹 [${signal}] Cleaning up ${this.sessions.size} active AI sessions...`);
114556
+ this.clearAllSessions();
114557
+ }
114558
+ };
114559
+ // Handle normal process exit
114560
+ process.on('exit', () => {
114561
+ if (this.sessions.size > 0) {
114562
+ console.error(`🧹 [exit] Cleaning up ${this.sessions.size} active AI sessions...`);
114563
+ // Note: async operations won't complete here, but sync cleanup methods will
114564
+ for (const [, agent] of this.sessions.entries()) {
114565
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
114566
+ if (agent && typeof agent.cleanup === 'function') {
114567
+ try {
114568
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
114569
+ agent.cleanup();
114570
+ }
114571
+ catch {
114572
+ // Silent fail on exit
114573
+ }
114574
+ }
114575
+ }
114576
+ this.sessions.clear();
114577
+ }
114578
+ });
114579
+ // Handle SIGINT (Ctrl+C)
114580
+ process.on('SIGINT', () => {
114581
+ cleanupAndExit('SIGINT');
114582
+ process.exit(0);
114583
+ });
114584
+ // Handle SIGTERM
114585
+ process.on('SIGTERM', () => {
114586
+ cleanupAndExit('SIGTERM');
114587
+ process.exit(0);
114588
+ });
114589
+ this.exitHandlerRegistered = true;
114590
+ }
114580
114591
  }
114581
114592
  exports.SessionRegistry = SessionRegistry;
114582
114593
 
@@ -228810,7 +228821,7 @@ module.exports = /*#__PURE__*/JSON.parse('{"application/1d-interleaved-parityfec
228810
228821
  /***/ ((module) => {
228811
228822
 
228812
228823
  "use strict";
228813
- module.exports = {"rE":"0.1.80"};
228824
+ module.exports = {"rE":"0.1.82"};
228814
228825
 
228815
228826
  /***/ })
228816
228827