Module: CovLoupe

Defined in:
lib/cov_loupe.rb,
lib/cov_loupe/cli.rb,
lib/cov_loupe/version.rb,
lib/cov_loupe/base_tool.rb,
lib/cov_loupe/resources.rb,
lib/cov_loupe/mcp_server.rb,
lib/cov_loupe/model/model.rb,
lib/cov_loupe/output_chars.rb,
lib/cov_loupe/config/logger.rb,
lib/cov_loupe/errors/errors.rb,
lib/cov_loupe/tools/help_tool.rb,
lib/cov_loupe/model/model_data.rb,
lib/cov_loupe/paths/glob_utils.rb,
lib/cov_loupe/paths/path_utils.rb,
lib/cov_loupe/config/app_config.rb,
lib/cov_loupe/config/app_context.rb,
lib/cov_loupe/tools/version_tool.rb,
lib/cov_loupe/config/boolean_type.rb,
lib/cov_loupe/commands/raw_command.rb,
lib/cov_loupe/config/config_parser.rb,
lib/cov_loupe/errors/error_handler.rb,
lib/cov_loupe/commands/base_command.rb,
lib/cov_loupe/commands/list_command.rb,
lib/cov_loupe/formatters/formatters.rb,
lib/cov_loupe/model/model_data_cache.rb,
lib/cov_loupe/paths/path_relativizer.rb,
lib/cov_loupe/staleness/stale_status.rb,
lib/cov_loupe/commands/totals_command.rb,
lib/cov_loupe/commands/command_factory.rb,
lib/cov_loupe/commands/summary_command.rb,
lib/cov_loupe/loaders/resultset_loader.rb,
lib/cov_loupe/scripts/latest_ci_status.rb,
lib/cov_loupe/scripts/setup_doc_server.rb,
lib/cov_loupe/scripts/start_doc_server.rb,
lib/cov_loupe/commands/detailed_command.rb,
lib/cov_loupe/commands/validate_command.rb,
lib/cov_loupe/config/option_normalizers.rb,
lib/cov_loupe/scripts/command_execution.rb,
lib/cov_loupe/scripts/pre_release_check.rb,
lib/cov_loupe/commands/uncovered_command.rb,
lib/cov_loupe/config/predicate_evaluator.rb,
lib/cov_loupe/coverage/coverage_reporter.rb,
lib/cov_loupe/formatters/table_formatter.rb,
lib/cov_loupe/presenters/payload_caching.rb,
lib/cov_loupe/resolvers/resolver_helpers.rb,
lib/cov_loupe/formatters/source_formatter.rb,
lib/cov_loupe/option_parsers/error_helper.rb,
lib/cov_loupe/staleness/staleness_checker.rb,
lib/cov_loupe/tools/project_coverage_tool.rb,
lib/cov_loupe/tools/project_validate_tool.rb,
lib/cov_loupe/config/option_parser_builder.rb,
lib/cov_loupe/coverage/coverage_calculator.rb,
lib/cov_loupe/errors/error_handler_factory.rb,
lib/cov_loupe/tools/file_coverage_raw_tool.rb,
lib/cov_loupe/paths/volume_case_sensitivity.rb,
lib/cov_loupe/tools/file_uncovered_lines_tool.rb,
lib/cov_loupe/repositories/coverage_repository.rb,
lib/cov_loupe/resolvers/coverage_line_resolver.rb,
lib/cov_loupe/tools/file_coverage_summary_tool.rb,
lib/cov_loupe/coverage/coverage_table_formatter.rb,
lib/cov_loupe/option_parsers/env_options_parser.rb,
lib/cov_loupe/resolvers/resultset_path_resolver.rb,
lib/cov_loupe/tools/file_coverage_detailed_tool.rb,
lib/cov_loupe/presenters/base_coverage_presenter.rb,
lib/cov_loupe/tools/project_coverage_totals_tool.rb,
lib/cov_loupe/presenters/project_totals_presenter.rb,
lib/cov_loupe/presenters/coverage_payload_presenter.rb,
lib/cov_loupe/presenters/project_coverage_presenter.rb,
lib/cov_loupe/staleness/staleness_message_formatter.rb

Overview

JSON-RPC server exposing coverage data tools via the Model Context Protocol (MCP).

Runs on stdio, making it suitable for editor/agent integrations (e.g., Claude, VS Code). Each tool call builds its own CoverageModel and relies on ModelDataCache for shared coverage data, so request-specific state does not leak across calls.

The TOOLSET constant defines which tools are registered. Each tool class inherits from BaseTool, which provides shared error handling, JSON response formatting, and model configuration merging from the server context plus per-call arguments.

Defined Under Namespace

Modules: Commands, CoverageReporter, ErrorHandlerFactory, Formatters, GlobUtils, OptionNormalizers, OptionParsers, OutputChars, PathUtils, Presenters, Repositories, Resolvers, Resources, Scripts, StaleStatus, StalenessFormatterMixin, Tools, VolumeCaseSensitivity Classes: AppConfig, AppContext, BaseTool, BooleanType, ConfigParser, ConfigurationError, CorruptCoverageDataError, CoverageCLI, CoverageCalculator, CoverageDataError, CoverageDataProjectStaleError, CoverageDataStaleError, CoverageModel, CoverageTableFormatter, Error, ErrorHandler, FileError, FileNotFoundError, FilePermissionError, Logger, MCPServer, ModelData, ModelDataCache, NotAFileError, OptionParserBuilder, PathRelativizer, PredicateEvaluator, ResultsetLoader, ResultsetNotFoundError, StalenessChecker, StalenessMessageFormatter, TableFormatter, UnknownError, UsageError

Constant Summary collapse

VERSION =
'6.0.0'

Class Method Summary collapse

Class Method Details

.active_log_fileObject



132
133
134
# File 'lib/cov_loupe.rb', line 132

def active_log_file
  context.log_target
end

.active_log_file=(value) ⇒ Object



136
137
138
139
140
141
142
143
144
145
# File 'lib/cov_loupe.rb', line 136

def active_log_file=(value)
  AppConfig.validate_log_file!(value)
  current = Thread.current[THREAD_CONTEXT_KEY]
  Thread.current[THREAD_CONTEXT_KEY] = if current
    current.with(log_target: value)
  else
    base = mutex.synchronize { internal_default_context }
    base.with(log_target: value)
  end
end

.contextObject



106
107
108
# File 'lib/cov_loupe.rb', line 106

def context
  Thread.current[THREAD_CONTEXT_KEY] || default_context
end

.create_context(error_handler:, log_target: nil, mode: :library, app_config: nil) ⇒ Object



110
111
112
113
114
115
116
117
# File 'lib/cov_loupe.rb', line 110

def create_context(error_handler:, log_target: nil, mode: :library, app_config: nil)
  AppContext.new(
    error_handler: error_handler,
    log_target:    log_target.nil? ? default_context.log_target : log_target,
    mode:          mode,
    app_config:    app_config
  )
end

.default_log_fileObject



119
120
121
# File 'lib/cov_loupe.rb', line 119

def default_log_file
  default_context.log_target
end

.default_log_file=(value) ⇒ Object



123
124
125
126
127
128
129
130
# File 'lib/cov_loupe.rb', line 123

def default_log_file=(value)
  AppConfig.validate_log_file!(value)
  mutex.synchronize do
    previous_default = internal_default_context
    @internal_default_context = previous_default.with(log_target: value)
  end
  value # rubocop:disable Lint/Void -- Setter should return assigned value for direct calls.
end

.error_handlerObject



147
148
149
# File 'lib/cov_loupe.rb', line 147

def error_handler
  context.error_handler
end

.error_handler=(handler) ⇒ Object



151
152
153
154
155
156
# File 'lib/cov_loupe.rb', line 151

def error_handler=(handler)
  mutex.synchronize do
    previous_default = internal_default_context
    @internal_default_context = previous_default.with(error_handler: handler)
  end
end

.loggerObject



158
159
160
# File 'lib/cov_loupe.rb', line 158

def logger
  context.logger
end

.run(argv) ⇒ Object

Primary entry point. Parses argv to determine mode (CLI or MCP server), then dispatches accordingly. Environment options from COV_LOUPE_OPTS are prepended before parsing so CLI arguments always take precedence.



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/cov_loupe.rb', line 66

def run(argv)
  # Parse config to determine mode
  require_relative 'cov_loupe/config/config_parser'

  begin
    # Prepend environment options once at entry point
    full_argv = extract_env_opts + argv
    config = ConfigParser.parse(full_argv.dup)
  rescue OptionParser::ParseError, ConfigurationError => e
    warn "Error: #{e.message}"
    warn "Run 'cov-loupe --help' for usage information."
    exit 2
  end

  if config.mode == :cli
    # CLI mode: load CLI components only
    require_relative 'cov_loupe/loaders/all_cli'
    CoverageCLI.new.run(full_argv)
  else
    # MCP server mode: load MCP server components only
    require_relative 'cov_loupe/loaders/all_mcp'

    handler = ErrorHandlerFactory.for_mcp_server(error_mode: config.error_mode)
    context = create_context(error_handler: handler, log_target: config.log_file,
      mode: :mcp, app_config: config)
    with_context(context) { MCPServer.new(context: context).run }
  end
end

.versionObject



169
170
171
# File 'lib/cov_loupe.rb', line 169

def version
  VERSION
end

.windows?Boolean

Returns true if running on Windows (mingw, mswin, cygwin).

Returns:

  • (Boolean)


163
164
165
166
167
# File 'lib/cov_loupe.rb', line 163

def windows?
  return @windows if defined?(@windows)

  @windows = RUBY_PLATFORM.match?(/mingw|mswin|cygwin/)
end

.with_context(context) ⇒ Object

Temporarily sets a thread-local context for the duration of the block, restoring the previous context afterward. Used to scope logging and error handling to a specific mode (CLI, MCP, library).



98
99
100
101
102
103
104
# File 'lib/cov_loupe.rb', line 98

def with_context(context)
  previous = Thread.current[THREAD_CONTEXT_KEY]
  Thread.current[THREAD_CONTEXT_KEY] = context
  yield
ensure
  Thread.current[THREAD_CONTEXT_KEY] = previous
end