kicad-sch-api 0.1.5__tar.gz → 0.1.7__tar.gz
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-0.1.5 → kicad_sch_api-0.1.7}/PKG-INFO +1 -1
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/kicad_sch_api/cli.py +33 -178
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/kicad_sch_api/mcp/server.py +2 -112
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/kicad_sch_api.egg-info/PKG-INFO +1 -1
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/kicad_sch_api.egg-info/SOURCES.txt +0 -1
- kicad_sch_api-0.1.7/kicad_sch_api.egg-info/entry_points.txt +3 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/pyproject.toml +1 -7
- kicad_sch_api-0.1.5/kicad_sch_api/daemon.py +0 -322
- kicad_sch_api-0.1.5/kicad_sch_api.egg-info/entry_points.txt +0 -7
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/.claude/commands/dev/dead-code-analysis.md +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/.claude/commands/dev/publish-pypi.md +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/.claude/commands/dev/review-implementation.md +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/.claude/commands/dev/run-tests.md +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/.claude/commands/dev/update-and-commit.md +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/.claude/commands/dev/update-memory-bank.md +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/.claude/commands/test/run-reference-tests.md +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/LICENSE +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/MANIFEST.in +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/README.md +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/examples/advanced_usage.py +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/examples/basic_usage.py +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/examples/mcp_basic_example.py +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/examples/mcp_integration.py +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/kicad_sch_api/__init__.py +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/kicad_sch_api/core/__init__.py +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/kicad_sch_api/core/components.py +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/kicad_sch_api/core/formatter.py +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/kicad_sch_api/core/ic_manager.py +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/kicad_sch_api/core/junctions.py +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/kicad_sch_api/core/parser.py +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/kicad_sch_api/core/schematic.py +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/kicad_sch_api/core/types.py +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/kicad_sch_api/core/wires.py +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/kicad_sch_api/discovery/__init__.py +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/kicad_sch_api/discovery/search_index.py +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/kicad_sch_api/library/__init__.py +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/kicad_sch_api/library/cache.py +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/kicad_sch_api/mcp/__init__.py +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/kicad_sch_api/py.typed +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/kicad_sch_api/utils/__init__.py +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/kicad_sch_api/utils/validation.py +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/kicad_sch_api.egg-info/dependency_links.txt +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/kicad_sch_api.egg-info/requires.txt +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/kicad_sch_api.egg-info/top_level.txt +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/setup.cfg +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/tests/reference_tests/reference_kicad_projects/README.md +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/tests/reference_tests/reference_kicad_projects/blank_schematic/blank_schematic.kicad_pro +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/tests/reference_tests/reference_kicad_projects/blank_schematic/blank_schematic.kicad_sch +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/tests/reference_tests/reference_kicad_projects/multi_unit_7400/multi_unit_7400.kicad_pro +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/tests/reference_tests/reference_kicad_projects/multi_unit_7400/multi_unit_7400.kicad_sch +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/tests/reference_tests/reference_kicad_projects/power_symbols/power_symbols.kicad_pro +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/tests/reference_tests/reference_kicad_projects/power_symbols/power_symbols.kicad_sch +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/tests/reference_tests/reference_kicad_projects/resistor_divider/resistor_divider.kicad_pro +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/tests/reference_tests/reference_kicad_projects/resistor_divider/resistor_divider.kicad_sch +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/tests/reference_tests/reference_kicad_projects/sch_title/sch_title.kicad_pro +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/tests/reference_tests/reference_kicad_projects/sch_title/sch_title.kicad_sch +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/tests/reference_tests/reference_kicad_projects/single_extended_component/single_extended_component.kicad_pro +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/tests/reference_tests/reference_kicad_projects/single_extended_component/single_extended_component.kicad_sch +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/tests/reference_tests/reference_kicad_projects/single_hierarchical_sheet/single_hierarchical_sheet.kicad_pro +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/tests/reference_tests/reference_kicad_projects/single_hierarchical_sheet/single_hierarchical_sheet.kicad_sch +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/tests/reference_tests/reference_kicad_projects/single_hierarchical_sheet/subcircuit1.kicad_sch +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/tests/reference_tests/reference_kicad_projects/single_label/single_label.kicad_pro +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/tests/reference_tests/reference_kicad_projects/single_label/single_label.kicad_sch +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/tests/reference_tests/reference_kicad_projects/single_label_hierarchical/single_label_hierarchical.kicad_pro +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/tests/reference_tests/reference_kicad_projects/single_label_hierarchical/single_label_hierarchical.kicad_sch +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/tests/reference_tests/reference_kicad_projects/single_resistor/single_resistor.kicad_pro +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/tests/reference_tests/reference_kicad_projects/single_resistor/single_resistor.kicad_sch +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/tests/reference_tests/reference_kicad_projects/single_text/single_text.kicad_pro +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/tests/reference_tests/reference_kicad_projects/single_text/single_text.kicad_sch +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/tests/reference_tests/reference_kicad_projects/single_text_box/single_text_box.kicad_pro +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/tests/reference_tests/reference_kicad_projects/single_text_box/single_text_box.kicad_sch +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/tests/reference_tests/reference_kicad_projects/single_wire/single_wire.kicad_pro +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/tests/reference_tests/reference_kicad_projects/single_wire/single_wire.kicad_sch +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/tests/reference_tests/reference_kicad_projects/two_resistors/two_resistors.kicad_pro +0 -0
- {kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/tests/reference_tests/reference_kicad_projects/two_resistors/two_resistors.kicad_sch +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: kicad-sch-api
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.7
|
|
4
4
|
Summary: Professional KiCAD schematic manipulation library with exact format preservation and AI agent integration
|
|
5
5
|
Author-email: Circuit-Synth <shane@circuit-synth.com>
|
|
6
6
|
Maintainer-email: Circuit-Synth <shane@circuit-synth.com>
|
|
@@ -37,34 +37,22 @@ def setup_claude_code() -> bool:
|
|
|
37
37
|
backup_path.write_text(config_path.read_text())
|
|
38
38
|
print(f"📁 Backed up existing config to: {backup_path}")
|
|
39
39
|
|
|
40
|
-
#
|
|
41
|
-
|
|
40
|
+
# Read existing config or create new one
|
|
41
|
+
if config_path.exists():
|
|
42
|
+
with open(config_path) as f:
|
|
43
|
+
config = json.load(f)
|
|
44
|
+
else:
|
|
45
|
+
config = {}
|
|
42
46
|
|
|
43
|
-
#
|
|
44
|
-
if
|
|
45
|
-
|
|
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
|
|
47
|
+
# Ensure mcpServers section exists
|
|
48
|
+
if "mcpServers" not in config:
|
|
49
|
+
config["mcpServers"] = {}
|
|
58
50
|
|
|
59
|
-
#
|
|
60
|
-
config = {
|
|
61
|
-
"
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
"args": [],
|
|
65
|
-
"env": {}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
51
|
+
# Use direct Python command - this is more reliable than trying to find binary paths
|
|
52
|
+
config["mcpServers"]["kicad-sch-api"] = {
|
|
53
|
+
"command": sys.executable,
|
|
54
|
+
"args": ["-m", "kicad_sch_api.mcp.server"],
|
|
55
|
+
"env": {}
|
|
68
56
|
}
|
|
69
57
|
|
|
70
58
|
# Write configuration
|
|
@@ -282,7 +270,7 @@ def show_logs():
|
|
|
282
270
|
def setup_everything() -> bool:
|
|
283
271
|
"""One-command setup that does everything automatically."""
|
|
284
272
|
print("🚀 KiCAD Schematic API - Complete Setup")
|
|
285
|
-
print("=" *
|
|
273
|
+
print("=" * 40)
|
|
286
274
|
print()
|
|
287
275
|
|
|
288
276
|
success = True
|
|
@@ -300,7 +288,7 @@ def setup_everything() -> bool:
|
|
|
300
288
|
print("⚠️ Cache initialization failed, but continuing...")
|
|
301
289
|
print()
|
|
302
290
|
|
|
303
|
-
# 3. Setup Claude Code
|
|
291
|
+
# 3. Setup Claude Code (using direct Python command)
|
|
304
292
|
print("Step 3/4: Configuring Claude Code...")
|
|
305
293
|
if not setup_claude_code():
|
|
306
294
|
print("⚠️ Claude Code setup failed, but continuing...")
|
|
@@ -315,97 +303,23 @@ def setup_everything() -> bool:
|
|
|
315
303
|
# Final status
|
|
316
304
|
print("🎉 Setup Complete!")
|
|
317
305
|
print()
|
|
318
|
-
print("
|
|
306
|
+
print("✅ What was configured:")
|
|
307
|
+
print(" • MCP server ready for Claude Code")
|
|
308
|
+
print(" • Component discovery cache initialized")
|
|
309
|
+
print(" • Demo schematic created")
|
|
310
|
+
print()
|
|
311
|
+
print("🚀 Next steps:")
|
|
319
312
|
print("1. Restart Claude Code")
|
|
320
313
|
print("2. Try: 'Create a voltage divider with two 10kΩ resistors'")
|
|
321
314
|
print("3. Open demo_circuit.kicad_sch in KiCAD to see the example")
|
|
322
315
|
print()
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
def setup_daemon() -> bool:
|
|
327
|
-
"""Setup with daemon-style MCP server (RECOMMENDED)."""
|
|
328
|
-
print("🚀 KiCAD Schematic API - Daemon Setup")
|
|
329
|
-
print("=" * 50)
|
|
330
|
-
print("This will set up a persistent MCP daemon that runs in the background.")
|
|
331
|
-
print()
|
|
332
|
-
|
|
333
|
-
success = True
|
|
334
|
-
|
|
335
|
-
# 1. Test installation
|
|
336
|
-
print("Step 1/5: Testing installation...")
|
|
337
|
-
if not test_installation():
|
|
338
|
-
print("❌ Installation test failed. Please reinstall the package.")
|
|
339
|
-
return False
|
|
316
|
+
print("🔍 To test manually:")
|
|
317
|
+
print(" python -m kicad_sch_api.mcp.server --test")
|
|
340
318
|
print()
|
|
341
319
|
|
|
342
|
-
# 2. Initialize cache
|
|
343
|
-
print("Step 2/5: Initializing component cache...")
|
|
344
|
-
if not init_cache():
|
|
345
|
-
print("⚠️ Cache initialization failed, but continuing...")
|
|
346
|
-
print()
|
|
347
|
-
|
|
348
|
-
# 3. Start daemon
|
|
349
|
-
print("Step 3/5: Starting MCP daemon...")
|
|
350
|
-
from .daemon import MCPDaemon
|
|
351
|
-
daemon = MCPDaemon()
|
|
352
|
-
|
|
353
|
-
if daemon.is_running():
|
|
354
|
-
print("✅ Daemon is already running")
|
|
355
|
-
else:
|
|
356
|
-
if not daemon.start():
|
|
357
|
-
print("❌ Failed to start daemon")
|
|
358
|
-
return False
|
|
359
|
-
print()
|
|
360
|
-
|
|
361
|
-
# 4. Configure Claude Code
|
|
362
|
-
print("Step 4/5: Configuring Claude Code...")
|
|
363
|
-
if not daemon._update_claude_config():
|
|
364
|
-
print("⚠️ Claude Code configuration failed, but daemon is running...")
|
|
365
|
-
else:
|
|
366
|
-
print("✅ Claude Code configured successfully")
|
|
367
|
-
print()
|
|
368
|
-
|
|
369
|
-
# 5. Create demo
|
|
370
|
-
print("Step 5/5: Creating demo schematic...")
|
|
371
|
-
if not create_demo():
|
|
372
|
-
print("⚠️ Demo creation failed, but setup is complete")
|
|
373
|
-
print()
|
|
374
|
-
|
|
375
|
-
# Final status
|
|
376
|
-
status = daemon.get_status()
|
|
377
|
-
print("🎉 Daemon Setup Complete!")
|
|
378
|
-
print()
|
|
379
|
-
print("✨ What's new with daemon mode:")
|
|
380
|
-
print(" • MCP server runs persistently in background")
|
|
381
|
-
print(" • No PATH issues or virtual environment problems")
|
|
382
|
-
print(" • Automatic startup after system reboot (if desired)")
|
|
383
|
-
print(" • Better performance and reliability")
|
|
384
|
-
print()
|
|
385
|
-
print("📊 Status:")
|
|
386
|
-
print(f" Daemon running: {'✅ Yes' if status['running'] else '❌ No'}")
|
|
387
|
-
print(f" Claude configured: {'✅ Yes' if status['claude_configured'] else '❌ No'}")
|
|
388
|
-
print(f" Log file: {status['log_file']}")
|
|
389
|
-
print()
|
|
390
|
-
|
|
391
|
-
if status['running'] and status['claude_configured']:
|
|
392
|
-
print("🚀 Next steps:")
|
|
393
|
-
print("1. Restart Claude Code")
|
|
394
|
-
print("2. Try: 'Create a voltage divider with two 10kΩ resistors'")
|
|
395
|
-
print("3. Open demo_circuit.kicad_sch in KiCAD to see the example")
|
|
396
|
-
print()
|
|
397
|
-
print("🔧 Daemon management:")
|
|
398
|
-
print(" kicad-sch-api --daemon-status # Check status")
|
|
399
|
-
print(" kicad-sch-api --stop-daemon # Stop daemon")
|
|
400
|
-
print(" kicad-sch-api --start-daemon # Start daemon")
|
|
401
|
-
print(" kicad-sch-api --restart-daemon # Restart daemon")
|
|
402
|
-
else:
|
|
403
|
-
print("⚠️ Setup incomplete. Check the status and try again.")
|
|
404
|
-
return False
|
|
405
|
-
|
|
406
|
-
print()
|
|
407
320
|
return True
|
|
408
321
|
|
|
322
|
+
|
|
409
323
|
def main():
|
|
410
324
|
"""Main CLI entry point."""
|
|
411
325
|
parser = argparse.ArgumentParser(
|
|
@@ -413,11 +327,8 @@ def main():
|
|
|
413
327
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
414
328
|
epilog="""
|
|
415
329
|
Examples:
|
|
416
|
-
kicad-sch-api --setup
|
|
417
|
-
kicad-sch-api --setup-
|
|
418
|
-
kicad-sch-api --start-daemon # Start MCP daemon in background
|
|
419
|
-
kicad-sch-api --stop-daemon # Stop MCP daemon
|
|
420
|
-
kicad-sch-api --daemon-status # Show daemon status
|
|
330
|
+
kicad-sch-api --setup # Complete one-command setup (RECOMMENDED)
|
|
331
|
+
kicad-sch-api --setup-claude-code # Configure Claude Code MCP settings only
|
|
421
332
|
kicad-sch-api --test # Test installation
|
|
422
333
|
kicad-sch-api --demo # Create demo schematic
|
|
423
334
|
"""
|
|
@@ -425,21 +336,9 @@ Examples:
|
|
|
425
336
|
|
|
426
337
|
# Main setup options
|
|
427
338
|
parser.add_argument('--setup', action='store_true',
|
|
428
|
-
help='Complete one-command setup (RECOMMENDED
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
# Daemon management
|
|
433
|
-
parser.add_argument('--start-daemon', action='store_true',
|
|
434
|
-
help='Start MCP daemon in background')
|
|
435
|
-
parser.add_argument('--stop-daemon', action='store_true',
|
|
436
|
-
help='Stop MCP daemon')
|
|
437
|
-
parser.add_argument('--restart-daemon', action='store_true',
|
|
438
|
-
help='Restart MCP daemon')
|
|
439
|
-
parser.add_argument('--daemon-status', action='store_true',
|
|
440
|
-
help='Show daemon status and logs')
|
|
441
|
-
|
|
442
|
-
# Legacy/manual setup options
|
|
339
|
+
help='Complete one-command setup (RECOMMENDED)')
|
|
340
|
+
|
|
341
|
+
# Setup options
|
|
443
342
|
parser.add_argument('--setup-claude-code', action='store_true',
|
|
444
343
|
help='Configure Claude Code MCP settings only')
|
|
445
344
|
parser.add_argument('--test', action='store_true',
|
|
@@ -457,65 +356,21 @@ Examples:
|
|
|
457
356
|
|
|
458
357
|
args = parser.parse_args()
|
|
459
358
|
|
|
460
|
-
# If no arguments provided, suggest
|
|
359
|
+
# If no arguments provided, suggest setup
|
|
461
360
|
if not any(vars(args).values()):
|
|
462
361
|
print("🚀 KiCAD Schematic API - Command Line Interface")
|
|
463
362
|
print()
|
|
464
|
-
print("🌟 RECOMMENDED:
|
|
465
|
-
print(" kicad-sch-api --setup-daemon")
|
|
466
|
-
print()
|
|
467
|
-
print("📖 For legacy setup:")
|
|
363
|
+
print("🌟 RECOMMENDED: Complete setup:")
|
|
468
364
|
print(" kicad-sch-api --setup")
|
|
469
365
|
print()
|
|
470
366
|
print("🆘 For help with all options:")
|
|
471
367
|
print(" kicad-sch-api --help")
|
|
472
368
|
return
|
|
473
369
|
|
|
474
|
-
# Import daemon management after args check
|
|
475
|
-
from .daemon import MCPDaemon
|
|
476
|
-
|
|
477
|
-
# Handle daemon commands
|
|
478
|
-
daemon = MCPDaemon()
|
|
479
|
-
|
|
480
|
-
if args.start_daemon:
|
|
481
|
-
success = daemon.start()
|
|
482
|
-
sys.exit(0 if success else 1)
|
|
483
|
-
|
|
484
|
-
if args.stop_daemon:
|
|
485
|
-
success = daemon.stop()
|
|
486
|
-
sys.exit(0 if success else 1)
|
|
487
|
-
|
|
488
|
-
if args.restart_daemon:
|
|
489
|
-
success = daemon.restart()
|
|
490
|
-
sys.exit(0 if success else 1)
|
|
491
|
-
|
|
492
|
-
if args.daemon_status:
|
|
493
|
-
status = daemon.get_status()
|
|
494
|
-
print(f"🚀 KiCAD Schematic MCP Server Status")
|
|
495
|
-
print("=" * 40)
|
|
496
|
-
print(f"Running: {'✅ Yes' if status['running'] else '❌ No'}")
|
|
497
|
-
|
|
498
|
-
if status["pid"]:
|
|
499
|
-
print(f"PID: {status['pid']}")
|
|
500
|
-
|
|
501
|
-
print(f"Log file: {status['log_file']}")
|
|
502
|
-
print(f"Claude configured: {'✅ Yes' if status['claude_configured'] else '❌ No'}")
|
|
503
|
-
|
|
504
|
-
if not status["claude_configured"]:
|
|
505
|
-
print("\n⚠️ Claude Code not configured. Run with --setup-daemon to fix.")
|
|
506
|
-
|
|
507
|
-
if status["running"]:
|
|
508
|
-
print("\n📜 Recent logs:")
|
|
509
|
-
daemon.show_logs(10)
|
|
510
|
-
|
|
511
|
-
return
|
|
512
|
-
|
|
513
370
|
# Execute requested actions
|
|
514
371
|
success = True
|
|
515
372
|
|
|
516
|
-
if args.
|
|
517
|
-
success &= setup_daemon()
|
|
518
|
-
elif args.setup:
|
|
373
|
+
if args.setup:
|
|
519
374
|
success &= setup_everything()
|
|
520
375
|
|
|
521
376
|
if args.setup_claude_code:
|
|
@@ -1457,28 +1457,17 @@ This hierarchical approach makes complex designs manageable and promotes reusabl
|
|
|
1457
1457
|
"""
|
|
1458
1458
|
|
|
1459
1459
|
def main():
|
|
1460
|
-
"""Run the MCP server."""
|
|
1460
|
+
"""Run the MCP server in standard on-demand mode."""
|
|
1461
1461
|
import argparse
|
|
1462
|
-
import os
|
|
1463
|
-
import signal
|
|
1464
|
-
import atexit
|
|
1465
|
-
import time
|
|
1466
1462
|
|
|
1467
1463
|
parser = argparse.ArgumentParser(description="KiCAD Schematic MCP Server")
|
|
1468
1464
|
parser.add_argument('--test', action='store_true', help='Run quick test and exit')
|
|
1469
1465
|
parser.add_argument('--debug', action='store_true', help='Enable debug logging')
|
|
1470
1466
|
parser.add_argument('--status', action='store_true', help='Show server status and exit')
|
|
1471
1467
|
parser.add_argument('--version', action='store_true', help='Show version and exit')
|
|
1472
|
-
parser.add_argument('--daemon', action='store_true', help='Run as daemon process')
|
|
1473
|
-
parser.add_argument('--log-file', type=str, help='Log file path for daemon mode')
|
|
1474
|
-
parser.add_argument('--pid-file', type=str, help='PID file path for daemon mode')
|
|
1475
1468
|
|
|
1476
1469
|
args = parser.parse_args()
|
|
1477
1470
|
|
|
1478
|
-
# Handle daemon mode
|
|
1479
|
-
if args.daemon:
|
|
1480
|
-
return run_daemon(args.log_file, args.pid_file, args.debug)
|
|
1481
|
-
|
|
1482
1471
|
if args.debug:
|
|
1483
1472
|
logging.getLogger().setLevel(logging.DEBUG)
|
|
1484
1473
|
logger.debug("Debug logging enabled")
|
|
@@ -1509,6 +1498,7 @@ def main():
|
|
|
1509
1498
|
|
|
1510
1499
|
logger.info("Starting KiCAD Schematic MCP Server...")
|
|
1511
1500
|
try:
|
|
1501
|
+
# Run normally - Claude Desktop will manage the process lifecycle
|
|
1512
1502
|
mcp.run()
|
|
1513
1503
|
except KeyboardInterrupt:
|
|
1514
1504
|
logger.info("Server stopped by user")
|
|
@@ -1516,106 +1506,6 @@ def main():
|
|
|
1516
1506
|
logger.error(f"Server error: {e}")
|
|
1517
1507
|
sys.exit(1)
|
|
1518
1508
|
|
|
1519
|
-
def run_daemon(log_file: Optional[str] = None, pid_file: Optional[str] = None, debug: bool = False):
|
|
1520
|
-
"""Run the MCP server as a daemon process."""
|
|
1521
|
-
import os
|
|
1522
|
-
import sys
|
|
1523
|
-
import signal
|
|
1524
|
-
import atexit
|
|
1525
|
-
from pathlib import Path
|
|
1526
|
-
|
|
1527
|
-
# Default paths
|
|
1528
|
-
if not log_file:
|
|
1529
|
-
log_file = str(Path.home() / ".kicad-sch-api" / "mcp-daemon.log")
|
|
1530
|
-
if not pid_file:
|
|
1531
|
-
pid_file = str(Path.home() / ".kicad-sch-api" / "mcp-daemon.pid")
|
|
1532
|
-
|
|
1533
|
-
# Ensure directory exists
|
|
1534
|
-
Path(log_file).parent.mkdir(parents=True, exist_ok=True)
|
|
1535
|
-
Path(pid_file).parent.mkdir(parents=True, exist_ok=True)
|
|
1536
|
-
|
|
1537
|
-
# Daemonize process
|
|
1538
|
-
try:
|
|
1539
|
-
pid = os.fork()
|
|
1540
|
-
if pid > 0:
|
|
1541
|
-
# Exit parent process
|
|
1542
|
-
sys.exit(0)
|
|
1543
|
-
except OSError as e:
|
|
1544
|
-
logger.error(f"Fork failed: {e}")
|
|
1545
|
-
sys.exit(1)
|
|
1546
|
-
|
|
1547
|
-
# Decouple from parent environment
|
|
1548
|
-
os.chdir("/")
|
|
1549
|
-
os.setsid()
|
|
1550
|
-
os.umask(0)
|
|
1551
|
-
|
|
1552
|
-
# Second fork
|
|
1553
|
-
try:
|
|
1554
|
-
pid = os.fork()
|
|
1555
|
-
if pid > 0:
|
|
1556
|
-
# Exit first child
|
|
1557
|
-
sys.exit(0)
|
|
1558
|
-
except OSError as e:
|
|
1559
|
-
logger.error(f"Second fork failed: {e}")
|
|
1560
|
-
sys.exit(1)
|
|
1561
|
-
|
|
1562
|
-
# Redirect standard file descriptors
|
|
1563
|
-
sys.stdout.flush()
|
|
1564
|
-
sys.stderr.flush()
|
|
1565
|
-
|
|
1566
|
-
# Redirect to log file
|
|
1567
|
-
with open(log_file, 'a') as f:
|
|
1568
|
-
os.dup2(f.fileno(), sys.stdout.fileno())
|
|
1569
|
-
os.dup2(f.fileno(), sys.stderr.fileno())
|
|
1570
|
-
|
|
1571
|
-
# Close stdin
|
|
1572
|
-
with open(os.devnull, 'r') as f:
|
|
1573
|
-
os.dup2(f.fileno(), sys.stdin.fileno())
|
|
1574
|
-
|
|
1575
|
-
# Write PID file
|
|
1576
|
-
with open(pid_file, 'w') as f:
|
|
1577
|
-
f.write(str(os.getpid()))
|
|
1578
|
-
|
|
1579
|
-
# Setup signal handlers for graceful shutdown
|
|
1580
|
-
def cleanup():
|
|
1581
|
-
"""Clean up PID file on exit."""
|
|
1582
|
-
try:
|
|
1583
|
-
os.unlink(pid_file)
|
|
1584
|
-
except OSError:
|
|
1585
|
-
pass
|
|
1586
|
-
|
|
1587
|
-
def signal_handler(signum, frame):
|
|
1588
|
-
"""Handle shutdown signals."""
|
|
1589
|
-
logger.info(f"Received signal {signum}, shutting down daemon...")
|
|
1590
|
-
cleanup()
|
|
1591
|
-
sys.exit(0)
|
|
1592
|
-
|
|
1593
|
-
signal.signal(signal.SIGTERM, signal_handler)
|
|
1594
|
-
signal.signal(signal.SIGINT, signal_handler)
|
|
1595
|
-
atexit.register(cleanup)
|
|
1596
|
-
|
|
1597
|
-
# Configure logging for daemon
|
|
1598
|
-
log_handler = logging.FileHandler(log_file)
|
|
1599
|
-
log_handler.setFormatter(logging.Formatter(
|
|
1600
|
-
'%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
|
1601
|
-
))
|
|
1602
|
-
|
|
1603
|
-
# Remove existing handlers and add file handler
|
|
1604
|
-
logger.handlers.clear()
|
|
1605
|
-
logger.addHandler(log_handler)
|
|
1606
|
-
logger.setLevel(logging.DEBUG if debug else logging.INFO)
|
|
1607
|
-
|
|
1608
|
-
# Start the MCP server
|
|
1609
|
-
logger.info("Starting KiCAD Schematic MCP Server daemon...")
|
|
1610
|
-
logger.info(f"PID: {os.getpid()}")
|
|
1611
|
-
logger.info(f"Log file: {log_file}")
|
|
1612
|
-
|
|
1613
|
-
try:
|
|
1614
|
-
mcp.run()
|
|
1615
|
-
except Exception as e:
|
|
1616
|
-
logger.error(f"Daemon error: {e}")
|
|
1617
|
-
cleanup()
|
|
1618
|
-
sys.exit(1)
|
|
1619
1509
|
|
|
1620
1510
|
if __name__ == "__main__":
|
|
1621
1511
|
main()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: kicad-sch-api
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.7
|
|
4
4
|
Summary: Professional KiCAD schematic manipulation library with exact format preservation and AI agent integration
|
|
5
5
|
Author-email: Circuit-Synth <shane@circuit-synth.com>
|
|
6
6
|
Maintainer-email: Circuit-Synth <shane@circuit-synth.com>
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "kicad-sch-api"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.7"
|
|
8
8
|
description = "Professional KiCAD schematic manipulation library with exact format preservation and AI agent integration"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
@@ -43,12 +43,6 @@ dependencies = [
|
|
|
43
43
|
kicad-sch-api = "kicad_sch_api.cli:main"
|
|
44
44
|
kicad-sch-mcp = "kicad_sch_api.mcp.server:main"
|
|
45
45
|
|
|
46
|
-
# New daemon-style entry points
|
|
47
|
-
kicad-sch-daemon = "kicad_sch_api.daemon:main"
|
|
48
|
-
kicad-sch-daemon-start = "kicad_sch_api.daemon:start_daemon"
|
|
49
|
-
kicad-sch-daemon-stop = "kicad_sch_api.daemon:stop_daemon"
|
|
50
|
-
kicad-sch-daemon-status = "kicad_sch_api.daemon:status_daemon"
|
|
51
|
-
|
|
52
46
|
[project.optional-dependencies]
|
|
53
47
|
dev = [
|
|
54
48
|
"pytest>=7.0.0",
|
|
@@ -1,322 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""
|
|
3
|
-
KiCAD Schematic API - MCP Server Daemon
|
|
4
|
-
|
|
5
|
-
Provides daemon-style MCP server with proper process management.
|
|
6
|
-
Users can start/stop/restart the server as a background process.
|
|
7
|
-
"""
|
|
8
|
-
|
|
9
|
-
import os
|
|
10
|
-
import sys
|
|
11
|
-
import signal
|
|
12
|
-
import subprocess
|
|
13
|
-
import time
|
|
14
|
-
import json
|
|
15
|
-
import logging
|
|
16
|
-
from pathlib import Path
|
|
17
|
-
from typing import Optional
|
|
18
|
-
import tempfile
|
|
19
|
-
|
|
20
|
-
# Setup logging
|
|
21
|
-
logging.basicConfig(
|
|
22
|
-
level=logging.INFO,
|
|
23
|
-
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
|
24
|
-
)
|
|
25
|
-
logger = logging.getLogger(__name__)
|
|
26
|
-
|
|
27
|
-
class MCPDaemon:
|
|
28
|
-
"""Manages the MCP server as a daemon process."""
|
|
29
|
-
|
|
30
|
-
def __init__(self):
|
|
31
|
-
self.name = "kicad-sch-mcp"
|
|
32
|
-
self.home_dir = Path.home()
|
|
33
|
-
self.config_dir = self.home_dir / ".kicad-sch-api"
|
|
34
|
-
self.config_dir.mkdir(exist_ok=True)
|
|
35
|
-
|
|
36
|
-
# Daemon files
|
|
37
|
-
self.pid_file = self.config_dir / "mcp-daemon.pid"
|
|
38
|
-
self.log_file = self.config_dir / "mcp-daemon.log"
|
|
39
|
-
self.socket_file = self.config_dir / "mcp-daemon.sock"
|
|
40
|
-
|
|
41
|
-
# Claude configuration
|
|
42
|
-
self.claude_config = self._get_claude_config_path()
|
|
43
|
-
|
|
44
|
-
def _get_claude_config_path(self) -> Path:
|
|
45
|
-
"""Get the Claude Code configuration file path for current platform."""
|
|
46
|
-
if sys.platform == "darwin":
|
|
47
|
-
return self.home_dir / "Library/Application Support/Claude/claude_desktop_config.json"
|
|
48
|
-
elif sys.platform == "win32":
|
|
49
|
-
return Path(os.environ["APPDATA"]) / "Claude/claude_desktop_config.json"
|
|
50
|
-
else: # Linux and others
|
|
51
|
-
return self.home_dir / ".config/Claude/claude_desktop_config.json"
|
|
52
|
-
|
|
53
|
-
def is_running(self) -> bool:
|
|
54
|
-
"""Check if daemon is currently running."""
|
|
55
|
-
if not self.pid_file.exists():
|
|
56
|
-
return False
|
|
57
|
-
|
|
58
|
-
try:
|
|
59
|
-
with open(self.pid_file) as f:
|
|
60
|
-
pid = int(f.read().strip())
|
|
61
|
-
|
|
62
|
-
# Check if process is still alive
|
|
63
|
-
os.kill(pid, 0)
|
|
64
|
-
return True
|
|
65
|
-
except (ValueError, ProcessLookupError, OSError):
|
|
66
|
-
# PID file exists but process is dead, clean up
|
|
67
|
-
self.pid_file.unlink(missing_ok=True)
|
|
68
|
-
return False
|
|
69
|
-
|
|
70
|
-
def get_status(self) -> dict:
|
|
71
|
-
"""Get detailed daemon status."""
|
|
72
|
-
status = {
|
|
73
|
-
"running": self.is_running(),
|
|
74
|
-
"pid": None,
|
|
75
|
-
"log_file": str(self.log_file),
|
|
76
|
-
"socket_file": str(self.socket_file),
|
|
77
|
-
"claude_configured": self._check_claude_config()
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
if status["running"] and self.pid_file.exists():
|
|
81
|
-
try:
|
|
82
|
-
with open(self.pid_file) as f:
|
|
83
|
-
status["pid"] = int(f.read().strip())
|
|
84
|
-
except (ValueError, OSError):
|
|
85
|
-
pass
|
|
86
|
-
|
|
87
|
-
return status
|
|
88
|
-
|
|
89
|
-
def _check_claude_config(self) -> bool:
|
|
90
|
-
"""Check if Claude Code is configured with our MCP server."""
|
|
91
|
-
if not self.claude_config.exists():
|
|
92
|
-
return False
|
|
93
|
-
|
|
94
|
-
try:
|
|
95
|
-
with open(self.claude_config) as f:
|
|
96
|
-
config = json.load(f)
|
|
97
|
-
|
|
98
|
-
servers = config.get("mcpServers", {})
|
|
99
|
-
return "kicad-sch-api" in servers
|
|
100
|
-
except (json.JSONDecodeError, OSError):
|
|
101
|
-
return False
|
|
102
|
-
|
|
103
|
-
def start(self) -> bool:
|
|
104
|
-
"""Start the daemon process."""
|
|
105
|
-
if self.is_running():
|
|
106
|
-
logger.info("Daemon is already running")
|
|
107
|
-
return True
|
|
108
|
-
|
|
109
|
-
logger.info("Starting MCP daemon...")
|
|
110
|
-
|
|
111
|
-
try:
|
|
112
|
-
# Create the daemon process using the MCP server entry point
|
|
113
|
-
cmd = [
|
|
114
|
-
sys.executable, "-m", "kicad_sch_api.mcp.server",
|
|
115
|
-
"--daemon",
|
|
116
|
-
"--log-file", str(self.log_file),
|
|
117
|
-
"--pid-file", str(self.pid_file)
|
|
118
|
-
]
|
|
119
|
-
|
|
120
|
-
# Start daemon process
|
|
121
|
-
process = subprocess.Popen(
|
|
122
|
-
cmd,
|
|
123
|
-
stdout=subprocess.DEVNULL,
|
|
124
|
-
stderr=subprocess.DEVNULL,
|
|
125
|
-
stdin=subprocess.DEVNULL,
|
|
126
|
-
start_new_session=True
|
|
127
|
-
)
|
|
128
|
-
|
|
129
|
-
# Give it a moment to start
|
|
130
|
-
time.sleep(2)
|
|
131
|
-
|
|
132
|
-
# Check if it started successfully
|
|
133
|
-
if self.is_running():
|
|
134
|
-
logger.info(f"Daemon started successfully (PID: {process.pid})")
|
|
135
|
-
self._update_claude_config()
|
|
136
|
-
return True
|
|
137
|
-
else:
|
|
138
|
-
logger.error("Failed to start daemon")
|
|
139
|
-
return False
|
|
140
|
-
|
|
141
|
-
except Exception as e:
|
|
142
|
-
logger.error(f"Error starting daemon: {e}")
|
|
143
|
-
return False
|
|
144
|
-
|
|
145
|
-
def stop(self) -> bool:
|
|
146
|
-
"""Stop the daemon process."""
|
|
147
|
-
if not self.is_running():
|
|
148
|
-
logger.info("Daemon is not running")
|
|
149
|
-
return True
|
|
150
|
-
|
|
151
|
-
try:
|
|
152
|
-
with open(self.pid_file) as f:
|
|
153
|
-
pid = int(f.read().strip())
|
|
154
|
-
|
|
155
|
-
logger.info(f"Stopping daemon (PID: {pid})...")
|
|
156
|
-
|
|
157
|
-
# Try graceful shutdown first
|
|
158
|
-
os.kill(pid, signal.SIGTERM)
|
|
159
|
-
|
|
160
|
-
# Wait for graceful shutdown
|
|
161
|
-
for _ in range(10):
|
|
162
|
-
if not self.is_running():
|
|
163
|
-
break
|
|
164
|
-
time.sleep(0.5)
|
|
165
|
-
|
|
166
|
-
# Force kill if still running
|
|
167
|
-
if self.is_running():
|
|
168
|
-
logger.warning("Forcing daemon shutdown...")
|
|
169
|
-
os.kill(pid, signal.SIGKILL)
|
|
170
|
-
time.sleep(1)
|
|
171
|
-
|
|
172
|
-
# Clean up files
|
|
173
|
-
self.pid_file.unlink(missing_ok=True)
|
|
174
|
-
self.socket_file.unlink(missing_ok=True)
|
|
175
|
-
|
|
176
|
-
if self.is_running():
|
|
177
|
-
logger.error("Failed to stop daemon")
|
|
178
|
-
return False
|
|
179
|
-
else:
|
|
180
|
-
logger.info("Daemon stopped successfully")
|
|
181
|
-
return True
|
|
182
|
-
|
|
183
|
-
except (ValueError, ProcessLookupError, OSError) as e:
|
|
184
|
-
logger.error(f"Error stopping daemon: {e}")
|
|
185
|
-
# Clean up stale files
|
|
186
|
-
self.pid_file.unlink(missing_ok=True)
|
|
187
|
-
self.socket_file.unlink(missing_ok=True)
|
|
188
|
-
return True
|
|
189
|
-
|
|
190
|
-
def restart(self) -> bool:
|
|
191
|
-
"""Restart the daemon process."""
|
|
192
|
-
logger.info("Restarting daemon...")
|
|
193
|
-
self.stop()
|
|
194
|
-
time.sleep(1)
|
|
195
|
-
return self.start()
|
|
196
|
-
|
|
197
|
-
def _update_claude_config(self) -> bool:
|
|
198
|
-
"""Update Claude Code configuration with daemon socket."""
|
|
199
|
-
try:
|
|
200
|
-
# Create directory if it doesn't exist
|
|
201
|
-
self.claude_config.parent.mkdir(parents=True, exist_ok=True)
|
|
202
|
-
|
|
203
|
-
# Read existing config or create new one
|
|
204
|
-
if self.claude_config.exists():
|
|
205
|
-
with open(self.claude_config) as f:
|
|
206
|
-
config = json.load(f)
|
|
207
|
-
else:
|
|
208
|
-
config = {}
|
|
209
|
-
|
|
210
|
-
# Ensure mcpServers section exists
|
|
211
|
-
if "mcpServers" not in config:
|
|
212
|
-
config["mcpServers"] = {}
|
|
213
|
-
|
|
214
|
-
# Update our server configuration
|
|
215
|
-
config["mcpServers"]["kicad-sch-api"] = {
|
|
216
|
-
"command": sys.executable,
|
|
217
|
-
"args": ["-m", "kicad_sch_api.mcp.server"],
|
|
218
|
-
"env": {}
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
# Write configuration back
|
|
222
|
-
with open(self.claude_config, 'w') as f:
|
|
223
|
-
json.dump(config, f, indent=2)
|
|
224
|
-
|
|
225
|
-
logger.info(f"Updated Claude configuration: {self.claude_config}")
|
|
226
|
-
return True
|
|
227
|
-
|
|
228
|
-
except Exception as e:
|
|
229
|
-
logger.error(f"Failed to update Claude configuration: {e}")
|
|
230
|
-
return False
|
|
231
|
-
|
|
232
|
-
def show_logs(self, lines: int = 20) -> None:
|
|
233
|
-
"""Show recent daemon log entries."""
|
|
234
|
-
if not self.log_file.exists():
|
|
235
|
-
print("No log file found")
|
|
236
|
-
return
|
|
237
|
-
|
|
238
|
-
try:
|
|
239
|
-
# Use tail-like functionality
|
|
240
|
-
with open(self.log_file) as f:
|
|
241
|
-
log_lines = f.readlines()
|
|
242
|
-
|
|
243
|
-
# Show last N lines
|
|
244
|
-
for line in log_lines[-lines:]:
|
|
245
|
-
print(line.rstrip())
|
|
246
|
-
|
|
247
|
-
except OSError as e:
|
|
248
|
-
logger.error(f"Error reading log file: {e}")
|
|
249
|
-
|
|
250
|
-
# CLI functions for entry points
|
|
251
|
-
def start_daemon():
|
|
252
|
-
"""Entry point for starting daemon."""
|
|
253
|
-
daemon = MCPDaemon()
|
|
254
|
-
success = daemon.start()
|
|
255
|
-
sys.exit(0 if success else 1)
|
|
256
|
-
|
|
257
|
-
def stop_daemon():
|
|
258
|
-
"""Entry point for stopping daemon."""
|
|
259
|
-
daemon = MCPDaemon()
|
|
260
|
-
success = daemon.stop()
|
|
261
|
-
sys.exit(0 if success else 1)
|
|
262
|
-
|
|
263
|
-
def restart_daemon():
|
|
264
|
-
"""Entry point for restarting daemon."""
|
|
265
|
-
daemon = MCPDaemon()
|
|
266
|
-
success = daemon.restart()
|
|
267
|
-
sys.exit(0 if success else 1)
|
|
268
|
-
|
|
269
|
-
def status_daemon():
|
|
270
|
-
"""Entry point for daemon status."""
|
|
271
|
-
daemon = MCPDaemon()
|
|
272
|
-
status = daemon.get_status()
|
|
273
|
-
|
|
274
|
-
print(f"🚀 KiCAD Schematic MCP Server Status")
|
|
275
|
-
print("=" * 40)
|
|
276
|
-
print(f"Running: {'✅ Yes' if status['running'] else '❌ No'}")
|
|
277
|
-
|
|
278
|
-
if status["pid"]:
|
|
279
|
-
print(f"PID: {status['pid']}")
|
|
280
|
-
|
|
281
|
-
print(f"Log file: {status['log_file']}")
|
|
282
|
-
print(f"Claude configured: {'✅ Yes' if status['claude_configured'] else '❌ No'}")
|
|
283
|
-
|
|
284
|
-
if not status["claude_configured"]:
|
|
285
|
-
print("\n⚠️ Claude Code not configured. Run with --configure-claude to fix.")
|
|
286
|
-
|
|
287
|
-
if status["running"]:
|
|
288
|
-
print("\n📜 Recent logs:")
|
|
289
|
-
daemon.show_logs(10)
|
|
290
|
-
|
|
291
|
-
def main():
|
|
292
|
-
"""Main daemon management interface."""
|
|
293
|
-
import argparse
|
|
294
|
-
|
|
295
|
-
parser = argparse.ArgumentParser(description="KiCAD Schematic MCP Daemon Manager")
|
|
296
|
-
parser.add_argument("--start", action="store_true", help="Start the daemon")
|
|
297
|
-
parser.add_argument("--stop", action="store_true", help="Stop the daemon")
|
|
298
|
-
parser.add_argument("--restart", action="store_true", help="Restart the daemon")
|
|
299
|
-
parser.add_argument("--status", action="store_true", help="Show daemon status")
|
|
300
|
-
parser.add_argument("--logs", type=int, default=20, help="Show recent log lines")
|
|
301
|
-
|
|
302
|
-
args = parser.parse_args()
|
|
303
|
-
|
|
304
|
-
daemon = MCPDaemon()
|
|
305
|
-
|
|
306
|
-
if args.start:
|
|
307
|
-
success = daemon.start()
|
|
308
|
-
sys.exit(0 if success else 1)
|
|
309
|
-
elif args.stop:
|
|
310
|
-
success = daemon.stop()
|
|
311
|
-
sys.exit(0 if success else 1)
|
|
312
|
-
elif args.restart:
|
|
313
|
-
success = daemon.restart()
|
|
314
|
-
sys.exit(0 if success else 1)
|
|
315
|
-
elif args.status:
|
|
316
|
-
status_daemon()
|
|
317
|
-
else:
|
|
318
|
-
# No arguments, show status
|
|
319
|
-
status_daemon()
|
|
320
|
-
|
|
321
|
-
if __name__ == "__main__":
|
|
322
|
-
main()
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
[console_scripts]
|
|
2
|
-
kicad-sch-api = kicad_sch_api.cli:main
|
|
3
|
-
kicad-sch-daemon = kicad_sch_api.daemon:main
|
|
4
|
-
kicad-sch-daemon-start = kicad_sch_api.daemon:start_daemon
|
|
5
|
-
kicad-sch-daemon-status = kicad_sch_api.daemon:status_daemon
|
|
6
|
-
kicad-sch-daemon-stop = kicad_sch_api.daemon:stop_daemon
|
|
7
|
-
kicad-sch-mcp = kicad_sch_api.mcp.server:main
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{kicad_sch_api-0.1.5 → kicad_sch_api-0.1.7}/tests/reference_tests/reference_kicad_projects/README.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|