kicad-sch-api 0.1.3__tar.gz → 0.1.5__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.3 → kicad_sch_api-0.1.5}/PKG-INFO +1 -1
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/kicad_sch_api/cli.py +208 -8
- kicad_sch_api-0.1.5/kicad_sch_api/daemon.py +322 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/kicad_sch_api/mcp/server.py +113 -1
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/kicad_sch_api.egg-info/PKG-INFO +1 -1
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/kicad_sch_api.egg-info/SOURCES.txt +1 -0
- kicad_sch_api-0.1.5/kicad_sch_api.egg-info/entry_points.txt +7 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/pyproject.toml +7 -1
- kicad_sch_api-0.1.3/kicad_sch_api.egg-info/entry_points.txt +0 -3
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/.claude/commands/dev/dead-code-analysis.md +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/.claude/commands/dev/publish-pypi.md +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/.claude/commands/dev/review-implementation.md +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/.claude/commands/dev/run-tests.md +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/.claude/commands/dev/update-and-commit.md +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/.claude/commands/dev/update-memory-bank.md +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/.claude/commands/test/run-reference-tests.md +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/LICENSE +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/MANIFEST.in +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/README.md +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/examples/advanced_usage.py +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/examples/basic_usage.py +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/examples/mcp_basic_example.py +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/examples/mcp_integration.py +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/kicad_sch_api/__init__.py +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/kicad_sch_api/core/__init__.py +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/kicad_sch_api/core/components.py +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/kicad_sch_api/core/formatter.py +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/kicad_sch_api/core/ic_manager.py +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/kicad_sch_api/core/junctions.py +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/kicad_sch_api/core/parser.py +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/kicad_sch_api/core/schematic.py +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/kicad_sch_api/core/types.py +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/kicad_sch_api/core/wires.py +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/kicad_sch_api/discovery/__init__.py +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/kicad_sch_api/discovery/search_index.py +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/kicad_sch_api/library/__init__.py +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/kicad_sch_api/library/cache.py +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/kicad_sch_api/mcp/__init__.py +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/kicad_sch_api/py.typed +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/kicad_sch_api/utils/__init__.py +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/kicad_sch_api/utils/validation.py +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/kicad_sch_api.egg-info/dependency_links.txt +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/kicad_sch_api.egg-info/requires.txt +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/kicad_sch_api.egg-info/top_level.txt +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/setup.cfg +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/tests/reference_tests/reference_kicad_projects/README.md +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/tests/reference_tests/reference_kicad_projects/blank_schematic/blank_schematic.kicad_pro +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/tests/reference_tests/reference_kicad_projects/blank_schematic/blank_schematic.kicad_sch +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/tests/reference_tests/reference_kicad_projects/multi_unit_7400/multi_unit_7400.kicad_pro +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/tests/reference_tests/reference_kicad_projects/multi_unit_7400/multi_unit_7400.kicad_sch +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/tests/reference_tests/reference_kicad_projects/power_symbols/power_symbols.kicad_pro +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/tests/reference_tests/reference_kicad_projects/power_symbols/power_symbols.kicad_sch +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/tests/reference_tests/reference_kicad_projects/resistor_divider/resistor_divider.kicad_pro +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/tests/reference_tests/reference_kicad_projects/resistor_divider/resistor_divider.kicad_sch +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/tests/reference_tests/reference_kicad_projects/sch_title/sch_title.kicad_pro +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/tests/reference_tests/reference_kicad_projects/sch_title/sch_title.kicad_sch +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/tests/reference_tests/reference_kicad_projects/single_extended_component/single_extended_component.kicad_pro +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/tests/reference_tests/reference_kicad_projects/single_extended_component/single_extended_component.kicad_sch +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/tests/reference_tests/reference_kicad_projects/single_hierarchical_sheet/single_hierarchical_sheet.kicad_pro +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/tests/reference_tests/reference_kicad_projects/single_hierarchical_sheet/single_hierarchical_sheet.kicad_sch +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/tests/reference_tests/reference_kicad_projects/single_hierarchical_sheet/subcircuit1.kicad_sch +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/tests/reference_tests/reference_kicad_projects/single_label/single_label.kicad_pro +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/tests/reference_tests/reference_kicad_projects/single_label/single_label.kicad_sch +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/tests/reference_tests/reference_kicad_projects/single_label_hierarchical/single_label_hierarchical.kicad_pro +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/tests/reference_tests/reference_kicad_projects/single_label_hierarchical/single_label_hierarchical.kicad_sch +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/tests/reference_tests/reference_kicad_projects/single_resistor/single_resistor.kicad_pro +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/tests/reference_tests/reference_kicad_projects/single_resistor/single_resistor.kicad_sch +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/tests/reference_tests/reference_kicad_projects/single_text/single_text.kicad_pro +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/tests/reference_tests/reference_kicad_projects/single_text/single_text.kicad_sch +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/tests/reference_tests/reference_kicad_projects/single_text_box/single_text_box.kicad_pro +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/tests/reference_tests/reference_kicad_projects/single_text_box/single_text_box.kicad_sch +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/tests/reference_tests/reference_kicad_projects/single_wire/single_wire.kicad_pro +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/tests/reference_tests/reference_kicad_projects/single_wire/single_wire.kicad_sch +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/tests/reference_tests/reference_kicad_projects/two_resistors/two_resistors.kicad_pro +0 -0
- {kicad_sch_api-0.1.3 → kicad_sch_api-0.1.5}/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.5
|
|
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>
|
|
@@ -279,6 +279,133 @@ def show_logs():
|
|
|
279
279
|
else:
|
|
280
280
|
print(" ~/.local/share/Claude/logs/mcp-server-kicad-sch-api.log")
|
|
281
281
|
|
|
282
|
+
def setup_everything() -> bool:
|
|
283
|
+
"""One-command setup that does everything automatically."""
|
|
284
|
+
print("🚀 KiCAD Schematic API - Complete Setup")
|
|
285
|
+
print("=" * 45)
|
|
286
|
+
print()
|
|
287
|
+
|
|
288
|
+
success = True
|
|
289
|
+
|
|
290
|
+
# 1. Test installation
|
|
291
|
+
print("Step 1/4: Testing installation...")
|
|
292
|
+
if not test_installation():
|
|
293
|
+
print("❌ Installation test failed. Please reinstall the package.")
|
|
294
|
+
return False
|
|
295
|
+
print()
|
|
296
|
+
|
|
297
|
+
# 2. Initialize cache
|
|
298
|
+
print("Step 2/4: Initializing component cache...")
|
|
299
|
+
if not init_cache():
|
|
300
|
+
print("⚠️ Cache initialization failed, but continuing...")
|
|
301
|
+
print()
|
|
302
|
+
|
|
303
|
+
# 3. Setup Claude Code
|
|
304
|
+
print("Step 3/4: Configuring Claude Code...")
|
|
305
|
+
if not setup_claude_code():
|
|
306
|
+
print("⚠️ Claude Code setup failed, but continuing...")
|
|
307
|
+
print()
|
|
308
|
+
|
|
309
|
+
# 4. Create demo
|
|
310
|
+
print("Step 4/4: Creating demo schematic...")
|
|
311
|
+
if not create_demo():
|
|
312
|
+
print("⚠️ Demo creation failed, but setup is complete")
|
|
313
|
+
print()
|
|
314
|
+
|
|
315
|
+
# Final status
|
|
316
|
+
print("🎉 Setup Complete!")
|
|
317
|
+
print()
|
|
318
|
+
print("Next steps:")
|
|
319
|
+
print("1. Restart Claude Code")
|
|
320
|
+
print("2. Try: 'Create a voltage divider with two 10kΩ resistors'")
|
|
321
|
+
print("3. Open demo_circuit.kicad_sch in KiCAD to see the example")
|
|
322
|
+
print()
|
|
323
|
+
|
|
324
|
+
return True
|
|
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
|
|
340
|
+
print()
|
|
341
|
+
|
|
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
|
+
return True
|
|
408
|
+
|
|
282
409
|
def main():
|
|
283
410
|
"""Main CLI entry point."""
|
|
284
411
|
parser = argparse.ArgumentParser(
|
|
@@ -286,19 +413,39 @@ def main():
|
|
|
286
413
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
287
414
|
epilog="""
|
|
288
415
|
Examples:
|
|
289
|
-
kicad-sch-api --setup
|
|
290
|
-
kicad-sch-api --
|
|
291
|
-
kicad-sch-api --
|
|
292
|
-
kicad-sch-api --
|
|
416
|
+
kicad-sch-api --setup # Complete one-command setup (RECOMMENDED)
|
|
417
|
+
kicad-sch-api --setup-daemon # Setup with daemon-style MCP server
|
|
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
|
|
421
|
+
kicad-sch-api --test # Test installation
|
|
422
|
+
kicad-sch-api --demo # Create demo schematic
|
|
293
423
|
"""
|
|
294
424
|
)
|
|
295
425
|
|
|
426
|
+
# Main setup options
|
|
427
|
+
parser.add_argument('--setup', action='store_true',
|
|
428
|
+
help='Complete one-command setup (RECOMMENDED for new users)')
|
|
429
|
+
parser.add_argument('--setup-daemon', action='store_true',
|
|
430
|
+
help='Setup with daemon-style MCP server (RECOMMENDED)')
|
|
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
|
|
296
443
|
parser.add_argument('--setup-claude-code', action='store_true',
|
|
297
|
-
help='Configure Claude Code MCP settings
|
|
444
|
+
help='Configure Claude Code MCP settings only')
|
|
298
445
|
parser.add_argument('--test', action='store_true',
|
|
299
446
|
help='Test that the installation is working')
|
|
300
447
|
parser.add_argument('--status', action='store_true',
|
|
301
|
-
help='Show installation and configuration status')
|
|
448
|
+
help='Show detailed installation and configuration status')
|
|
302
449
|
parser.add_argument('--demo', action='store_true',
|
|
303
450
|
help='Create a demo schematic')
|
|
304
451
|
parser.add_argument('--init-cache', action='store_true',
|
|
@@ -310,14 +457,67 @@ Examples:
|
|
|
310
457
|
|
|
311
458
|
args = parser.parse_args()
|
|
312
459
|
|
|
313
|
-
# If no arguments provided,
|
|
460
|
+
# If no arguments provided, suggest the daemon setup
|
|
314
461
|
if not any(vars(args).values()):
|
|
315
|
-
|
|
462
|
+
print("🚀 KiCAD Schematic API - Command Line Interface")
|
|
463
|
+
print()
|
|
464
|
+
print("🌟 RECOMMENDED: Setup with daemon-style MCP server:")
|
|
465
|
+
print(" kicad-sch-api --setup-daemon")
|
|
466
|
+
print()
|
|
467
|
+
print("📖 For legacy setup:")
|
|
468
|
+
print(" kicad-sch-api --setup")
|
|
469
|
+
print()
|
|
470
|
+
print("🆘 For help with all options:")
|
|
471
|
+
print(" kicad-sch-api --help")
|
|
472
|
+
return
|
|
473
|
+
|
|
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
|
+
|
|
316
511
|
return
|
|
317
512
|
|
|
318
513
|
# Execute requested actions
|
|
319
514
|
success = True
|
|
320
515
|
|
|
516
|
+
if args.setup_daemon:
|
|
517
|
+
success &= setup_daemon()
|
|
518
|
+
elif args.setup:
|
|
519
|
+
success &= setup_everything()
|
|
520
|
+
|
|
321
521
|
if args.setup_claude_code:
|
|
322
522
|
success &= setup_claude_code()
|
|
323
523
|
|
|
@@ -0,0 +1,322 @@
|
|
|
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()
|
|
@@ -1459,21 +1459,32 @@ This hierarchical approach makes complex designs manageable and promotes reusabl
|
|
|
1459
1459
|
def main():
|
|
1460
1460
|
"""Run the MCP server."""
|
|
1461
1461
|
import argparse
|
|
1462
|
+
import os
|
|
1463
|
+
import signal
|
|
1464
|
+
import atexit
|
|
1465
|
+
import time
|
|
1462
1466
|
|
|
1463
1467
|
parser = argparse.ArgumentParser(description="KiCAD Schematic MCP Server")
|
|
1464
1468
|
parser.add_argument('--test', action='store_true', help='Run quick test and exit')
|
|
1465
1469
|
parser.add_argument('--debug', action='store_true', help='Enable debug logging')
|
|
1466
1470
|
parser.add_argument('--status', action='store_true', help='Show server status and exit')
|
|
1467
1471
|
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')
|
|
1468
1475
|
|
|
1469
1476
|
args = parser.parse_args()
|
|
1470
1477
|
|
|
1478
|
+
# Handle daemon mode
|
|
1479
|
+
if args.daemon:
|
|
1480
|
+
return run_daemon(args.log_file, args.pid_file, args.debug)
|
|
1481
|
+
|
|
1471
1482
|
if args.debug:
|
|
1472
1483
|
logging.getLogger().setLevel(logging.DEBUG)
|
|
1473
1484
|
logger.debug("Debug logging enabled")
|
|
1474
1485
|
|
|
1475
1486
|
if args.version:
|
|
1476
|
-
print("KiCAD Schematic MCP Server v0.1.
|
|
1487
|
+
print("KiCAD Schematic MCP Server v0.1.5")
|
|
1477
1488
|
return
|
|
1478
1489
|
|
|
1479
1490
|
if args.status:
|
|
@@ -1505,5 +1516,106 @@ def main():
|
|
|
1505
1516
|
logger.error(f"Server error: {e}")
|
|
1506
1517
|
sys.exit(1)
|
|
1507
1518
|
|
|
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
|
+
|
|
1508
1620
|
if __name__ == "__main__":
|
|
1509
1621
|
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.5
|
|
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>
|
|
@@ -0,0 +1,7 @@
|
|
|
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
|
|
@@ -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.5"
|
|
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,6 +43,12 @@ 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
|
+
|
|
46
52
|
[project.optional-dependencies]
|
|
47
53
|
dev = [
|
|
48
54
|
"pytest>=7.0.0",
|
|
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.3 → kicad_sch_api-0.1.5}/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
|