@probelabs/visor 0.1.37 → 0.1.38

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
@@ -94976,6 +94976,40 @@ class CheckExecutionEngine {
94976
94976
  provider.setWebhookContext(this.webhookContext.webhookData);
94977
94977
  }
94978
94978
  }
94979
+ /**
94980
+ * Filter checks based on tag filter configuration
94981
+ */
94982
+ filterChecksByTags(checks, config, tagFilter) {
94983
+ if (!tagFilter || (!tagFilter.include && !tagFilter.exclude)) {
94984
+ return checks;
94985
+ }
94986
+ const logFn = this.config?.output?.pr_comment ? console.error : console.log;
94987
+ return checks.filter(checkName => {
94988
+ const checkConfig = config?.checks?.[checkName];
94989
+ if (!checkConfig) {
94990
+ // If no config for this check, include it by default
94991
+ return true;
94992
+ }
94993
+ const checkTags = checkConfig.tags || [];
94994
+ // Check exclude tags first (if any exclude tag matches, skip the check)
94995
+ if (tagFilter.exclude && tagFilter.exclude.length > 0) {
94996
+ const hasExcludedTag = tagFilter.exclude.some(tag => checkTags.includes(tag));
94997
+ if (hasExcludedTag) {
94998
+ logFn(`⏭️ Skipping check '${checkName}' - has excluded tag`);
94999
+ return false;
95000
+ }
95001
+ }
95002
+ // Check include tags (if specified, at least one must match)
95003
+ if (tagFilter.include && tagFilter.include.length > 0) {
95004
+ const hasIncludedTag = tagFilter.include.some(tag => checkTags.includes(tag));
95005
+ if (!hasIncludedTag) {
95006
+ logFn(`⏭️ Skipping check '${checkName}' - does not have required tags`);
95007
+ return false;
95008
+ }
95009
+ }
95010
+ return true;
95011
+ });
95012
+ }
94979
95013
  /**
94980
95014
  * Execute checks on the local repository
94981
95015
  */
@@ -95005,13 +95039,23 @@ class CheckExecutionEngine {
95005
95039
  }
95006
95040
  // Convert to PRInfo format for compatibility with existing reviewer
95007
95041
  const prInfo = this.gitAnalyzer.toPRInfo(repositoryInfo);
95042
+ // Apply tag filtering if specified
95043
+ const filteredChecks = this.filterChecksByTags(options.checks, options.config, options.tagFilter || options.config?.tag_filter);
95044
+ if (filteredChecks.length === 0) {
95045
+ logFn('⚠️ No checks match the tag filter criteria');
95046
+ // Complete GitHub checks with no checks message if they were initialized
95047
+ if (this.checkRunMap) {
95048
+ await this.completeGitHubChecksWithError('No checks match the tag filter criteria');
95049
+ }
95050
+ return this.createErrorResult(repositoryInfo, 'No checks match the tag filter criteria', startTime, timestamp, options.checks);
95051
+ }
95008
95052
  // Update GitHub checks to in-progress status
95009
95053
  if (this.checkRunMap) {
95010
95054
  await this.updateGitHubChecksInProgress(options);
95011
95055
  }
95012
95056
  // Execute checks using the existing PRReviewer
95013
- logFn(`🤖 Executing checks: ${options.checks.join(', ')}`);
95014
- const reviewSummary = await this.executeReviewChecks(prInfo, options.checks, options.timeout, options.config, options.outputFormat, options.debug, options.maxParallelism, options.failFast);
95057
+ logFn(`🤖 Executing checks: ${filteredChecks.join(', ')}`);
95058
+ const reviewSummary = await this.executeReviewChecks(prInfo, filteredChecks, options.timeout, options.config, options.outputFormat, options.debug, options.maxParallelism, options.failFast);
95015
95059
  // Complete GitHub checks with results
95016
95060
  if (this.checkRunMap) {
95017
95061
  await this.completeGitHubChecksWithResults(reviewSummary, options);
@@ -95035,7 +95079,7 @@ class CheckExecutionEngine {
95035
95079
  reviewSummary,
95036
95080
  executionTime,
95037
95081
  timestamp,
95038
- checksExecuted: options.checks,
95082
+ checksExecuted: filteredChecks,
95039
95083
  debug: debugInfo,
95040
95084
  };
95041
95085
  }
@@ -95237,7 +95281,7 @@ class CheckExecutionEngine {
95237
95281
  /**
95238
95282
  * Execute review checks and return grouped results for new architecture
95239
95283
  */
95240
- async executeGroupedChecks(prInfo, checks, timeout, config, outputFormat, debug, maxParallelism, failFast) {
95284
+ async executeGroupedChecks(prInfo, checks, timeout, config, outputFormat, debug, maxParallelism, failFast, tagFilter) {
95241
95285
  // Determine where to send log messages based on output format
95242
95286
  const logFn = outputFormat === 'json' || outputFormat === 'sarif' ? console.error : console.log;
95243
95287
  // Only output debug messages if debug mode is enabled
@@ -95250,8 +95294,18 @@ class CheckExecutionEngine {
95250
95294
  if (filteredChecks.length !== checks.length && debug) {
95251
95295
  logFn(`🔧 Debug: Event filtering reduced checks from ${checks.length} to ${filteredChecks.length}: ${JSON.stringify(filteredChecks)}`);
95252
95296
  }
95297
+ // Apply tag filtering if specified
95298
+ const tagFilteredChecks = this.filterChecksByTags(filteredChecks, config, tagFilter || config?.tag_filter);
95299
+ if (tagFilteredChecks.length !== filteredChecks.length && debug) {
95300
+ logFn(`🔧 Debug: Tag filtering reduced checks from ${filteredChecks.length} to ${tagFilteredChecks.length}: ${JSON.stringify(tagFilteredChecks)}`);
95301
+ }
95253
95302
  // Use filtered checks for execution
95254
- checks = filteredChecks;
95303
+ checks = tagFilteredChecks;
95304
+ // Check if we have any checks left after filtering
95305
+ if (checks.length === 0) {
95306
+ logFn('⚠️ No checks remain after tag filtering');
95307
+ return {};
95308
+ }
95255
95309
  if (!config?.checks) {
95256
95310
  throw new Error('Config with check definitions required for grouped execution');
95257
95311
  }
@@ -96799,17 +96853,35 @@ async function main() {
96799
96853
  logFn(`🤖 Executing checks: ${checksToRun.join(', ')}`);
96800
96854
  // Create CheckExecutionEngine for running checks
96801
96855
  const engine = new check_execution_engine_1.CheckExecutionEngine();
96856
+ // Build tag filter from CLI options
96857
+ const tagFilter = options.tags || options.excludeTags
96858
+ ? {
96859
+ include: options.tags,
96860
+ exclude: options.excludeTags,
96861
+ }
96862
+ : undefined;
96802
96863
  // Execute checks with proper parameters (cast to PRInfo)
96803
- const groupedResults = await engine.executeGroupedChecks(repositoryInfo, checksToRun, options.timeout, config, options.output, options.debug || false);
96864
+ const groupedResults = await engine.executeGroupedChecks(repositoryInfo, checksToRun, options.timeout, config, options.output, options.debug || false, options.maxParallelism, options.failFast, tagFilter);
96804
96865
  // Format output based on format type
96805
96866
  let output;
96806
96867
  if (options.output === 'json') {
96807
96868
  output = JSON.stringify(groupedResults, null, 2);
96808
96869
  }
96809
96870
  else if (options.output === 'sarif') {
96810
- // For SARIF output, we need to convert to SARIF format
96811
- // For now, output as JSON until proper SARIF formatting is implemented
96812
- output = JSON.stringify(groupedResults, null, 2);
96871
+ // Build analysis result and format as SARIF
96872
+ const analysisResult = {
96873
+ repositoryInfo,
96874
+ reviewSummary: {
96875
+ issues: Object.values(groupedResults)
96876
+ .flatMap((r) => r.map((check) => check.issues || []).flat())
96877
+ .flat(),
96878
+ suggestions: [],
96879
+ },
96880
+ executionTime: 0,
96881
+ timestamp: new Date().toISOString(),
96882
+ checksExecuted: checksToRun,
96883
+ };
96884
+ output = output_formatters_1.OutputFormatters.formatAsSarif(analysisResult);
96813
96885
  }
96814
96886
  else if (options.output === 'markdown') {
96815
96887
  // Create analysis result for markdown formatting
@@ -96958,6 +97030,8 @@ class CLI {
96958
97030
  .option('--max-parallelism <count>', 'Maximum number of checks to run in parallel (default: 3)', value => parseInt(value, 10))
96959
97031
  .option('--debug', 'Enable debug mode for detailed output')
96960
97032
  .option('--fail-fast', 'Stop execution on first failure condition')
97033
+ .option('--tags <tags>', 'Include checks with these tags (comma-separated)')
97034
+ .option('--exclude-tags <tags>', 'Exclude checks with these tags (comma-separated)')
96961
97035
  .option('--no-remote-extends', 'Disable loading configurations from remote URLs')
96962
97036
  .addHelpText('after', this.getExamplesText())
96963
97037
  .exitOverride(); // Prevent automatic process.exit for better error handling
@@ -96993,6 +97067,8 @@ class CLI {
96993
97067
  .option('--max-parallelism <count>', 'Maximum number of checks to run in parallel (default: 3)', value => parseInt(value, 10))
96994
97068
  .option('--debug', 'Enable debug mode for detailed output')
96995
97069
  .option('--fail-fast', 'Stop execution on first failure condition')
97070
+ .option('--tags <tags>', 'Include checks with these tags (comma-separated)')
97071
+ .option('--exclude-tags <tags>', 'Exclude checks with these tags (comma-separated)')
96996
97072
  .option('--allowed-remote-patterns <patterns>', 'Comma-separated list of allowed URL prefixes for remote config extends (e.g., "https://github.com/,https://raw.githubusercontent.com/")')
96997
97073
  .allowUnknownOption(false)
96998
97074
  .allowExcessArguments(false) // Don't allow positional arguments
@@ -97015,6 +97091,15 @@ class CLI {
97015
97091
  .split(',')
97016
97092
  .map((p) => p.trim());
97017
97093
  }
97094
+ // Parse tag filters
97095
+ let tags;
97096
+ if (options.tags) {
97097
+ tags = options.tags.split(',').map((t) => t.trim());
97098
+ }
97099
+ let excludeTags;
97100
+ if (options.excludeTags) {
97101
+ excludeTags = options.excludeTags.split(',').map((t) => t.trim());
97102
+ }
97018
97103
  return {
97019
97104
  checks: uniqueChecks,
97020
97105
  output: options.output,
@@ -97023,6 +97108,8 @@ class CLI {
97023
97108
  maxParallelism: options.maxParallelism,
97024
97109
  debug: options.debug,
97025
97110
  failFast: options.failFast,
97111
+ tags,
97112
+ excludeTags,
97026
97113
  allowedRemotePatterns,
97027
97114
  help: options.help,
97028
97115
  version: options.version,
@@ -97129,7 +97216,10 @@ Examples:
97129
97216
  visor --check all --timeout 300000 --output json # 5 minute timeout
97130
97217
  visor --check all --max-parallelism 5 --output json # Run up to 5 checks in parallel
97131
97218
  visor --check all --debug --output markdown # Enable debug mode
97132
- visor --check all --fail-fast --output json # Stop on first failure`;
97219
+ visor --check all --fail-fast --output json # Stop on first failure
97220
+ visor --tags local,fast --output table # Run checks tagged as 'local' or 'fast'
97221
+ visor --exclude-tags slow,experimental --output json # Skip checks tagged as 'slow' or 'experimental'
97222
+ visor --tags security --exclude-tags slow # Run security checks but skip slow ones`;
97133
97223
  }
97134
97224
  /**
97135
97225
  * Display help
@@ -97270,6 +97360,7 @@ class ConfigManager {
97270
97360
  'http_input',
97271
97361
  'http_client',
97272
97362
  'noop',
97363
+ 'log',
97273
97364
  ];
97274
97365
  validEventTriggers = [
97275
97366
  'pr_opened',
@@ -97580,6 +97671,10 @@ class ConfigManager {
97580
97671
  });
97581
97672
  }
97582
97673
  }
97674
+ // Validate tag_filter if present
97675
+ if (config.tag_filter) {
97676
+ this.validateTagFilter(config.tag_filter, errors);
97677
+ }
97583
97678
  if (errors.length > 0) {
97584
97679
  throw new Error(errors[0].message);
97585
97680
  }
@@ -97694,6 +97789,98 @@ class ConfigManager {
97694
97789
  }
97695
97790
  }
97696
97791
  }
97792
+ // Validate tags configuration
97793
+ if (checkConfig.tags !== undefined) {
97794
+ if (!Array.isArray(checkConfig.tags)) {
97795
+ errors.push({
97796
+ field: `checks.${checkName}.tags`,
97797
+ message: `Invalid tags value for "${checkName}": must be an array of strings`,
97798
+ value: checkConfig.tags,
97799
+ });
97800
+ }
97801
+ else {
97802
+ // Validate each tag
97803
+ const validTagPattern = /^[a-zA-Z0-9][a-zA-Z0-9-_]*$/;
97804
+ checkConfig.tags.forEach((tag, index) => {
97805
+ if (typeof tag !== 'string') {
97806
+ errors.push({
97807
+ field: `checks.${checkName}.tags[${index}]`,
97808
+ message: `Invalid tag at index ${index} for "${checkName}": must be a string`,
97809
+ value: tag,
97810
+ });
97811
+ }
97812
+ else if (!validTagPattern.test(tag)) {
97813
+ errors.push({
97814
+ field: `checks.${checkName}.tags[${index}]`,
97815
+ message: `Invalid tag "${tag}" for "${checkName}": tags must be alphanumeric with hyphens or underscores (start with alphanumeric)`,
97816
+ value: tag,
97817
+ });
97818
+ }
97819
+ });
97820
+ }
97821
+ }
97822
+ }
97823
+ /**
97824
+ * Validate tag filter configuration
97825
+ */
97826
+ validateTagFilter(tagFilter, errors) {
97827
+ const validTagPattern = /^[a-zA-Z0-9][a-zA-Z0-9-_]*$/;
97828
+ // Validate include tags
97829
+ if (tagFilter.include !== undefined) {
97830
+ if (!Array.isArray(tagFilter.include)) {
97831
+ errors.push({
97832
+ field: 'tag_filter.include',
97833
+ message: 'tag_filter.include must be an array of strings',
97834
+ value: tagFilter.include,
97835
+ });
97836
+ }
97837
+ else {
97838
+ tagFilter.include.forEach((tag, index) => {
97839
+ if (typeof tag !== 'string') {
97840
+ errors.push({
97841
+ field: `tag_filter.include[${index}]`,
97842
+ message: `Invalid tag at index ${index}: must be a string`,
97843
+ value: tag,
97844
+ });
97845
+ }
97846
+ else if (!validTagPattern.test(tag)) {
97847
+ errors.push({
97848
+ field: `tag_filter.include[${index}]`,
97849
+ message: `Invalid tag "${tag}": tags must be alphanumeric with hyphens or underscores`,
97850
+ value: tag,
97851
+ });
97852
+ }
97853
+ });
97854
+ }
97855
+ }
97856
+ // Validate exclude tags
97857
+ if (tagFilter.exclude !== undefined) {
97858
+ if (!Array.isArray(tagFilter.exclude)) {
97859
+ errors.push({
97860
+ field: 'tag_filter.exclude',
97861
+ message: 'tag_filter.exclude must be an array of strings',
97862
+ value: tagFilter.exclude,
97863
+ });
97864
+ }
97865
+ else {
97866
+ tagFilter.exclude.forEach((tag, index) => {
97867
+ if (typeof tag !== 'string') {
97868
+ errors.push({
97869
+ field: `tag_filter.exclude[${index}]`,
97870
+ message: `Invalid tag at index ${index}: must be a string`,
97871
+ value: tag,
97872
+ });
97873
+ }
97874
+ else if (!validTagPattern.test(tag)) {
97875
+ errors.push({
97876
+ field: `tag_filter.exclude[${index}]`,
97877
+ message: `Invalid tag "${tag}": tags must be alphanumeric with hyphens or underscores`,
97878
+ value: tag,
97879
+ });
97880
+ }
97881
+ });
97882
+ }
97883
+ }
97697
97884
  }
97698
97885
  /**
97699
97886
  * Validate HTTP server configuration
@@ -99612,6 +99799,9 @@ async function run() {
99612
99799
  'max-parallelism': (0, core_1.getInput)('max-parallelism') || undefined,
99613
99800
  'ai-provider': (0, core_1.getInput)('ai-provider') || undefined,
99614
99801
  'ai-model': (0, core_1.getInput)('ai-model') || undefined,
99802
+ // Tag filtering inputs
99803
+ tags: (0, core_1.getInput)('tags') || undefined,
99804
+ 'exclude-tags': (0, core_1.getInput)('exclude-tags') || undefined,
99615
99805
  // Legacy inputs for backward compatibility
99616
99806
  'visor-config-path': (0, core_1.getInput)('visor-config-path') || undefined,
99617
99807
  'visor-checks': (0, core_1.getInput)('visor-checks') || undefined,
@@ -101683,6 +101873,7 @@ const issue_filter_1 = __nccwpck_require__(36879);
101683
101873
  const liquidjs_1 = __nccwpck_require__(48694);
101684
101874
  const promises_1 = __importDefault(__nccwpck_require__(91943));
101685
101875
  const path_1 = __importDefault(__nccwpck_require__(16928));
101876
+ const claude_code_types_1 = __nccwpck_require__(21710);
101686
101877
  /**
101687
101878
  * AI-powered check provider using probe agent
101688
101879
  */
@@ -101724,6 +101915,39 @@ class AICheckProvider extends check_provider_interface_1.CheckProvider {
101724
101915
  !['google', 'anthropic', 'openai', 'mock'].includes(cfg.ai.provider)) {
101725
101916
  return false;
101726
101917
  }
101918
+ // Validate mcpServers if present
101919
+ if (cfg.ai.mcpServers) {
101920
+ if (!this.validateMcpServers(cfg.ai.mcpServers)) {
101921
+ return false;
101922
+ }
101923
+ }
101924
+ }
101925
+ // Validate check-level MCP servers if present
101926
+ if (cfg.ai_mcp_servers) {
101927
+ if (!this.validateMcpServers(cfg.ai_mcp_servers)) {
101928
+ return false;
101929
+ }
101930
+ }
101931
+ return true;
101932
+ }
101933
+ /**
101934
+ * Validate MCP servers configuration
101935
+ */
101936
+ validateMcpServers(mcpServers) {
101937
+ if (typeof mcpServers !== 'object' || mcpServers === null) {
101938
+ return false;
101939
+ }
101940
+ for (const serverConfig of Object.values(mcpServers)) {
101941
+ if (!serverConfig || typeof serverConfig !== 'object') {
101942
+ return false;
101943
+ }
101944
+ const config = serverConfig;
101945
+ if (!config.command || typeof config.command !== 'string') {
101946
+ return false;
101947
+ }
101948
+ if (config.args && !Array.isArray(config.args)) {
101949
+ return false;
101950
+ }
101727
101951
  }
101728
101952
  return true;
101729
101953
  }
@@ -101990,6 +102214,53 @@ class AICheckProvider extends check_provider_interface_1.CheckProvider {
101990
102214
  throw new Error(`Failed to render prompt template: ${error instanceof Error ? error.message : 'Unknown error'}`);
101991
102215
  }
101992
102216
  }
102217
+ /**
102218
+ * Setup MCP tools based on AI configuration
102219
+ */
102220
+ async setupMcpTools(aiConfig) {
102221
+ const tools = [];
102222
+ // Setup custom MCP servers if configured
102223
+ if (aiConfig.mcpServers) {
102224
+ try {
102225
+ // Import MCP SDK for custom server creation using safe import
102226
+ const mcpModule = await (0, claude_code_types_1.safeImport)('@modelcontextprotocol/sdk');
102227
+ if (!mcpModule) {
102228
+ console.warn('@modelcontextprotocol/sdk package not found. MCP servers disabled.');
102229
+ return tools;
102230
+ }
102231
+ const createSdkMcpServer = mcpModule.createSdkMcpServer || mcpModule.default?.createSdkMcpServer;
102232
+ if (createSdkMcpServer) {
102233
+ for (const [serverName, serverConfig] of Object.entries(aiConfig.mcpServers)) {
102234
+ try {
102235
+ // Create MCP server instance
102236
+ const server = await createSdkMcpServer({
102237
+ name: serverName,
102238
+ command: serverConfig.command,
102239
+ args: serverConfig.args || [],
102240
+ env: { ...process.env, ...serverConfig.env },
102241
+ });
102242
+ // Add server tools to available tools
102243
+ const serverTools = await server.listTools();
102244
+ tools.push(...serverTools.map((tool) => ({
102245
+ name: tool.name,
102246
+ server: serverName,
102247
+ })));
102248
+ }
102249
+ catch (serverError) {
102250
+ console.warn(`Failed to setup MCP server ${serverName}: ${serverError instanceof Error ? serverError.message : 'Unknown error'}`);
102251
+ }
102252
+ }
102253
+ }
102254
+ else {
102255
+ console.warn('createSdkMcpServer function not found in @modelcontextprotocol/sdk. MCP servers disabled.');
102256
+ }
102257
+ }
102258
+ catch (error) {
102259
+ console.warn(`Failed to import MCP SDK: ${error instanceof Error ? error.message : 'Unknown error'}. MCP servers disabled.`);
102260
+ }
102261
+ }
102262
+ return tools;
102263
+ }
101993
102264
  async execute(prInfo, config, _dependencyResults, sessionInfo) {
101994
102265
  // Apply environment configuration if present
101995
102266
  if (config.env) {
@@ -102038,6 +102309,32 @@ class AICheckProvider extends check_provider_interface_1.CheckProvider {
102038
102309
  if (!customPrompt) {
102039
102310
  throw new Error(`No prompt defined for check. All checks must have prompts defined in .visor.yaml configuration.`);
102040
102311
  }
102312
+ // Setup MCP tools from multiple configuration levels
102313
+ const mcpServers = {};
102314
+ // 1. Start with global MCP servers (from visor config root)
102315
+ const globalConfig = config; // Cast to access potential global config
102316
+ if (globalConfig.ai_mcp_servers) {
102317
+ Object.assign(mcpServers, globalConfig.ai_mcp_servers);
102318
+ }
102319
+ // 2. Add check-level MCP servers (overrides global)
102320
+ if (config.ai_mcp_servers) {
102321
+ Object.assign(mcpServers, config.ai_mcp_servers);
102322
+ }
102323
+ // 3. Add ai.mcpServers (overrides everything)
102324
+ if (config.ai?.mcpServers) {
102325
+ Object.assign(mcpServers, config.ai.mcpServers);
102326
+ }
102327
+ // Setup MCP tools if any servers are configured
102328
+ if (Object.keys(mcpServers).length > 0) {
102329
+ const mcpConfig = { mcpServers };
102330
+ const mcpTools = await this.setupMcpTools(mcpConfig);
102331
+ if (mcpTools.length > 0) {
102332
+ aiConfig.tools = mcpTools;
102333
+ if (aiConfig.debug) {
102334
+ console.error(`🔧 Debug: AI check configured with ${mcpTools.length} MCP tools from ${Object.keys(mcpServers).length} servers`);
102335
+ }
102336
+ }
102337
+ }
102041
102338
  // Process prompt with Liquid templates and file loading
102042
102339
  const processedPrompt = await this.processPrompt(customPrompt, prInfo, config.eventContext, _dependencyResults);
102043
102340
  // Create AI service with config - environment variables will be used if aiConfig is empty
@@ -102106,8 +102403,10 @@ class AICheckProvider extends check_provider_interface_1.CheckProvider {
102106
102403
  'ai.model',
102107
102404
  'ai.apiKey',
102108
102405
  'ai.timeout',
102406
+ 'ai.mcpServers',
102109
102407
  'ai_model',
102110
102408
  'ai_provider',
102409
+ 'ai_mcp_servers',
102111
102410
  'env',
102112
102411
  ];
102113
102412
  }
@@ -102143,6 +102442,7 @@ const http_check_provider_1 = __nccwpck_require__(31115);
102143
102442
  const http_input_provider_1 = __nccwpck_require__(74423);
102144
102443
  const http_client_provider_1 = __nccwpck_require__(36270);
102145
102444
  const noop_check_provider_1 = __nccwpck_require__(53003);
102445
+ const log_check_provider_1 = __nccwpck_require__(24903);
102146
102446
  const claude_code_check_provider_1 = __nccwpck_require__(17985);
102147
102447
  /**
102148
102448
  * Registry for managing check providers
@@ -102174,6 +102474,7 @@ class CheckProviderRegistry {
102174
102474
  this.register(new http_input_provider_1.HttpInputProvider());
102175
102475
  this.register(new http_client_provider_1.HttpClientProvider());
102176
102476
  this.register(new noop_check_provider_1.NoopCheckProvider());
102477
+ this.register(new log_check_provider_1.LogCheckProvider());
102177
102478
  // Try to register ClaudeCodeCheckProvider - it may fail if dependencies are missing
102178
102479
  try {
102179
102480
  this.register(new claude_code_check_provider_1.ClaudeCodeCheckProvider());
@@ -103555,6 +103856,205 @@ class HttpInputProvider extends check_provider_interface_1.CheckProvider {
103555
103856
  exports.HttpInputProvider = HttpInputProvider;
103556
103857
 
103557
103858
 
103859
+ /***/ }),
103860
+
103861
+ /***/ 24903:
103862
+ /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
103863
+
103864
+ "use strict";
103865
+
103866
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
103867
+ exports.LogCheckProvider = void 0;
103868
+ const check_provider_interface_1 = __nccwpck_require__(14131);
103869
+ const liquidjs_1 = __nccwpck_require__(48694);
103870
+ /**
103871
+ * Check provider that outputs debugging and logging information.
103872
+ * Useful for troubleshooting check workflows and understanding execution flow.
103873
+ */
103874
+ class LogCheckProvider extends check_provider_interface_1.CheckProvider {
103875
+ liquid;
103876
+ constructor() {
103877
+ super();
103878
+ this.liquid = new liquidjs_1.Liquid({
103879
+ strictVariables: false,
103880
+ strictFilters: false,
103881
+ });
103882
+ }
103883
+ getName() {
103884
+ return 'log';
103885
+ }
103886
+ getDescription() {
103887
+ return 'Output debugging and logging information for troubleshooting check workflows';
103888
+ }
103889
+ async validateConfig(config) {
103890
+ if (!config || typeof config !== 'object') {
103891
+ return false;
103892
+ }
103893
+ const cfg = config;
103894
+ // Type must be 'log'
103895
+ if (cfg.type !== 'log') {
103896
+ return false;
103897
+ }
103898
+ // Message is required
103899
+ if (!cfg.message || typeof cfg.message !== 'string') {
103900
+ return false;
103901
+ }
103902
+ // Validate log level if provided
103903
+ if (cfg.level && !['debug', 'info', 'warn', 'error'].includes(cfg.level)) {
103904
+ return false;
103905
+ }
103906
+ return true;
103907
+ }
103908
+ async execute(prInfo, config, dependencyResults, _sessionInfo) {
103909
+ const message = config.message;
103910
+ const level = config.level || 'info';
103911
+ const includePrContext = config.include_pr_context !== false;
103912
+ const includeDependencies = config.include_dependencies !== false;
103913
+ const includeMetadata = config.include_metadata !== false;
103914
+ // Prepare template context
103915
+ const templateContext = this.buildTemplateContext(prInfo, dependencyResults, includePrContext, includeDependencies, includeMetadata);
103916
+ // Render the log message template
103917
+ const renderedMessage = await this.liquid.parseAndRender(message, templateContext);
103918
+ // Build the log output
103919
+ const logOutput = this.formatLogOutput(level, renderedMessage, templateContext, includePrContext, includeDependencies, includeMetadata);
103920
+ return {
103921
+ issues: [], // Log provider doesn't generate issues
103922
+ suggestions: [logOutput], // Put formatted log output as the primary suggestion
103923
+ };
103924
+ }
103925
+ buildTemplateContext(prInfo, dependencyResults, includePrContext = true, includeDependencies = true, includeMetadata = true) {
103926
+ const context = {};
103927
+ if (includePrContext) {
103928
+ context.pr = {
103929
+ number: prInfo.number,
103930
+ title: prInfo.title,
103931
+ body: prInfo.body,
103932
+ author: prInfo.author,
103933
+ base: prInfo.base,
103934
+ head: prInfo.head,
103935
+ totalAdditions: prInfo.totalAdditions,
103936
+ totalDeletions: prInfo.totalDeletions,
103937
+ files: prInfo.files.map(f => ({
103938
+ filename: f.filename,
103939
+ status: f.status,
103940
+ additions: f.additions,
103941
+ deletions: f.deletions,
103942
+ changes: f.changes,
103943
+ })),
103944
+ };
103945
+ // Add convenience data
103946
+ context.filenames = prInfo.files.map(f => f.filename);
103947
+ context.fileCount = prInfo.files.length;
103948
+ }
103949
+ if (includeDependencies && dependencyResults) {
103950
+ const dependencies = {};
103951
+ context.dependencyCount = dependencyResults.size;
103952
+ for (const [checkName, result] of dependencyResults.entries()) {
103953
+ dependencies[checkName] = {
103954
+ issueCount: result.issues?.length || 0,
103955
+ suggestionCount: result.suggestions?.length || 0,
103956
+ issues: result.issues || [],
103957
+ suggestions: result.suggestions || [],
103958
+ };
103959
+ }
103960
+ context.dependencies = dependencies;
103961
+ }
103962
+ if (includeMetadata) {
103963
+ context.metadata = {
103964
+ timestamp: new Date().toISOString(),
103965
+ executionTime: Date.now(),
103966
+ nodeVersion: process.version,
103967
+ platform: process.platform,
103968
+ workingDirectory: process.cwd(),
103969
+ };
103970
+ }
103971
+ return context;
103972
+ }
103973
+ formatLogOutput(level, message, templateContext, includePrContext, includeDependencies, includeMetadata) {
103974
+ const sections = [];
103975
+ // Log level and message
103976
+ const levelEmoji = this.getLevelEmoji(level);
103977
+ sections.push(`${levelEmoji} **${level.toUpperCase()}**: ${message}`);
103978
+ // PR context section
103979
+ if (includePrContext && templateContext.pr) {
103980
+ const pr = templateContext.pr;
103981
+ sections.push('');
103982
+ sections.push('### PR Context');
103983
+ sections.push(`- **PR #${pr.number}**: ${pr.title}`);
103984
+ sections.push(`- **Author**: ${pr.author}`);
103985
+ sections.push(`- **Base**: ${pr.base} → **Head**: ${pr.head}`);
103986
+ sections.push(`- **Changes**: +${pr.totalAdditions} -${pr.totalDeletions}`);
103987
+ sections.push(`- **Files Modified**: ${templateContext.fileCount}`);
103988
+ }
103989
+ // Dependencies section
103990
+ if (includeDependencies && templateContext.dependencies) {
103991
+ const deps = templateContext.dependencies;
103992
+ sections.push('');
103993
+ sections.push('### Dependency Results');
103994
+ if (Object.keys(deps).length === 0) {
103995
+ sections.push('- No dependency results available');
103996
+ }
103997
+ else {
103998
+ for (const [checkName, result] of Object.entries(deps)) {
103999
+ sections.push(`- **${checkName}**: ${result.issueCount} issues, ${result.suggestionCount} suggestions`);
104000
+ }
104001
+ }
104002
+ }
104003
+ // Metadata section
104004
+ if (includeMetadata && templateContext.metadata) {
104005
+ const meta = templateContext.metadata;
104006
+ sections.push('');
104007
+ sections.push('### Execution Metadata');
104008
+ sections.push(`- **Timestamp**: ${meta.timestamp}`);
104009
+ sections.push(`- **Node Version**: ${meta.nodeVersion}`);
104010
+ sections.push(`- **Platform**: ${meta.platform}`);
104011
+ sections.push(`- **Working Directory**: ${meta.workingDirectory}`);
104012
+ }
104013
+ return sections.join('\n');
104014
+ }
104015
+ getLevelEmoji(level) {
104016
+ switch (level) {
104017
+ case 'debug':
104018
+ return '🐛';
104019
+ case 'info':
104020
+ return 'ℹ️';
104021
+ case 'warn':
104022
+ return '⚠️';
104023
+ case 'error':
104024
+ return '❌';
104025
+ default:
104026
+ return 'ℹ️';
104027
+ }
104028
+ }
104029
+ getSupportedConfigKeys() {
104030
+ return [
104031
+ 'type',
104032
+ 'message',
104033
+ 'level',
104034
+ 'include_pr_context',
104035
+ 'include_dependencies',
104036
+ 'include_metadata',
104037
+ 'group',
104038
+ 'command',
104039
+ 'depends_on',
104040
+ 'on',
104041
+ 'if',
104042
+ ];
104043
+ }
104044
+ async isAvailable() {
104045
+ // Log provider is always available
104046
+ return true;
104047
+ }
104048
+ getRequirements() {
104049
+ return [
104050
+ 'No external dependencies required',
104051
+ 'Used for debugging and logging check execution flow',
104052
+ ];
104053
+ }
104054
+ }
104055
+ exports.LogCheckProvider = LogCheckProvider;
104056
+
104057
+
103558
104058
  /***/ }),
103559
104059
 
103560
104060
  /***/ 53003: