simplecov-mcp 1.0.0 → 2.0.0

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.
Files changed (164) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +98 -50
  3. data/docs/{ARCHITECTURE.md → dev/ARCHITECTURE.md} +11 -10
  4. data/docs/dev/BRANCH_ONLY_COVERAGE.md +158 -0
  5. data/docs/{DEVELOPMENT.md → dev/DEVELOPMENT.md} +2 -1
  6. data/docs/dev/README.md +10 -0
  7. data/docs/dev/RELEASING.md +146 -0
  8. data/docs/{arch-decisions → dev/arch-decisions}/001-x-arch-decision.md +3 -1
  9. data/docs/{arch-decisions → dev/arch-decisions}/002-x-arch-decision.md +7 -5
  10. data/docs/{arch-decisions → dev/arch-decisions}/003-x-arch-decision.md +2 -0
  11. data/docs/{arch-decisions → dev/arch-decisions}/004-x-arch-decision.md +6 -2
  12. data/docs/{arch-decisions → dev/arch-decisions}/005-x-arch-decision.md +4 -2
  13. data/docs/{arch-decisions → dev/arch-decisions}/README.md +3 -3
  14. data/docs/{presentations → dev/presentations}/simplecov-mcp-presentation.md +28 -22
  15. data/docs/fixtures/demo_project/README.md +9 -0
  16. data/docs/{ADVANCED_USAGE.md → user/ADVANCED_USAGE.md} +129 -319
  17. data/docs/user/CLI_FALLBACK_FOR_LLMS.md +34 -0
  18. data/docs/user/CLI_USAGE.md +750 -0
  19. data/docs/{ERROR_HANDLING.md → user/ERROR_HANDLING.md} +12 -12
  20. data/docs/user/EXAMPLES.md +588 -0
  21. data/docs/user/INSTALLATION.md +130 -0
  22. data/docs/{LIBRARY_API.md → user/LIBRARY_API.md} +90 -32
  23. data/docs/{MCP_INTEGRATION.md → user/MCP_INTEGRATION.md} +36 -34
  24. data/docs/user/README.md +14 -0
  25. data/docs/{TROUBLESHOOTING.md → user/TROUBLESHOOTING.md} +21 -100
  26. data/docs/user/V2-BREAKING-CHANGES.md +472 -0
  27. data/exe/simplecov-mcp +1 -1
  28. data/lib/simplecov_mcp/{cli_config.rb → app_config.rb} +12 -12
  29. data/lib/simplecov_mcp/app_context.rb +1 -1
  30. data/lib/simplecov_mcp/base_tool.rb +66 -38
  31. data/lib/simplecov_mcp/cli.rb +67 -123
  32. data/lib/simplecov_mcp/commands/base_command.rb +16 -27
  33. data/lib/simplecov_mcp/commands/command_factory.rb +8 -2
  34. data/lib/simplecov_mcp/commands/detailed_command.rb +16 -2
  35. data/lib/simplecov_mcp/commands/list_command.rb +1 -1
  36. data/lib/simplecov_mcp/commands/raw_command.rb +18 -2
  37. data/lib/simplecov_mcp/commands/summary_command.rb +20 -3
  38. data/lib/simplecov_mcp/commands/totals_command.rb +53 -0
  39. data/lib/simplecov_mcp/commands/uncovered_command.rb +24 -5
  40. data/lib/simplecov_mcp/commands/validate_command.rb +60 -0
  41. data/lib/simplecov_mcp/commands/version_command.rb +19 -4
  42. data/lib/simplecov_mcp/config_parser.rb +32 -0
  43. data/lib/simplecov_mcp/constants.rb +3 -3
  44. data/lib/simplecov_mcp/coverage_reporter.rb +31 -0
  45. data/lib/simplecov_mcp/error_handler.rb +81 -40
  46. data/lib/simplecov_mcp/error_handler_factory.rb +2 -2
  47. data/lib/simplecov_mcp/errors.rb +32 -20
  48. data/lib/simplecov_mcp/formatters/source_formatter.rb +23 -19
  49. data/lib/simplecov_mcp/formatters.rb +51 -0
  50. data/lib/simplecov_mcp/mcp_server.rb +9 -7
  51. data/lib/simplecov_mcp/mode_detector.rb +6 -5
  52. data/lib/simplecov_mcp/model.rb +122 -83
  53. data/lib/simplecov_mcp/option_normalizers.rb +39 -18
  54. data/lib/simplecov_mcp/option_parser_builder.rb +82 -65
  55. data/lib/simplecov_mcp/option_parsers/env_options_parser.rb +3 -5
  56. data/lib/simplecov_mcp/option_parsers/error_helper.rb +18 -17
  57. data/lib/simplecov_mcp/path_relativizer.rb +17 -14
  58. data/lib/simplecov_mcp/predicate_evaluator.rb +72 -0
  59. data/lib/simplecov_mcp/presenters/base_coverage_presenter.rb +1 -3
  60. data/lib/simplecov_mcp/presenters/coverage_detailed_presenter.rb +1 -3
  61. data/lib/simplecov_mcp/presenters/coverage_raw_presenter.rb +1 -3
  62. data/lib/simplecov_mcp/presenters/coverage_summary_presenter.rb +1 -3
  63. data/lib/simplecov_mcp/presenters/coverage_uncovered_presenter.rb +1 -3
  64. data/lib/simplecov_mcp/presenters/project_coverage_presenter.rb +1 -3
  65. data/lib/simplecov_mcp/presenters/project_totals_presenter.rb +27 -0
  66. data/lib/simplecov_mcp/resolvers/coverage_line_resolver.rb +14 -18
  67. data/lib/simplecov_mcp/resolvers/resultset_path_resolver.rb +7 -9
  68. data/lib/simplecov_mcp/resultset_loader.rb +20 -25
  69. data/lib/simplecov_mcp/staleness_checker.rb +50 -46
  70. data/lib/simplecov_mcp/table_formatter.rb +64 -0
  71. data/lib/simplecov_mcp/tools/all_files_coverage_tool.rb +20 -50
  72. data/lib/simplecov_mcp/tools/coverage_detailed_tool.rb +13 -7
  73. data/lib/simplecov_mcp/tools/coverage_raw_tool.rb +12 -7
  74. data/lib/simplecov_mcp/tools/coverage_summary_tool.rb +13 -8
  75. data/lib/simplecov_mcp/tools/coverage_table_tool.rb +20 -60
  76. data/lib/simplecov_mcp/tools/coverage_totals_tool.rb +44 -0
  77. data/lib/simplecov_mcp/tools/help_tool.rb +38 -66
  78. data/lib/simplecov_mcp/tools/uncovered_lines_tool.rb +13 -8
  79. data/lib/simplecov_mcp/tools/validate_tool.rb +72 -0
  80. data/lib/simplecov_mcp/tools/version_tool.rb +7 -14
  81. data/lib/simplecov_mcp/util.rb +18 -12
  82. data/lib/simplecov_mcp/version.rb +1 -1
  83. data/lib/simplecov_mcp.rb +23 -29
  84. data/spec/all_files_coverage_tool_spec.rb +4 -3
  85. data/spec/{cli_config_spec.rb → app_config_spec.rb} +31 -26
  86. data/spec/base_tool_spec.rb +17 -14
  87. data/spec/cli/show_default_report_spec.rb +2 -2
  88. data/spec/cli_enumerated_options_spec.rb +31 -9
  89. data/spec/cli_error_spec.rb +46 -23
  90. data/spec/cli_format_spec.rb +123 -0
  91. data/spec/cli_json_options_spec.rb +50 -0
  92. data/spec/cli_source_spec.rb +11 -63
  93. data/spec/cli_spec.rb +82 -97
  94. data/spec/cli_usage_spec.rb +15 -15
  95. data/spec/commands/base_command_spec.rb +12 -92
  96. data/spec/commands/command_factory_spec.rb +7 -3
  97. data/spec/commands/detailed_command_spec.rb +10 -24
  98. data/spec/commands/list_command_spec.rb +28 -0
  99. data/spec/commands/raw_command_spec.rb +43 -20
  100. data/spec/commands/summary_command_spec.rb +10 -23
  101. data/spec/commands/totals_command_spec.rb +34 -0
  102. data/spec/commands/uncovered_command_spec.rb +29 -23
  103. data/spec/commands/validate_command_spec.rb +213 -0
  104. data/spec/commands/version_command_spec.rb +38 -0
  105. data/spec/constants_spec.rb +3 -3
  106. data/spec/coverage_reporter_spec.rb +102 -0
  107. data/spec/coverage_table_tool_spec.rb +21 -10
  108. data/spec/coverage_totals_tool_spec.rb +37 -0
  109. data/spec/error_handler_spec.rb +120 -4
  110. data/spec/error_mode_spec.rb +18 -22
  111. data/spec/errors_edge_cases_spec.rb +101 -28
  112. data/spec/errors_stale_spec.rb +34 -0
  113. data/spec/file_based_mcp_tools_spec.rb +6 -6
  114. data/spec/fixtures/project1/lib/bar.rb +2 -0
  115. data/spec/fixtures/project1/lib/foo.rb +2 -0
  116. data/spec/help_tool_spec.rb +2 -18
  117. data/spec/integration_spec.rb +114 -170
  118. data/spec/logging_fallback_spec.rb +3 -3
  119. data/spec/mcp_server_integration_spec.rb +1 -1
  120. data/spec/mcp_server_spec.rb +70 -53
  121. data/spec/mode_detector_spec.rb +46 -41
  122. data/spec/model_error_handling_spec.rb +141 -82
  123. data/spec/model_staleness_spec.rb +13 -13
  124. data/spec/option_normalizers_spec.rb +111 -112
  125. data/spec/option_parsers/env_options_parser_spec.rb +25 -37
  126. data/spec/option_parsers/error_helper_spec.rb +56 -56
  127. data/spec/path_relativizer_spec.rb +15 -0
  128. data/spec/presenters/coverage_detailed_presenter_spec.rb +1 -1
  129. data/spec/presenters/coverage_summary_presenter_spec.rb +1 -1
  130. data/spec/presenters/coverage_uncovered_presenter_spec.rb +1 -1
  131. data/spec/presenters/project_coverage_presenter_spec.rb +9 -8
  132. data/spec/presenters/project_totals_presenter_spec.rb +144 -0
  133. data/spec/resolvers/coverage_line_resolver_spec.rb +261 -36
  134. data/spec/resolvers/resultset_path_resolver_spec.rb +13 -8
  135. data/spec/shared_examples/file_based_mcp_tools.rb +23 -18
  136. data/spec/shared_examples/formatted_command_examples.rb +64 -0
  137. data/spec/simple_cov_mcp_module_spec.rb +24 -3
  138. data/spec/simplecov_mcp/formatters/source_formatter_spec.rb +267 -0
  139. data/spec/simplecov_mcp/formatters_spec.rb +76 -0
  140. data/spec/simplecov_mcp/presenters/base_coverage_presenter_spec.rb +79 -0
  141. data/spec/simplecov_mcp_model_spec.rb +99 -49
  142. data/spec/simplecov_mcp_opts_spec.rb +42 -39
  143. data/spec/spec_helper.rb +27 -92
  144. data/spec/staleness_checker_spec.rb +10 -9
  145. data/spec/staleness_more_spec.rb +4 -4
  146. data/spec/support/cli_helpers.rb +22 -0
  147. data/spec/support/control_flow_helpers.rb +20 -0
  148. data/spec/support/fake_mcp.rb +40 -0
  149. data/spec/support/io_helpers.rb +29 -0
  150. data/spec/support/mcp_helpers.rb +35 -0
  151. data/spec/support/mcp_runner.rb +10 -8
  152. data/spec/support/mocking_helpers.rb +30 -0
  153. data/spec/table_format_spec.rb +70 -0
  154. data/spec/tools/validate_tool_spec.rb +132 -0
  155. data/spec/tools_error_handling_spec.rb +34 -48
  156. data/spec/util_spec.rb +5 -4
  157. data/spec/version_spec.rb +7 -7
  158. data/spec/version_tool_spec.rb +20 -22
  159. metadata +90 -23
  160. data/docs/BRANCH_ONLY_COVERAGE.md +0 -81
  161. data/docs/CLI_USAGE.md +0 -637
  162. data/docs/EXAMPLES.md +0 -430
  163. data/docs/INSTALLATION.md +0 -352
  164. data/spec/cli_success_predicate_spec.rb +0 -141
@@ -7,60 +7,30 @@ require 'simplecov_mcp/tools/coverage_summary_tool'
7
7
  require 'simplecov_mcp/tools/coverage_raw_tool'
8
8
  require 'simplecov_mcp/tools/uncovered_lines_tool'
9
9
  require 'simplecov_mcp/tools/coverage_detailed_tool'
10
+ require 'simplecov_mcp/tools/coverage_totals_tool'
10
11
 
11
- RSpec.describe 'MCP Tool error handling' do
12
+ RSpec.describe SimpleCovMcp::Tools do
12
13
  let(:server_context) { instance_double('ServerContext').as_null_object }
13
14
 
14
15
  before do
15
16
  setup_mcp_response_stub
16
17
  end
17
18
 
18
- # Note: VersionTool error handling is difficult to test because the tool is so simple
19
+ # NOTE: VersionTool error handling is difficult to test because the tool is so simple
19
20
  # and doesn't have any complex logic that could fail. The rescue clause in the tool
20
21
  # exists for consistency with other tools but is unlikely to be triggered in practice.
21
22
 
22
23
  describe SimpleCovMcp::Tools::HelpTool do
23
- it 'handles errors during query processing' do
24
- # Simulate an error during filter_entries
25
- allow(described_class).to receive(:filter_entries).and_raise(StandardError, 'Filter error')
24
+ it 'returns tool information without errors' do
25
+ response = described_class.call(error_mode: 'log', server_context: server_context)
26
26
 
27
- response = described_class.call(query: 'test', error_mode: 'on',
28
- server_context: server_context)
29
-
30
- # Should return error response
31
27
  expect(response).to be_a(MCP::Tool::Response)
32
28
  item = response.payload.first
33
29
  expect(item[:type] || item['type']).to eq('text')
34
- expect(item[:text] || item['text']).to include('Error')
35
- end
36
-
37
- it 'returns empty array when tokens are empty after filtering' do
38
- # Test the edge case where query contains only non-word characters
39
- response = described_class.call(query: '!!!', server_context: server_context)
40
-
41
- data = JSON.parse(response.payload.first['text'])
42
- # With empty tokens, should return all entries (no filtering applied)
43
- expect(data['tools']).not_to be_empty
44
- end
45
30
 
46
- it 'handles non-string, non-array values in filter' do
47
- # Test value_matches? with values that are neither strings nor arrays
48
- # This exercises the 'else false' branch
49
- allow(described_class).to receive(:format_entry).and_return({
50
- 'tool' => 'test_tool',
51
- 'label' => nil, # Neither string nor array
52
- 'use_when' => 123, # Neither string nor array
53
- 'avoid_when' => true, # Neither string nor array
54
- 'inputs' => {}, # Neither string nor array
55
- 'example' => 'example'
56
- })
57
-
58
- response = described_class.call(query: 'test', server_context: server_context)
59
-
60
- # Should not crash, should return response
61
- expect(response).to be_a(MCP::Tool::Response)
62
- data = JSON.parse(response.payload.first['text'])
31
+ data = JSON.parse(item['text'])
63
32
  expect(data).to have_key('tools')
33
+ expect(data['tools']).not_to be_empty
64
34
  end
65
35
  end
66
36
 
@@ -70,7 +40,7 @@ RSpec.describe 'MCP Tool error handling' do
70
40
 
71
41
  response = described_class.call(
72
42
  path: 'lib/foo.rb',
73
- error_mode: 'on',
43
+ error_mode: 'log',
74
44
  server_context: server_context
75
45
  )
76
46
 
@@ -78,7 +48,7 @@ RSpec.describe 'MCP Tool error handling' do
78
48
  expect(response).to be_a(MCP::Tool::Response)
79
49
  item = response.payload.first
80
50
  expect(item[:type] || item['type']).to eq('text')
81
- expect(item[:text] || item['text']).to include('Error')
51
+ expect(item['text']).to include('Error')
82
52
  end
83
53
  end
84
54
 
@@ -88,9 +58,9 @@ RSpec.describe 'MCP Tool error handling' do
88
58
  allow(SimpleCovMcp::CoverageModel).to receive(:new).and_return(model)
89
59
  allow(model).to receive(:raw_for).and_raise(StandardError, 'Raw data error')
90
60
 
91
- response = SimpleCovMcp::Tools::CoverageRawTool.call(
61
+ response = described_class.call(
92
62
  path: 'lib/foo.rb',
93
- error_mode: 'on',
63
+ error_mode: 'log',
94
64
  server_context: server_context
95
65
  )
96
66
 
@@ -98,7 +68,7 @@ RSpec.describe 'MCP Tool error handling' do
98
68
  expect(response).to be_a(MCP::Tool::Response)
99
69
  item = response.payload.first
100
70
  expect(item[:type] || item['type']).to eq('text')
101
- expect(item[:text] || item['text']).to include('Error')
71
+ expect(item['text']).to include('Error')
102
72
  end
103
73
  end
104
74
 
@@ -108,9 +78,9 @@ RSpec.describe 'MCP Tool error handling' do
108
78
  allow(SimpleCovMcp::CoverageModel).to receive(:new).and_return(model)
109
79
  allow(model).to receive(:uncovered_for).and_raise(StandardError, 'Uncovered error')
110
80
 
111
- response = SimpleCovMcp::Tools::UncoveredLinesTool.call(
81
+ response = described_class.call(
112
82
  path: 'lib/foo.rb',
113
- error_mode: 'on',
83
+ error_mode: 'log',
114
84
  server_context: server_context
115
85
  )
116
86
 
@@ -118,7 +88,7 @@ RSpec.describe 'MCP Tool error handling' do
118
88
  expect(response).to be_a(MCP::Tool::Response)
119
89
  item = response.payload.first
120
90
  expect(item[:type] || item['type']).to eq('text')
121
- expect(item[:text] || item['text']).to include('Error')
91
+ expect(item['text']).to include('Error')
122
92
  end
123
93
  end
124
94
 
@@ -128,9 +98,9 @@ RSpec.describe 'MCP Tool error handling' do
128
98
  allow(SimpleCovMcp::CoverageModel).to receive(:new).and_return(model)
129
99
  allow(model).to receive(:detailed_for).and_raise(StandardError, 'Detailed error')
130
100
 
131
- response = SimpleCovMcp::Tools::CoverageDetailedTool.call(
101
+ response = described_class.call(
132
102
  path: 'lib/foo.rb',
133
- error_mode: 'on',
103
+ error_mode: 'log',
134
104
  server_context: server_context
135
105
  )
136
106
 
@@ -138,7 +108,23 @@ RSpec.describe 'MCP Tool error handling' do
138
108
  expect(response).to be_a(MCP::Tool::Response)
139
109
  item = response.payload.first
140
110
  expect(item[:type] || item['type']).to eq('text')
141
- expect(item[:text] || item['text']).to include('Error')
111
+ expect(item['text']).to include('Error')
112
+ end
113
+ end
114
+
115
+ describe SimpleCovMcp::Tools::CoverageTotalsTool do
116
+ it 'handles errors during totals calculation' do
117
+ allow(SimpleCovMcp::CoverageModel).to receive(:new).and_raise(StandardError, 'Model error')
118
+
119
+ response = described_class.call(
120
+ error_mode: 'log',
121
+ server_context: server_context
122
+ )
123
+
124
+ expect(response).to be_a(MCP::Tool::Response)
125
+ item = response.payload.first
126
+ expect(item[:type] || item['type']).to eq('text')
127
+ expect(item['text']).to include('Error')
142
128
  end
143
129
  end
144
130
  end
data/spec/util_spec.rb CHANGED
@@ -35,11 +35,12 @@ RSpec.describe SimpleCovMcp::CovUtil do
35
35
  end
36
36
 
37
37
  it 'summary handles edge cases and coercion' do
38
- expect(described_class.summary([])).to include('pct' => 100.0, 'total' => 0, 'covered' => 0)
38
+ expect(described_class.summary([]))
39
+ .to include('percentage' => 100.0, 'total' => 0, 'covered' => 0)
39
40
  expect(described_class.summary([nil, nil]))
40
- .to include('pct' => 100.0, 'total' => 0, 'covered' => 0)
41
+ .to include('percentage' => 100.0, 'total' => 0, 'covered' => 0)
41
42
  expect(described_class.summary(['1', '0', nil]))
42
- .to include('pct' => 50.0, 'total' => 2, 'covered' => 1)
43
+ .to include('percentage' => 50.0, 'total' => 2, 'covered' => 1)
43
44
  end
44
45
 
45
46
  it 'uncovered and detailed ignore nils' do
@@ -65,7 +66,7 @@ RSpec.describe SimpleCovMcp::CovUtil do
65
66
  describe 'logging configuration' do
66
67
  let(:test_message) { 'test log message' }
67
68
 
68
- around(:each) do |example|
69
+ around do |example|
69
70
  # Reset logging settings so each example starts clean.
70
71
  old_default = SimpleCovMcp.default_log_file
71
72
  old_active = SimpleCovMcp.active_log_file
data/spec/version_spec.rb CHANGED
@@ -27,12 +27,12 @@ RSpec.describe 'SimpleCovMcp::VERSION' do
27
27
  (?<major>0|[1-9]\d*)\.
28
28
  (?<minor>0|[1-9]\d*)\.
29
29
  (?<patch>0|[1-9]\d*)
30
- (?:-(?<prerelease>[0-9A-Za-z.-]+))?
30
+ (?:[.-](?<prerelease>[0-9A-Za-z.-]+))?
31
31
  (?:\+(?<buildmetadata>[0-9A-Za-z.-]+))?
32
32
  \z}x
33
33
  end
34
34
 
35
- it 'follows semantic versioning format' do
35
+ it 'follows semantic versioning format (accepting hyphen or dot pre-release separator)' do
36
36
  expect(version).to match(semver_regex)
37
37
  end
38
38
 
@@ -105,19 +105,19 @@ RSpec.describe 'SimpleCovMcp::VERSION' do
105
105
 
106
106
  describe 'standalone version file load' do
107
107
  it 'defines the module and VERSION constant when only version.rb is loaded' do
108
- original_module = SimpleCovMcp
109
108
  original_version = SimpleCovMcp::VERSION
110
109
 
111
- Object.send(:remove_const, :SimpleCovMcp)
110
+ stub_const('SimpleCovMcp', Module.new do
111
+ class << self
112
+ attr_accessor :default_log_file, :active_log_file
113
+ end
114
+ end)
112
115
 
113
116
  version_path = File.expand_path('../lib/simplecov_mcp/version.rb', __dir__)
114
117
  load version_path
115
118
 
116
119
  expect(Object.const_defined?(:SimpleCovMcp)).to be true
117
120
  expect(SimpleCovMcp::VERSION).to eq(original_version)
118
- ensure
119
- Object.send(:remove_const, :SimpleCovMcp) if Object.const_defined?(:SimpleCovMcp)
120
- Object.const_set(:SimpleCovMcp, original_module)
121
121
  end
122
122
  end
123
123
  end
@@ -15,14 +15,14 @@ RSpec.describe SimpleCovMcp::Tools::VersionTool do
15
15
  response = described_class.call(server_context: server_context)
16
16
  item = response.payload.first
17
17
  expect(item[:type] || item['type']).to eq('text')
18
- text = item[:text] || item['text']
18
+ text = item['text']
19
19
  expect(text).to eq("SimpleCovMcp version: #{SimpleCovMcp::VERSION}")
20
20
  end
21
21
 
22
22
  it 'includes the exact version constant value' do
23
23
  response = described_class.call(server_context: server_context)
24
24
  item = response.payload.first
25
- text = item[:text] || item['text']
25
+ text = item['text']
26
26
  expect(text).to include(SimpleCovMcp::VERSION)
27
27
  end
28
28
 
@@ -30,7 +30,7 @@ RSpec.describe SimpleCovMcp::Tools::VersionTool do
30
30
  expected_format = "SimpleCovMcp version: #{SimpleCovMcp::VERSION}"
31
31
  response = described_class.call(server_context: server_context)
32
32
  item = response.payload.first
33
- text = item[:text] || item['text']
33
+ text = item['text']
34
34
  expect(text).to eq(expected_format)
35
35
  end
36
36
 
@@ -49,18 +49,18 @@ RSpec.describe SimpleCovMcp::Tools::VersionTool do
49
49
  it 'accepts error_mode parameter without affecting output' do
50
50
  response = described_class.call(error_mode: 'off', server_context: server_context)
51
51
  item = response.payload.first
52
- text = item[:text] || item['text']
52
+ text = item['text']
53
53
  expect(text).to eq("SimpleCovMcp version: #{SimpleCovMcp::VERSION}")
54
54
  end
55
55
 
56
- it 'accepts error_mode "on" (default)' do
57
- response = described_class.call(error_mode: 'on', server_context: server_context)
56
+ it 'accepts error_mode "log" (default)' do
57
+ response = described_class.call(error_mode: 'log', server_context: server_context)
58
58
  item = response.payload.first
59
59
  expect(item[:type] || item['type']).to eq('text')
60
60
  end
61
61
 
62
- it 'accepts error_mode "trace"' do
63
- response = described_class.call(error_mode: 'trace', server_context: server_context)
62
+ it 'accepts error_mode "debug"' do
63
+ response = described_class.call(error_mode: 'debug', server_context: server_context)
64
64
  item = response.payload.first
65
65
  expect(item[:type] || item['type']).to eq('text')
66
66
  end
@@ -74,28 +74,26 @@ RSpec.describe SimpleCovMcp::Tools::VersionTool do
74
74
  another: { nested: 'data' }
75
75
  )
76
76
  item = response.payload.first
77
- text = item[:text] || item['text']
77
+ text = item['text']
78
78
  expect(text).to eq("SimpleCovMcp version: #{SimpleCovMcp::VERSION}")
79
79
  end
80
80
  end
81
81
 
82
82
  context 'when an error occurs' do
83
83
  it 'handles VERSION constant access errors and returns structured error response' do
84
- # Force an error by overriding const_get to raise an error when VERSION is accessed
85
- allow(SimpleCovMcp).to receive(:const_missing).with(:VERSION).and_raise(StandardError,
86
- 'Version access error')
84
+ # Force an error by hiding VERSION so const_missing is triggered
85
+ hide_const('SimpleCovMcp::VERSION')
86
+ allow(SimpleCovMcp).to receive(:const_missing).with(:VERSION)
87
+ .and_raise(StandardError, 'Version access error')
87
88
 
88
- # Clear the cached VERSION constant to trigger const_missing
89
- SimpleCovMcp.send(:remove_const, :VERSION) if SimpleCovMcp.const_defined?(:VERSION)
90
-
91
- response = described_class.call(error_mode: 'on', server_context: server_context)
89
+ response = described_class.call(error_mode: 'log', server_context: server_context)
92
90
 
93
91
  # Should return error response in MCP format
94
92
  expect(response).to be_a(MCP::Tool::Response)
95
93
  item = response.payload.first
96
94
  expect(item[:type] || item['type']).to eq('text')
97
95
 
98
- error_text = item[:text] || item['text']
96
+ error_text = item['text']
99
97
  expect(error_text).to include('Error')
100
98
  end
101
99
 
@@ -107,14 +105,14 @@ RSpec.describe SimpleCovMcp::Tools::VersionTool do
107
105
  # Replace VERSION with our mock object
108
106
  stub_const('SimpleCovMcp::VERSION', version_obj)
109
107
 
110
- response = described_class.call(error_mode: 'on', server_context: server_context)
108
+ response = described_class.call(error_mode: 'log', server_context: server_context)
111
109
 
112
110
  # Should return error response in MCP format via the rescue block
113
111
  expect(response).to be_a(MCP::Tool::Response)
114
112
  item = response.payload.first
115
113
  expect(item[:type] || item['type']).to eq('text')
116
114
 
117
- error_text = item[:text] || item['text']
115
+ error_text = item['text']
118
116
  expect(error_text).to include('Error')
119
117
  end
120
118
 
@@ -130,12 +128,12 @@ RSpec.describe SimpleCovMcp::Tools::VersionTool do
130
128
  item = response.payload.first
131
129
  expect(item[:type] || item['type']).to eq('text')
132
130
 
133
- # Test error_mode 'trace' (should include more detail)
134
- response = described_class.call(error_mode: 'trace', server_context: server_context)
131
+ # Test error_mode 'debug' (should include more detail)
132
+ response = described_class.call(error_mode: 'debug', server_context: server_context)
135
133
  expect(response).to be_a(MCP::Tool::Response)
136
134
  item = response.payload.first
137
135
  expect(item[:type] || item['type']).to eq('text')
138
- error_text = item[:text] || item['text']
136
+ error_text = item['text']
139
137
  expect(error_text).to include('Error')
140
138
  end
141
139
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: simplecov-mcp
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Keith R. Bennett
@@ -9,6 +9,20 @@ bindir: exe
9
9
  cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: awesome_print
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '1.9'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '1.9'
12
26
  - !ruby/object:Gem::Dependency
13
27
  name: mcp
14
28
  requirement: !ruby/object:Gem::Requirement
@@ -54,42 +68,53 @@ extra_rdoc_files: []
54
68
  files:
55
69
  - LICENSE
56
70
  - README.md
57
- - docs/ADVANCED_USAGE.md
58
- - docs/ARCHITECTURE.md
59
- - docs/BRANCH_ONLY_COVERAGE.md
60
- - docs/CLI_USAGE.md
61
- - docs/DEVELOPMENT.md
62
- - docs/ERROR_HANDLING.md
63
- - docs/EXAMPLES.md
64
- - docs/INSTALLATION.md
65
- - docs/LIBRARY_API.md
66
- - docs/MCP_INTEGRATION.md
67
- - docs/TROUBLESHOOTING.md
68
- - docs/arch-decisions/001-x-arch-decision.md
69
- - docs/arch-decisions/002-x-arch-decision.md
70
- - docs/arch-decisions/003-x-arch-decision.md
71
- - docs/arch-decisions/004-x-arch-decision.md
72
- - docs/arch-decisions/005-x-arch-decision.md
73
- - docs/arch-decisions/README.md
74
- - docs/presentations/simplecov-mcp-presentation.md
71
+ - docs/dev/ARCHITECTURE.md
72
+ - docs/dev/BRANCH_ONLY_COVERAGE.md
73
+ - docs/dev/DEVELOPMENT.md
74
+ - docs/dev/README.md
75
+ - docs/dev/RELEASING.md
76
+ - docs/dev/arch-decisions/001-x-arch-decision.md
77
+ - docs/dev/arch-decisions/002-x-arch-decision.md
78
+ - docs/dev/arch-decisions/003-x-arch-decision.md
79
+ - docs/dev/arch-decisions/004-x-arch-decision.md
80
+ - docs/dev/arch-decisions/005-x-arch-decision.md
81
+ - docs/dev/arch-decisions/README.md
82
+ - docs/dev/presentations/simplecov-mcp-presentation.md
83
+ - docs/fixtures/demo_project/README.md
84
+ - docs/user/ADVANCED_USAGE.md
85
+ - docs/user/CLI_FALLBACK_FOR_LLMS.md
86
+ - docs/user/CLI_USAGE.md
87
+ - docs/user/ERROR_HANDLING.md
88
+ - docs/user/EXAMPLES.md
89
+ - docs/user/INSTALLATION.md
90
+ - docs/user/LIBRARY_API.md
91
+ - docs/user/MCP_INTEGRATION.md
92
+ - docs/user/README.md
93
+ - docs/user/TROUBLESHOOTING.md
94
+ - docs/user/V2-BREAKING-CHANGES.md
75
95
  - exe/simplecov-mcp
76
96
  - lib/simplecov_mcp.rb
97
+ - lib/simplecov_mcp/app_config.rb
77
98
  - lib/simplecov_mcp/app_context.rb
78
99
  - lib/simplecov_mcp/base_tool.rb
79
100
  - lib/simplecov_mcp/cli.rb
80
- - lib/simplecov_mcp/cli_config.rb
81
101
  - lib/simplecov_mcp/commands/base_command.rb
82
102
  - lib/simplecov_mcp/commands/command_factory.rb
83
103
  - lib/simplecov_mcp/commands/detailed_command.rb
84
104
  - lib/simplecov_mcp/commands/list_command.rb
85
105
  - lib/simplecov_mcp/commands/raw_command.rb
86
106
  - lib/simplecov_mcp/commands/summary_command.rb
107
+ - lib/simplecov_mcp/commands/totals_command.rb
87
108
  - lib/simplecov_mcp/commands/uncovered_command.rb
109
+ - lib/simplecov_mcp/commands/validate_command.rb
88
110
  - lib/simplecov_mcp/commands/version_command.rb
111
+ - lib/simplecov_mcp/config_parser.rb
89
112
  - lib/simplecov_mcp/constants.rb
113
+ - lib/simplecov_mcp/coverage_reporter.rb
90
114
  - lib/simplecov_mcp/error_handler.rb
91
115
  - lib/simplecov_mcp/error_handler_factory.rb
92
116
  - lib/simplecov_mcp/errors.rb
117
+ - lib/simplecov_mcp/formatters.rb
93
118
  - lib/simplecov_mcp/formatters/source_formatter.rb
94
119
  - lib/simplecov_mcp/mcp_server.rb
95
120
  - lib/simplecov_mcp/mode_detector.rb
@@ -99,48 +124,60 @@ files:
99
124
  - lib/simplecov_mcp/option_parsers/env_options_parser.rb
100
125
  - lib/simplecov_mcp/option_parsers/error_helper.rb
101
126
  - lib/simplecov_mcp/path_relativizer.rb
127
+ - lib/simplecov_mcp/predicate_evaluator.rb
102
128
  - lib/simplecov_mcp/presenters/base_coverage_presenter.rb
103
129
  - lib/simplecov_mcp/presenters/coverage_detailed_presenter.rb
104
130
  - lib/simplecov_mcp/presenters/coverage_raw_presenter.rb
105
131
  - lib/simplecov_mcp/presenters/coverage_summary_presenter.rb
106
132
  - lib/simplecov_mcp/presenters/coverage_uncovered_presenter.rb
107
133
  - lib/simplecov_mcp/presenters/project_coverage_presenter.rb
134
+ - lib/simplecov_mcp/presenters/project_totals_presenter.rb
108
135
  - lib/simplecov_mcp/resolvers/coverage_line_resolver.rb
109
136
  - lib/simplecov_mcp/resolvers/resolver_factory.rb
110
137
  - lib/simplecov_mcp/resolvers/resultset_path_resolver.rb
111
138
  - lib/simplecov_mcp/resultset_loader.rb
112
139
  - lib/simplecov_mcp/staleness_checker.rb
140
+ - lib/simplecov_mcp/table_formatter.rb
113
141
  - lib/simplecov_mcp/tools/all_files_coverage_tool.rb
114
142
  - lib/simplecov_mcp/tools/coverage_detailed_tool.rb
115
143
  - lib/simplecov_mcp/tools/coverage_raw_tool.rb
116
144
  - lib/simplecov_mcp/tools/coverage_summary_tool.rb
117
145
  - lib/simplecov_mcp/tools/coverage_table_tool.rb
146
+ - lib/simplecov_mcp/tools/coverage_totals_tool.rb
118
147
  - lib/simplecov_mcp/tools/help_tool.rb
119
148
  - lib/simplecov_mcp/tools/uncovered_lines_tool.rb
149
+ - lib/simplecov_mcp/tools/validate_tool.rb
120
150
  - lib/simplecov_mcp/tools/version_tool.rb
121
151
  - lib/simplecov_mcp/util.rb
122
152
  - lib/simplecov_mcp/version.rb
123
153
  - spec/MCP_INTEGRATION_TESTS_README.md
124
154
  - spec/TIMESTAMPS.md
125
155
  - spec/all_files_coverage_tool_spec.rb
156
+ - spec/app_config_spec.rb
126
157
  - spec/base_tool_spec.rb
127
158
  - spec/cli/show_default_report_spec.rb
128
- - spec/cli_config_spec.rb
129
159
  - spec/cli_enumerated_options_spec.rb
130
160
  - spec/cli_error_spec.rb
161
+ - spec/cli_format_spec.rb
162
+ - spec/cli_json_options_spec.rb
131
163
  - spec/cli_source_spec.rb
132
164
  - spec/cli_spec.rb
133
- - spec/cli_success_predicate_spec.rb
134
165
  - spec/cli_table_spec.rb
135
166
  - spec/cli_usage_spec.rb
136
167
  - spec/commands/base_command_spec.rb
137
168
  - spec/commands/command_factory_spec.rb
138
169
  - spec/commands/detailed_command_spec.rb
170
+ - spec/commands/list_command_spec.rb
139
171
  - spec/commands/raw_command_spec.rb
140
172
  - spec/commands/summary_command_spec.rb
173
+ - spec/commands/totals_command_spec.rb
141
174
  - spec/commands/uncovered_command_spec.rb
175
+ - spec/commands/validate_command_spec.rb
176
+ - spec/commands/version_command_spec.rb
142
177
  - spec/constants_spec.rb
178
+ - spec/coverage_reporter_spec.rb
143
179
  - spec/coverage_table_tool_spec.rb
180
+ - spec/coverage_totals_tool_spec.rb
144
181
  - spec/error_handler_spec.rb
145
182
  - spec/error_mode_spec.rb
146
183
  - spec/errors_edge_cases_spec.rb
@@ -166,6 +203,7 @@ files:
166
203
  - spec/presenters/coverage_summary_presenter_spec.rb
167
204
  - spec/presenters/coverage_uncovered_presenter_spec.rb
168
205
  - spec/presenters/project_coverage_presenter_spec.rb
206
+ - spec/presenters/project_totals_presenter_spec.rb
169
207
  - spec/resolvers/coverage_line_resolver_spec.rb
170
208
  - spec/resolvers/resolver_factory_spec.rb
171
209
  - spec/resolvers/resultset_path_resolver_spec.rb
@@ -173,14 +211,26 @@ files:
173
211
  - spec/shared_examples/README.md
174
212
  - spec/shared_examples/coverage_presenter_examples.rb
175
213
  - spec/shared_examples/file_based_mcp_tools.rb
214
+ - spec/shared_examples/formatted_command_examples.rb
176
215
  - spec/shared_examples/mcp_tool_text_json_response.rb
177
216
  - spec/simple_cov_mcp_module_spec.rb
217
+ - spec/simplecov_mcp/formatters/source_formatter_spec.rb
218
+ - spec/simplecov_mcp/formatters_spec.rb
219
+ - spec/simplecov_mcp/presenters/base_coverage_presenter_spec.rb
178
220
  - spec/simplecov_mcp_model_spec.rb
179
221
  - spec/simplecov_mcp_opts_spec.rb
180
222
  - spec/spec_helper.rb
181
223
  - spec/staleness_checker_spec.rb
182
224
  - spec/staleness_more_spec.rb
225
+ - spec/support/cli_helpers.rb
226
+ - spec/support/control_flow_helpers.rb
227
+ - spec/support/fake_mcp.rb
228
+ - spec/support/io_helpers.rb
229
+ - spec/support/mcp_helpers.rb
183
230
  - spec/support/mcp_runner.rb
231
+ - spec/support/mocking_helpers.rb
232
+ - spec/table_format_spec.rb
233
+ - spec/tools/validate_tool_spec.rb
184
234
  - spec/tools_error_handling_spec.rb
185
235
  - spec/util_spec.rb
186
236
  - spec/version_spec.rb
@@ -190,6 +240,23 @@ licenses:
190
240
  - MIT
191
241
  metadata:
192
242
  rubygems_mfa_required: 'true'
243
+ post_install_message: |
244
+ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
245
+ ┃ V2.0.0 BREAKING CHANGES ┃
246
+ ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
247
+ ┃ ┃
248
+ ┃ V2.0.0 brings several breaking changes to this gem: ┃
249
+ ┃ ┃
250
+ ┃ • Options must now come BEFORE subcommands ┃
251
+ ┃ • --stale renamed to --staleness (-S still works) ┃
252
+ ┃ • --json replaced with --format json ┃
253
+ ┃ • Error modes renamed: 'on' → 'log', 'trace' → 'debug' ┃
254
+ ┃ • --success-predicate moved to 'validate' subcommand ┃
255
+ ┃ • Default sort order changed from ascending to descending ┃
256
+ ┃ ┃
257
+ ┃ See docs/user/V2-BREAKING-CHANGES.md for complete migration guide. ┃
258
+ ┃ ┃
259
+ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
193
260
  rdoc_options: []
194
261
  require_paths:
195
262
  - lib
@@ -204,7 +271,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
204
271
  - !ruby/object:Gem::Version
205
272
  version: '0'
206
273
  requirements: []
207
- rubygems_version: 3.6.9
274
+ rubygems_version: 3.7.2
208
275
  specification_version: 4
209
276
  summary: MCP server + CLI for SimpleCov coverage data
210
277
  test_files: []
@@ -1,81 +0,0 @@
1
- # Branch-Only Coverage Handling
2
-
3
- SimpleCov can collect *line* coverage, *branch* coverage, or both. Projects that
4
- enable the `:branch` mode without `:line` produce a `.resultset.json` where the
5
- per-file entries contain a `branches` hash while the legacy `lines` array is
6
- `null`. This document explains that format and why SimpleCov MCP synthesizes a
7
- line array on the fly so downstream consumers continue to work.
8
-
9
- ## SimpleCov branch payloads
10
-
11
- Each resultset groups coverage by absolute (or project-relative) path. A branch
12
- only entry looks like:
13
-
14
- ```json
15
- {
16
- "lib/example.rb": {
17
- "lines": null,
18
- "branches": {
19
- "[:if, 0, 12, 4, 20, 29]": {
20
- "[:then, 1, 13, 6, 13, 18]": 4,
21
- "[:else, 2, 15, 6, 15, 16]": 0
22
- }
23
- }
24
- }
25
- }
26
- ```
27
-
28
- Key observations:
29
-
30
- - The outer hash key is either a stringified Ruby array or the raw array itself:
31
- `[:if, branch_id, line, column, end_line, end_column]`. Array structure:
32
- - index 0: branch type (`:if`, `:case`, `:unless`, etc.)
33
- - index 1: internal branch identifier
34
- - **index 2: line where the branch starts** (the field we care about for coverage)
35
- - index 3: column where the branch starts
36
- - index 4: line where the branch expression ends
37
- - index 5: column where the branch expression ends
38
- - SimpleCov reuses a single branch tuple for all recorded runs.
39
- - The nested hash contains targets (`[:then, …]`, `[:else, …]`, `[:when, …]`, etc.)
40
- Each target tuple mirrors the same shape—branch type at index 0, an internal
41
- identifier at 1, then the start/end positions for that branch leg.
42
- The integer value is the execution count for that branch leg. SimpleCov MCP
43
- sums these counts per line when synthesizing fallback line data.
44
-
45
- ## Synthesizing line coverage
46
-
47
- SimpleCov MCP exposes APIs and CLI tooling built around line-oriented coverage.
48
- To support branch-only projects, we reconstruct a minimal line array by summing
49
- branch hits per line. The resolver:
50
-
51
- 1. Normalizes branch tuples, whether they arrive as arrays or strings.
52
- 2. Extracts the line token (element `2`) and converts it to an integer.
53
- 3. Aggregates hit counts across all branch targets for that line.
54
- 4. Builds a dense array up to the highest line seen. Each populated slot stores
55
- the total branch hits recorded for that line. Slots remain `nil` when a line
56
- never appeared in the branch data.
57
-
58
- This produces the familiar SimpleCov shape (array index → line number - 1), so
59
- utilities like `summary`, `uncovered`, and staleness checks keep working.
60
-
61
- ## Code map
62
-
63
- Relevant implementation points:
64
-
65
- - `lib/simplecov_mcp/resolvers/coverage_line_resolver.rb` — entry point that
66
- synthesizes the array when `lines` is missing.
67
- - Specs covering branch-only behaviour live in
68
- `spec/resolvers/coverage_line_resolver_spec.rb` and
69
- `spec/simplecov_mcp_model_spec.rb`.
70
- - Fixture data resides at
71
- `spec/fixtures/branch_only_project/coverage/.resultset.json`.
72
-
73
- Implementation notes:
74
-
75
- - The resolver must return `nil` when a path fails to match. `CovUtil.lookup_lines`
76
- tries alternate keys (absolute, project-relative, cwd-stripped). Returning
77
- `nil` allows those attempts to continue, ultimately raising the expected
78
- `FileError` only after every variant is exhausted.
79
- - SimpleCov may evolve the branch tuple format. When that happens, extend
80
- `extract_line_number` to recognize the new shape and refresh this document so
81
- future maintainers understand which forms are supported.