hatch-xclam 0.7.1.dev3__py3-none-any.whl → 0.8.0.dev1__py3-none-any.whl

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 (81) hide show
  1. hatch/__init__.py +1 -1
  2. hatch/cli/__init__.py +71 -0
  3. hatch/cli/__main__.py +1035 -0
  4. hatch/cli/cli_env.py +865 -0
  5. hatch/cli/cli_mcp.py +1965 -0
  6. hatch/cli/cli_package.py +566 -0
  7. hatch/cli/cli_system.py +136 -0
  8. hatch/cli/cli_utils.py +1289 -0
  9. hatch/cli_hatch.py +160 -2838
  10. hatch/mcp_host_config/__init__.py +10 -10
  11. hatch/mcp_host_config/adapters/__init__.py +34 -0
  12. hatch/mcp_host_config/adapters/base.py +170 -0
  13. hatch/mcp_host_config/adapters/claude.py +105 -0
  14. hatch/mcp_host_config/adapters/codex.py +104 -0
  15. hatch/mcp_host_config/adapters/cursor.py +83 -0
  16. hatch/mcp_host_config/adapters/gemini.py +75 -0
  17. hatch/mcp_host_config/adapters/kiro.py +78 -0
  18. hatch/mcp_host_config/adapters/lmstudio.py +79 -0
  19. hatch/mcp_host_config/adapters/registry.py +149 -0
  20. hatch/mcp_host_config/adapters/vscode.py +83 -0
  21. hatch/mcp_host_config/backup.py +5 -3
  22. hatch/mcp_host_config/fields.py +126 -0
  23. hatch/mcp_host_config/models.py +161 -456
  24. hatch/mcp_host_config/reporting.py +57 -16
  25. hatch/mcp_host_config/strategies.py +155 -87
  26. hatch/template_generator.py +1 -1
  27. {hatch_xclam-0.7.1.dev3.dist-info → hatch_xclam-0.8.0.dev1.dist-info}/METADATA +3 -2
  28. {hatch_xclam-0.7.1.dev3.dist-info → hatch_xclam-0.8.0.dev1.dist-info}/RECORD +52 -43
  29. {hatch_xclam-0.7.1.dev3.dist-info → hatch_xclam-0.8.0.dev1.dist-info}/WHEEL +1 -1
  30. hatch_xclam-0.8.0.dev1.dist-info/entry_points.txt +2 -0
  31. tests/cli_test_utils.py +280 -0
  32. tests/integration/cli/__init__.py +14 -0
  33. tests/integration/cli/test_cli_reporter_integration.py +2439 -0
  34. tests/integration/mcp/__init__.py +0 -0
  35. tests/integration/mcp/test_adapter_serialization.py +173 -0
  36. tests/regression/cli/__init__.py +16 -0
  37. tests/regression/cli/test_color_logic.py +268 -0
  38. tests/regression/cli/test_consequence_type.py +298 -0
  39. tests/regression/cli/test_error_formatting.py +328 -0
  40. tests/regression/cli/test_result_reporter.py +586 -0
  41. tests/regression/cli/test_table_formatter.py +211 -0
  42. tests/regression/mcp/__init__.py +0 -0
  43. tests/regression/mcp/test_field_filtering.py +162 -0
  44. tests/test_cli_version.py +7 -5
  45. tests/test_data/fixtures/cli_reporter_fixtures.py +184 -0
  46. tests/unit/__init__.py +0 -0
  47. tests/unit/mcp/__init__.py +0 -0
  48. tests/unit/mcp/test_adapter_protocol.py +138 -0
  49. tests/unit/mcp/test_adapter_registry.py +158 -0
  50. tests/unit/mcp/test_config_model.py +146 -0
  51. hatch_xclam-0.7.1.dev3.dist-info/entry_points.txt +0 -2
  52. tests/integration/test_mcp_kiro_integration.py +0 -153
  53. tests/regression/test_mcp_codex_backup_integration.py +0 -162
  54. tests/regression/test_mcp_codex_host_strategy.py +0 -163
  55. tests/regression/test_mcp_codex_model_validation.py +0 -117
  56. tests/regression/test_mcp_kiro_backup_integration.py +0 -241
  57. tests/regression/test_mcp_kiro_cli_integration.py +0 -141
  58. tests/regression/test_mcp_kiro_decorator_registration.py +0 -71
  59. tests/regression/test_mcp_kiro_host_strategy.py +0 -214
  60. tests/regression/test_mcp_kiro_model_validation.py +0 -116
  61. tests/regression/test_mcp_kiro_omni_conversion.py +0 -104
  62. tests/test_mcp_atomic_operations.py +0 -276
  63. tests/test_mcp_backup_integration.py +0 -308
  64. tests/test_mcp_cli_all_host_specific_args.py +0 -496
  65. tests/test_mcp_cli_backup_management.py +0 -295
  66. tests/test_mcp_cli_direct_management.py +0 -456
  67. tests/test_mcp_cli_discovery_listing.py +0 -582
  68. tests/test_mcp_cli_host_config_integration.py +0 -823
  69. tests/test_mcp_cli_package_management.py +0 -360
  70. tests/test_mcp_cli_partial_updates.py +0 -859
  71. tests/test_mcp_environment_integration.py +0 -520
  72. tests/test_mcp_host_config_backup.py +0 -257
  73. tests/test_mcp_host_configuration_manager.py +0 -331
  74. tests/test_mcp_host_registry_decorator.py +0 -348
  75. tests/test_mcp_pydantic_architecture_v4.py +0 -603
  76. tests/test_mcp_server_config_models.py +0 -242
  77. tests/test_mcp_server_config_type_field.py +0 -221
  78. tests/test_mcp_sync_functionality.py +0 -316
  79. tests/test_mcp_user_feedback_reporting.py +0 -359
  80. {hatch_xclam-0.7.1.dev3.dist-info → hatch_xclam-0.8.0.dev1.dist-info}/licenses/LICENSE +0 -0
  81. {hatch_xclam-0.7.1.dev3.dist-info → hatch_xclam-0.8.0.dev1.dist-info}/top_level.txt +0 -0
@@ -1,348 +0,0 @@
1
- """
2
- Test suite for decorator-based host registry.
3
-
4
- This module tests the decorator-based strategy registration system
5
- following Hatchling patterns with inheritance validation.
6
- """
7
-
8
- import unittest
9
- import sys
10
- from pathlib import Path
11
-
12
- # Add the parent directory to the path to import wobble
13
- sys.path.insert(0, str(Path(__file__).parent.parent))
14
-
15
- try:
16
- from wobble.decorators import regression_test, integration_test
17
- except ImportError:
18
- # Fallback decorators if wobble is not available
19
- def regression_test(func):
20
- return func
21
-
22
- def integration_test(scope="component"):
23
- def decorator(func):
24
- return func
25
- return decorator
26
-
27
- from hatch.mcp_host_config.host_management import MCPHostRegistry, register_host_strategy, MCPHostStrategy
28
- from hatch.mcp_host_config.models import MCPHostType, MCPServerConfig, HostConfiguration
29
- from pathlib import Path
30
-
31
-
32
- class TestMCPHostRegistryDecorator(unittest.TestCase):
33
- """Test suite for decorator-based host registry."""
34
-
35
- def setUp(self):
36
- """Set up test environment."""
37
- # Clear registry before each test
38
- MCPHostRegistry._strategies.clear()
39
- MCPHostRegistry._instances.clear()
40
-
41
- def tearDown(self):
42
- """Clean up test environment."""
43
- # Clear registry after each test
44
- MCPHostRegistry._strategies.clear()
45
- MCPHostRegistry._instances.clear()
46
-
47
- @regression_test
48
- def test_decorator_registration_functionality(self):
49
- """Test that decorator registration works correctly."""
50
-
51
- @register_host_strategy(MCPHostType.CLAUDE_DESKTOP)
52
- class TestClaudeStrategy(MCPHostStrategy):
53
- def get_config_path(self):
54
- return Path("/test/path")
55
- def is_host_available(self):
56
- return True
57
- def read_configuration(self):
58
- return HostConfiguration()
59
- def write_configuration(self, config, no_backup=False):
60
- return True
61
- def validate_server_config(self, server_config):
62
- return True
63
-
64
- # Verify registration
65
- self.assertIn(MCPHostType.CLAUDE_DESKTOP, MCPHostRegistry._strategies)
66
- self.assertEqual(
67
- MCPHostRegistry._strategies[MCPHostType.CLAUDE_DESKTOP],
68
- TestClaudeStrategy
69
- )
70
-
71
- # Verify instance creation
72
- strategy = MCPHostRegistry.get_strategy(MCPHostType.CLAUDE_DESKTOP)
73
- self.assertIsInstance(strategy, TestClaudeStrategy)
74
-
75
- @regression_test
76
- def test_decorator_registration_with_inheritance(self):
77
- """Test decorator registration with inheritance patterns."""
78
-
79
- class TestClaudeBase(MCPHostStrategy):
80
- def __init__(self):
81
- self.company_origin = "Anthropic"
82
- self.config_format = "claude_format"
83
-
84
- def get_config_key(self):
85
- return "mcpServers"
86
-
87
- @register_host_strategy(MCPHostType.CLAUDE_DESKTOP)
88
- class TestClaudeDesktop(TestClaudeBase):
89
- def get_config_path(self):
90
- return Path("/test/claude")
91
- def is_host_available(self):
92
- return True
93
- def read_configuration(self):
94
- return HostConfiguration()
95
- def write_configuration(self, config, no_backup=False):
96
- return True
97
- def validate_server_config(self, server_config):
98
- return True
99
-
100
- strategy = MCPHostRegistry.get_strategy(MCPHostType.CLAUDE_DESKTOP)
101
-
102
- # Verify inheritance properties
103
- self.assertEqual(strategy.company_origin, "Anthropic")
104
- self.assertEqual(strategy.config_format, "claude_format")
105
- self.assertEqual(strategy.get_config_key(), "mcpServers")
106
- self.assertIsInstance(strategy, TestClaudeBase)
107
-
108
- @regression_test
109
- def test_decorator_registration_duplicate_warning(self):
110
- """Test warning on duplicate strategy registration."""
111
- import logging
112
-
113
- class BaseTestStrategy(MCPHostStrategy):
114
- def get_config_path(self):
115
- return Path("/test")
116
- def is_host_available(self):
117
- return True
118
- def read_configuration(self):
119
- return HostConfiguration()
120
- def write_configuration(self, config, no_backup=False):
121
- return True
122
- def validate_server_config(self, server_config):
123
- return True
124
-
125
- @register_host_strategy(MCPHostType.CLAUDE_DESKTOP)
126
- class FirstStrategy(BaseTestStrategy):
127
- pass
128
-
129
- # Register second strategy for same host type - should log warning
130
- with self.assertLogs('hatch.mcp_host_config.host_management', level='WARNING') as log:
131
- @register_host_strategy(MCPHostType.CLAUDE_DESKTOP)
132
- class SecondStrategy(BaseTestStrategy):
133
- pass
134
-
135
- # Verify warning was logged
136
- self.assertTrue(any("Overriding existing strategy" in message for message in log.output))
137
-
138
- # Verify second strategy is now registered
139
- strategy = MCPHostRegistry.get_strategy(MCPHostType.CLAUDE_DESKTOP)
140
- self.assertIsInstance(strategy, SecondStrategy)
141
-
142
- @regression_test
143
- def test_decorator_registration_inheritance_validation(self):
144
- """Test that decorator validates inheritance from MCPHostStrategy."""
145
-
146
- # Should raise ValueError for non-MCPHostStrategy class
147
- with self.assertRaises(ValueError) as context:
148
- @register_host_strategy(MCPHostType.CLAUDE_DESKTOP)
149
- class InvalidStrategy: # Does not inherit from MCPHostStrategy
150
- pass
151
-
152
- self.assertIn("must inherit from MCPHostStrategy", str(context.exception))
153
-
154
- @regression_test
155
- def test_registry_get_strategy_unknown_host_type(self):
156
- """Test error handling for unknown host type."""
157
- # Clear registry to ensure no strategies are registered
158
- MCPHostRegistry._strategies.clear()
159
-
160
- with self.assertRaises(ValueError) as context:
161
- MCPHostRegistry.get_strategy(MCPHostType.CLAUDE_DESKTOP)
162
-
163
- self.assertIn("Unknown host type", str(context.exception))
164
- self.assertIn("Available: []", str(context.exception))
165
-
166
- @regression_test
167
- def test_registry_singleton_instance_behavior(self):
168
- """Test that registry returns singleton instances."""
169
-
170
- @register_host_strategy(MCPHostType.CLAUDE_DESKTOP)
171
- class TestStrategy(MCPHostStrategy):
172
- def __init__(self):
173
- self.instance_id = id(self)
174
-
175
- def get_config_path(self):
176
- return Path("/test")
177
- def is_host_available(self):
178
- return True
179
- def read_configuration(self):
180
- return HostConfiguration()
181
- def write_configuration(self, config, no_backup=False):
182
- return True
183
- def validate_server_config(self, server_config):
184
- return True
185
-
186
- # Get strategy multiple times
187
- strategy1 = MCPHostRegistry.get_strategy(MCPHostType.CLAUDE_DESKTOP)
188
- strategy2 = MCPHostRegistry.get_strategy(MCPHostType.CLAUDE_DESKTOP)
189
-
190
- # Should be the same instance
191
- self.assertIs(strategy1, strategy2)
192
- self.assertEqual(strategy1.instance_id, strategy2.instance_id)
193
-
194
- @regression_test
195
- def test_registry_detect_available_hosts(self):
196
- """Test host detection functionality."""
197
-
198
- @register_host_strategy(MCPHostType.CLAUDE_DESKTOP)
199
- class AvailableStrategy(MCPHostStrategy):
200
- def get_config_path(self):
201
- return Path("/test")
202
- def is_host_available(self):
203
- return True # Available
204
- def read_configuration(self):
205
- return HostConfiguration()
206
- def write_configuration(self, config, no_backup=False):
207
- return True
208
- def validate_server_config(self, server_config):
209
- return True
210
-
211
- @register_host_strategy(MCPHostType.CURSOR)
212
- class UnavailableStrategy(MCPHostStrategy):
213
- def get_config_path(self):
214
- return Path("/test")
215
- def is_host_available(self):
216
- return False # Not available
217
- def read_configuration(self):
218
- return HostConfiguration()
219
- def write_configuration(self, config, no_backup=False):
220
- return True
221
- def validate_server_config(self, server_config):
222
- return True
223
-
224
- @register_host_strategy(MCPHostType.VSCODE)
225
- class ErrorStrategy(MCPHostStrategy):
226
- def get_config_path(self):
227
- return Path("/test")
228
- def is_host_available(self):
229
- raise Exception("Detection error") # Error during detection
230
- def read_configuration(self):
231
- return HostConfiguration()
232
- def write_configuration(self, config, no_backup=False):
233
- return True
234
- def validate_server_config(self, server_config):
235
- return True
236
-
237
- available_hosts = MCPHostRegistry.detect_available_hosts()
238
-
239
- # Only the available strategy should be detected
240
- self.assertIn(MCPHostType.CLAUDE_DESKTOP, available_hosts)
241
- self.assertNotIn(MCPHostType.CURSOR, available_hosts)
242
- self.assertNotIn(MCPHostType.VSCODE, available_hosts)
243
-
244
- @regression_test
245
- def test_registry_family_mappings(self):
246
- """Test family host mappings."""
247
- claude_family = MCPHostRegistry.get_family_hosts("claude")
248
- cursor_family = MCPHostRegistry.get_family_hosts("cursor")
249
- unknown_family = MCPHostRegistry.get_family_hosts("unknown")
250
-
251
- # Verify family mappings
252
- self.assertIn(MCPHostType.CLAUDE_DESKTOP, claude_family)
253
- self.assertIn(MCPHostType.CLAUDE_CODE, claude_family)
254
- self.assertIn(MCPHostType.CURSOR, cursor_family)
255
- self.assertIn(MCPHostType.LMSTUDIO, cursor_family)
256
- self.assertEqual(unknown_family, [])
257
-
258
- @regression_test
259
- def test_registry_get_host_config_path(self):
260
- """Test getting host configuration path through registry."""
261
-
262
- @register_host_strategy(MCPHostType.CLAUDE_DESKTOP)
263
- class TestStrategy(MCPHostStrategy):
264
- def get_config_path(self):
265
- return Path("/test/claude/config.json")
266
- def is_host_available(self):
267
- return True
268
- def read_configuration(self):
269
- return HostConfiguration()
270
- def write_configuration(self, config, no_backup=False):
271
- return True
272
- def validate_server_config(self, server_config):
273
- return True
274
-
275
- config_path = MCPHostRegistry.get_host_config_path(MCPHostType.CLAUDE_DESKTOP)
276
- self.assertEqual(config_path, Path("/test/claude/config.json"))
277
-
278
-
279
- class TestFamilyBasedStrategyRegistration(unittest.TestCase):
280
- """Test suite for family-based strategy registration with decorators."""
281
-
282
- def setUp(self):
283
- """Set up test environment."""
284
- # Clear registry before each test
285
- MCPHostRegistry._strategies.clear()
286
- MCPHostRegistry._instances.clear()
287
-
288
- def tearDown(self):
289
- """Clean up test environment."""
290
- # Clear registry after each test
291
- MCPHostRegistry._strategies.clear()
292
- MCPHostRegistry._instances.clear()
293
-
294
- @regression_test
295
- def test_claude_family_decorator_registration(self):
296
- """Test Claude family strategies register with decorators."""
297
-
298
- class TestClaudeBase(MCPHostStrategy):
299
- def __init__(self):
300
- self.company_origin = "Anthropic"
301
- self.config_format = "claude_format"
302
-
303
- def validate_server_config(self, server_config):
304
- # Claude family accepts any valid command or URL
305
- if server_config.command or server_config.url:
306
- return True
307
- return False
308
-
309
- @register_host_strategy(MCPHostType.CLAUDE_DESKTOP)
310
- class TestClaudeDesktop(TestClaudeBase):
311
- def get_config_path(self):
312
- return Path("/test/claude_desktop")
313
- def is_host_available(self):
314
- return True
315
- def read_configuration(self):
316
- return HostConfiguration()
317
- def write_configuration(self, config, no_backup=False):
318
- return True
319
-
320
- @register_host_strategy(MCPHostType.CLAUDE_CODE)
321
- class TestClaudeCode(TestClaudeBase):
322
- def get_config_path(self):
323
- return Path("/test/claude_code")
324
- def is_host_available(self):
325
- return True
326
- def read_configuration(self):
327
- return HostConfiguration()
328
- def write_configuration(self, config, no_backup=False):
329
- return True
330
-
331
- # Verify both strategies are registered
332
- claude_desktop = MCPHostRegistry.get_strategy(MCPHostType.CLAUDE_DESKTOP)
333
- claude_code = MCPHostRegistry.get_strategy(MCPHostType.CLAUDE_CODE)
334
-
335
- # Verify inheritance properties
336
- self.assertEqual(claude_desktop.company_origin, "Anthropic")
337
- self.assertEqual(claude_code.company_origin, "Anthropic")
338
- self.assertIsInstance(claude_desktop, TestClaudeBase)
339
- self.assertIsInstance(claude_code, TestClaudeBase)
340
-
341
- # Verify family mappings
342
- claude_family = MCPHostRegistry.get_family_hosts("claude")
343
- self.assertIn(MCPHostType.CLAUDE_DESKTOP, claude_family)
344
- self.assertIn(MCPHostType.CLAUDE_CODE, claude_family)
345
-
346
-
347
- if __name__ == '__main__':
348
- unittest.main()