kicad-sch-api 0.1.1__py3-none-any.whl → 0.1.3__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.

Potentially problematic release.


This version of kicad-sch-api might be problematic. Click here for more details.

kicad_sch_api/cli.py ADDED
@@ -0,0 +1,345 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ KiCAD Schematic API - Command Line Interface
4
+
5
+ Provides helpful commands for setup, testing, and usage of the MCP server.
6
+ """
7
+
8
+ import sys
9
+ import json
10
+ import os
11
+ import subprocess
12
+ import argparse
13
+ from pathlib import Path
14
+ from typing import Dict, Any
15
+
16
+ def get_claude_config_path() -> Path:
17
+ """Get the Claude Code configuration file path for current platform."""
18
+ if sys.platform == "darwin":
19
+ return Path.home() / "Library/Application Support/Claude/claude_desktop_config.json"
20
+ elif sys.platform == "win32":
21
+ return Path(os.environ["APPDATA"]) / "Claude/claude_desktop_config.json"
22
+ else: # Linux and others
23
+ return Path.home() / ".config/Claude/claude_desktop_config.json"
24
+
25
+ def setup_claude_code() -> bool:
26
+ """Automatically configure Claude Code MCP settings."""
27
+ print("🔧 Setting up Claude Code MCP configuration...")
28
+
29
+ config_path = get_claude_config_path()
30
+
31
+ # Create directory if it doesn't exist
32
+ config_path.parent.mkdir(parents=True, exist_ok=True)
33
+
34
+ # Backup existing config
35
+ if config_path.exists():
36
+ backup_path = config_path.with_suffix(f".backup.{config_path.stat().st_mtime:.0f}.json")
37
+ backup_path.write_text(config_path.read_text())
38
+ print(f"📁 Backed up existing config to: {backup_path}")
39
+
40
+ # Determine MCP command path
41
+ mcp_command = os.environ.get('FOUND_MCP_PATH', 'kicad-sch-mcp')
42
+
43
+ # If still using default, try to find the actual path
44
+ if mcp_command == 'kicad-sch-mcp':
45
+ python_version = f"{sys.version_info.major}.{sys.version_info.minor}"
46
+ possible_paths = [
47
+ f"/Library/Frameworks/Python.framework/Versions/{python_version}/bin/kicad-sch-mcp",
48
+ os.path.expanduser(f"~/Library/Python/{python_version}/bin/kicad-sch-mcp"),
49
+ os.path.expanduser("~/.local/bin/kicad-sch-mcp"),
50
+ "/usr/local/bin/kicad-sch-mcp"
51
+ ]
52
+
53
+ for path_to_try in possible_paths:
54
+ if os.path.exists(path_to_try) and os.access(path_to_try, os.X_OK):
55
+ mcp_command = path_to_try
56
+ print(f"📍 Using MCP command at: {mcp_command}")
57
+ break
58
+
59
+ # Create new configuration
60
+ config = {
61
+ "mcpServers": {
62
+ "kicad-sch-api": {
63
+ "command": mcp_command,
64
+ "args": [],
65
+ "env": {}
66
+ }
67
+ }
68
+ }
69
+
70
+ # Write configuration
71
+ with open(config_path, 'w') as f:
72
+ json.dump(config, f, indent=2)
73
+
74
+ print(f"✅ Configuration written to: {config_path}")
75
+ print("🔄 Please restart Claude Code to apply changes")
76
+ return True
77
+
78
+ def test_installation() -> bool:
79
+ """Test that the MCP server is working correctly."""
80
+ print("🧪 Testing KiCAD Schematic MCP Server...")
81
+
82
+ try:
83
+ # Test import
84
+ from kicad_sch_api.mcp.server import main as mcp_main
85
+ print("✅ MCP server module imports successfully")
86
+
87
+ # Test component discovery
88
+ from kicad_sch_api.discovery.search_index import get_search_index
89
+ print("✅ Component discovery system available")
90
+
91
+ # Test KiCAD library access
92
+ from kicad_sch_api.library.cache import get_symbol_cache
93
+ cache = get_symbol_cache()
94
+ stats = cache.get_performance_stats()
95
+ print(f"✅ Symbol cache initialized: {stats['total_symbols_cached']} symbols")
96
+
97
+ print("🎉 All tests passed!")
98
+ return True
99
+
100
+ except Exception as e:
101
+ print(f"❌ Test failed: {e}")
102
+ return False
103
+
104
+ def show_status() -> bool:
105
+ """Show current installation and configuration status."""
106
+ print("📊 KiCAD Schematic MCP Server Status")
107
+ print("=" * 40)
108
+
109
+ # Check installation
110
+ try:
111
+ import kicad_sch_api
112
+ version = getattr(kicad_sch_api, '__version__', 'unknown')
113
+ print(f"✅ Package installed: v{version}")
114
+ except ImportError:
115
+ print("❌ Package not installed")
116
+ return False
117
+
118
+ # Check MCP command
119
+ mcp_cmd_path = None
120
+ try:
121
+ result = subprocess.run(['kicad-sch-mcp', '--help'],
122
+ capture_output=True, timeout=5)
123
+ if result.returncode == 0:
124
+ print("✅ MCP command available")
125
+ mcp_cmd_path = "kicad-sch-mcp"
126
+ else:
127
+ print("⚠️ MCP command found but returns error")
128
+ except (subprocess.TimeoutExpired, FileNotFoundError):
129
+ # Try to find the command in common locations
130
+ import sys
131
+ python_version = f"{sys.version_info.major}.{sys.version_info.minor}"
132
+ possible_paths = [
133
+ f"/Library/Frameworks/Python.framework/Versions/{python_version}/bin/kicad-sch-mcp",
134
+ os.path.expanduser(f"~/Library/Python/{python_version}/bin/kicad-sch-mcp"),
135
+ os.path.expanduser("~/.local/bin/kicad-sch-mcp"),
136
+ "/usr/local/bin/kicad-sch-mcp"
137
+ ]
138
+
139
+ for path_to_try in possible_paths:
140
+ if os.path.exists(path_to_try) and os.access(path_to_try, os.X_OK):
141
+ print(f"✅ MCP command found at: {path_to_try}")
142
+ print("⚠️ Note: Command not in PATH, but found at above location")
143
+ mcp_cmd_path = path_to_try
144
+ break
145
+
146
+ if not mcp_cmd_path:
147
+ print("❌ MCP command not found in PATH")
148
+ print(" You may need to add Python scripts directory to your PATH")
149
+ print(f" Try: export PATH=\"/Library/Frameworks/Python.framework/Versions/{python_version}/bin:$PATH\"")
150
+
151
+ # Store found path for potential use in configuration
152
+ if mcp_cmd_path:
153
+ os.environ['FOUND_MCP_PATH'] = mcp_cmd_path
154
+
155
+ # Check Claude Code configuration
156
+ config_path = get_claude_config_path()
157
+ if config_path.exists():
158
+ try:
159
+ with open(config_path) as f:
160
+ config = json.load(f)
161
+ if "kicad-sch-api" in config.get("mcpServers", {}):
162
+ print("✅ Claude Code MCP configuration found")
163
+ else:
164
+ print("⚠️ Claude Code config exists but kicad-sch-api not configured")
165
+ except json.JSONDecodeError:
166
+ print("❌ Claude Code config file is invalid JSON")
167
+ else:
168
+ print("❌ Claude Code configuration not found")
169
+
170
+ # Check KiCAD libraries
171
+ try:
172
+ from kicad_sch_api.library.cache import get_symbol_cache
173
+ cache = get_symbol_cache()
174
+ stats = cache.get_performance_stats()
175
+ print(f"✅ KiCAD libraries: {len(cache._lib_stats)} libraries, {stats['total_symbols_cached']} symbols")
176
+ except Exception as e:
177
+ print(f"⚠️ KiCAD library access: {e}")
178
+
179
+ return True
180
+
181
+ def create_demo() -> bool:
182
+ """Create a demo schematic to test functionality."""
183
+ print("🎨 Creating demo schematic...")
184
+
185
+ try:
186
+ import kicad_sch_api as ksa
187
+
188
+ # Create demo schematic
189
+ sch = ksa.create_schematic("Demo_Circuit")
190
+
191
+ # Add components
192
+ resistor = sch.components.add('Device:R', reference='R1', value='10k', position=(100, 100))
193
+ capacitor = sch.components.add('Device:C', reference='C1', value='100nF', position=(150, 100))
194
+ led = sch.components.add('Device:LED', reference='D1', value='LED', position=(200, 100))
195
+
196
+ # Add a hierarchical sheet
197
+ sheet_uuid = sch.add_sheet(
198
+ name="Subcircuit",
199
+ filename="subcircuit_demo.kicad_sch",
200
+ position=(100, 150),
201
+ size=(60, 40)
202
+ )
203
+
204
+ # Add sheet pins
205
+ sch.add_sheet_pin(sheet_uuid, "VCC", "input", (0, 10))
206
+ sch.add_sheet_pin(sheet_uuid, "GND", "input", (0, 30))
207
+
208
+ # Save schematic
209
+ sch.save("demo_circuit.kicad_sch")
210
+
211
+ print("✅ Demo schematic created: demo_circuit.kicad_sch")
212
+ print("📁 Contains: resistor, capacitor, LED, and hierarchical sheet")
213
+ print("🔗 Try opening in KiCAD: kicad demo_circuit.kicad_sch")
214
+
215
+ return True
216
+
217
+ except Exception as e:
218
+ print(f"❌ Demo creation failed: {e}")
219
+ return False
220
+
221
+ def init_cache() -> bool:
222
+ """Initialize the component discovery cache."""
223
+ print("🔄 Initializing component discovery cache...")
224
+
225
+ try:
226
+ from kicad_sch_api.discovery.search_index import ensure_index_built
227
+ component_count = ensure_index_built()
228
+ print(f"✅ Component cache initialized: {component_count} components indexed")
229
+ return True
230
+ except Exception as e:
231
+ print(f"❌ Cache initialization failed: {e}")
232
+ return False
233
+
234
+ def check_kicad() -> bool:
235
+ """Check KiCAD installation and library access."""
236
+ print("🔍 Checking KiCAD installation...")
237
+
238
+ try:
239
+ # Check if KiCAD command is available
240
+ result = subprocess.run(['kicad', '--version'],
241
+ capture_output=True, timeout=10)
242
+ if result.returncode == 0:
243
+ version_output = result.stdout.decode().strip()
244
+ print(f"✅ KiCAD found: {version_output}")
245
+ else:
246
+ print("⚠️ KiCAD command found but version check failed")
247
+ except (subprocess.TimeoutExpired, FileNotFoundError):
248
+ print("❌ KiCAD command not found in PATH")
249
+ print(" Please ensure KiCAD is installed and accessible")
250
+
251
+ # Check library directories
252
+ try:
253
+ from kicad_sch_api.library.cache import get_symbol_cache
254
+ cache = get_symbol_cache()
255
+
256
+ print("📚 KiCAD Library Status:")
257
+ for lib_name, lib_stats in cache._lib_stats.items():
258
+ print(f" • {lib_name}: {lib_stats.symbol_count} symbols")
259
+
260
+ return True
261
+ except Exception as e:
262
+ print(f"❌ Library access failed: {e}")
263
+ return False
264
+
265
+ def show_logs():
266
+ """Show recent MCP server logs."""
267
+ print("📜 Recent MCP Server Logs")
268
+ print("=" * 25)
269
+
270
+ # For now, just run the server with debug output
271
+ print("To view live logs, run:")
272
+ print(" kicad-sch-mcp --debug")
273
+ print()
274
+ print("Or check Claude Code logs in:")
275
+ if sys.platform == "darwin":
276
+ print(" ~/Library/Logs/Claude/mcp-server-kicad-sch-api.log")
277
+ elif sys.platform == "win32":
278
+ print(" %USERPROFILE%\\AppData\\Local\\Claude\\Logs\\mcp-server-kicad-sch-api.log")
279
+ else:
280
+ print(" ~/.local/share/Claude/logs/mcp-server-kicad-sch-api.log")
281
+
282
+ def main():
283
+ """Main CLI entry point."""
284
+ parser = argparse.ArgumentParser(
285
+ description="KiCAD Schematic API - Command Line Interface",
286
+ formatter_class=argparse.RawDescriptionHelpFormatter,
287
+ epilog="""
288
+ Examples:
289
+ kicad-sch-api --setup-claude-code # Configure Claude Code MCP
290
+ kicad-sch-api --test # Test installation
291
+ kicad-sch-api --demo # Create demo schematic
292
+ kicad-sch-api --status # Show status
293
+ """
294
+ )
295
+
296
+ parser.add_argument('--setup-claude-code', action='store_true',
297
+ help='Configure Claude Code MCP settings automatically')
298
+ parser.add_argument('--test', action='store_true',
299
+ help='Test that the installation is working')
300
+ parser.add_argument('--status', action='store_true',
301
+ help='Show installation and configuration status')
302
+ parser.add_argument('--demo', action='store_true',
303
+ help='Create a demo schematic')
304
+ parser.add_argument('--init-cache', action='store_true',
305
+ help='Initialize component discovery cache')
306
+ parser.add_argument('--check-kicad', action='store_true',
307
+ help='Check KiCAD installation and libraries')
308
+ parser.add_argument('--logs', action='store_true',
309
+ help='Show recent MCP server logs')
310
+
311
+ args = parser.parse_args()
312
+
313
+ # If no arguments provided, show help
314
+ if not any(vars(args).values()):
315
+ parser.print_help()
316
+ return
317
+
318
+ # Execute requested actions
319
+ success = True
320
+
321
+ if args.setup_claude_code:
322
+ success &= setup_claude_code()
323
+
324
+ if args.test:
325
+ success &= test_installation()
326
+
327
+ if args.status:
328
+ success &= show_status()
329
+
330
+ if args.demo:
331
+ success &= create_demo()
332
+
333
+ if args.init_cache:
334
+ success &= init_cache()
335
+
336
+ if args.check_kicad:
337
+ success &= check_kicad()
338
+
339
+ if args.logs:
340
+ show_logs()
341
+
342
+ sys.exit(0 if success else 1)
343
+
344
+ if __name__ == "__main__":
345
+ main()
@@ -0,0 +1,10 @@
1
+ """
2
+ Component discovery tools for KiCAD schematic API.
3
+
4
+ This module provides fast search and discovery capabilities for KiCAD components
5
+ using a SQLite search index built from the existing symbol cache.
6
+ """
7
+
8
+ from .search_index import ComponentSearchIndex, get_search_index
9
+
10
+ __all__ = ["ComponentSearchIndex", "get_search_index"]