nff 0.2.1__tar.gz → 0.2.2__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.
- {nff-0.2.1 → nff-0.2.2}/PKG-INFO +1 -1
- {nff-0.2.1 → nff-0.2.2}/nff/cli.py +2 -0
- nff-0.2.2/nff/commands/clean.py +117 -0
- {nff-0.2.1 → nff-0.2.2}/nff/commands/init.py +12 -1
- {nff-0.2.1 → nff-0.2.2}/nff.egg-info/PKG-INFO +1 -1
- {nff-0.2.1 → nff-0.2.2}/nff.egg-info/SOURCES.txt +1 -0
- {nff-0.2.1 → nff-0.2.2}/pyproject.toml +1 -1
- {nff-0.2.1 → nff-0.2.2}/LICENSE +0 -0
- {nff-0.2.1 → nff-0.2.2}/README.md +0 -0
- {nff-0.2.1 → nff-0.2.2}/nff/__init__.py +0 -0
- {nff-0.2.1 → nff-0.2.2}/nff/commands/__init__.py +0 -0
- {nff-0.2.1 → nff-0.2.2}/nff/commands/doctor.py +0 -0
- {nff-0.2.1 → nff-0.2.2}/nff/commands/flash.py +0 -0
- {nff-0.2.1 → nff-0.2.2}/nff/commands/monitor.py +0 -0
- {nff-0.2.1 → nff-0.2.2}/nff/commands/wokwi.py +0 -0
- {nff-0.2.1 → nff-0.2.2}/nff/config.py +0 -0
- {nff-0.2.1 → nff-0.2.2}/nff/mcp_server.py +0 -0
- {nff-0.2.1 → nff-0.2.2}/nff/tools/__init__.py +0 -0
- {nff-0.2.1 → nff-0.2.2}/nff/tools/boards.py +0 -0
- {nff-0.2.1 → nff-0.2.2}/nff/tools/installer.py +0 -0
- {nff-0.2.1 → nff-0.2.2}/nff/tools/serial.py +0 -0
- {nff-0.2.1 → nff-0.2.2}/nff/tools/toolchain.py +0 -0
- {nff-0.2.1 → nff-0.2.2}/nff/tools/wokwi.py +0 -0
- {nff-0.2.1 → nff-0.2.2}/nff/tools/wokwi_installer.py +0 -0
- {nff-0.2.1 → nff-0.2.2}/nff.egg-info/dependency_links.txt +0 -0
- {nff-0.2.1 → nff-0.2.2}/nff.egg-info/entry_points.txt +0 -0
- {nff-0.2.1 → nff-0.2.2}/nff.egg-info/requires.txt +0 -0
- {nff-0.2.1 → nff-0.2.2}/nff.egg-info/top_level.txt +0 -0
- {nff-0.2.1 → nff-0.2.2}/setup.cfg +0 -0
- {nff-0.2.1 → nff-0.2.2}/tests/test_boards.py +0 -0
- {nff-0.2.1 → nff-0.2.2}/tests/test_config.py +0 -0
- {nff-0.2.1 → nff-0.2.2}/tests/test_doctor.py +0 -0
- {nff-0.2.1 → nff-0.2.2}/tests/test_mcp.py +0 -0
- {nff-0.2.1 → nff-0.2.2}/tests/test_serial.py +0 -0
- {nff-0.2.1 → nff-0.2.2}/tests/test_toolchain.py +0 -0
- {nff-0.2.1 → nff-0.2.2}/tests/test_wokwi.py +0 -0
{nff-0.2.1 → nff-0.2.2}/PKG-INFO
RENAMED
|
@@ -38,12 +38,14 @@ from nff.commands.flash import flash # noqa: E402
|
|
|
38
38
|
from nff.commands.monitor import monitor # noqa: E402
|
|
39
39
|
from nff.commands.doctor import doctor # noqa: E402
|
|
40
40
|
from nff.commands.wokwi import wokwi # noqa: E402
|
|
41
|
+
from nff.commands.clean import clean # noqa: E402
|
|
41
42
|
|
|
42
43
|
cli.add_command(init)
|
|
43
44
|
cli.add_command(flash)
|
|
44
45
|
cli.add_command(monitor)
|
|
45
46
|
cli.add_command(doctor)
|
|
46
47
|
cli.add_command(wokwi)
|
|
48
|
+
cli.add_command(clean)
|
|
47
49
|
|
|
48
50
|
|
|
49
51
|
@cli.command("install-deps")
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"""nff clean — remove the MCP server registration and optionally the nff config."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import shutil
|
|
7
|
+
import subprocess
|
|
8
|
+
import sys
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
import click
|
|
12
|
+
from rich.console import Console
|
|
13
|
+
|
|
14
|
+
from nff import config as cfg_module
|
|
15
|
+
|
|
16
|
+
if sys.platform == "win32" and hasattr(sys.stdout, "reconfigure"):
|
|
17
|
+
sys.stdout.reconfigure(encoding="utf-8")
|
|
18
|
+
|
|
19
|
+
console = Console(legacy_windows=False)
|
|
20
|
+
|
|
21
|
+
_CLAUDE_DESKTOP_CONFIG = Path.home() / ".claude" / "claude_desktop_config.json"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _remove_from_claude_code() -> bool:
|
|
25
|
+
"""Run `claude mcp remove nff`. Returns True on success."""
|
|
26
|
+
if not shutil.which("claude"):
|
|
27
|
+
return False
|
|
28
|
+
try:
|
|
29
|
+
result = subprocess.run(
|
|
30
|
+
["claude", "mcp", "remove", "nff"],
|
|
31
|
+
capture_output=True,
|
|
32
|
+
text=True,
|
|
33
|
+
timeout=15,
|
|
34
|
+
)
|
|
35
|
+
return result.returncode == 0
|
|
36
|
+
except (OSError, subprocess.TimeoutExpired):
|
|
37
|
+
return False
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _remove_from_claude_desktop_config() -> bool:
|
|
41
|
+
"""Remove the nff mcpServers entry from claude_desktop_config.json.
|
|
42
|
+
|
|
43
|
+
Returns True if the entry was present and removed, False if it wasn't there.
|
|
44
|
+
"""
|
|
45
|
+
if not _CLAUDE_DESKTOP_CONFIG.exists():
|
|
46
|
+
return False
|
|
47
|
+
|
|
48
|
+
raw = _CLAUDE_DESKTOP_CONFIG.read_text(encoding="utf-8")
|
|
49
|
+
if not raw.strip():
|
|
50
|
+
return False
|
|
51
|
+
|
|
52
|
+
data: dict = json.loads(raw)
|
|
53
|
+
servers: dict = data.get("mcpServers", {})
|
|
54
|
+
if "nff" not in servers:
|
|
55
|
+
return False
|
|
56
|
+
|
|
57
|
+
del servers["nff"]
|
|
58
|
+
if not servers:
|
|
59
|
+
data.pop("mcpServers", None)
|
|
60
|
+
|
|
61
|
+
_CLAUDE_DESKTOP_CONFIG.write_text(json.dumps(data, indent=2), encoding="utf-8")
|
|
62
|
+
return True
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
@click.command()
|
|
66
|
+
@click.option(
|
|
67
|
+
"--config",
|
|
68
|
+
"remove_config",
|
|
69
|
+
is_flag=True,
|
|
70
|
+
help="Also delete ~/.nff/config.json.",
|
|
71
|
+
)
|
|
72
|
+
def clean(remove_config: bool) -> None:
|
|
73
|
+
"""Remove the nff MCP server registration from Claude Code and Claude Desktop."""
|
|
74
|
+
any_removed = False
|
|
75
|
+
|
|
76
|
+
# Claude Code CLI
|
|
77
|
+
if _remove_from_claude_code():
|
|
78
|
+
console.print(
|
|
79
|
+
" [bold green]✓[/bold green] Removed from Claude Code "
|
|
80
|
+
"([bold]claude mcp remove nff[/bold])"
|
|
81
|
+
)
|
|
82
|
+
any_removed = True
|
|
83
|
+
else:
|
|
84
|
+
console.print(
|
|
85
|
+
" [dim]`claude` CLI not found or nff was not registered — skipping.[/dim]"
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
# Claude Desktop JSON config
|
|
89
|
+
try:
|
|
90
|
+
removed = _remove_from_claude_desktop_config()
|
|
91
|
+
if removed:
|
|
92
|
+
console.print(
|
|
93
|
+
f" [bold green]✓[/bold green] Removed nff entry from "
|
|
94
|
+
f"[bold]{_CLAUDE_DESKTOP_CONFIG}[/bold]"
|
|
95
|
+
)
|
|
96
|
+
any_removed = True
|
|
97
|
+
else:
|
|
98
|
+
console.print(
|
|
99
|
+
f" [dim]nff not found in {_CLAUDE_DESKTOP_CONFIG} — nothing to remove.[/dim]"
|
|
100
|
+
)
|
|
101
|
+
except (ValueError, OSError) as exc:
|
|
102
|
+
console.print(f" [yellow]⚠[/yellow] Could not update Claude Desktop config: {exc}")
|
|
103
|
+
|
|
104
|
+
# Optional: nff config file
|
|
105
|
+
if remove_config:
|
|
106
|
+
config_path = cfg_module.CONFIG_PATH
|
|
107
|
+
if config_path.exists():
|
|
108
|
+
config_path.unlink()
|
|
109
|
+
console.print(
|
|
110
|
+
f" [bold green]✓[/bold green] Deleted [bold]{config_path}[/bold]"
|
|
111
|
+
)
|
|
112
|
+
any_removed = True
|
|
113
|
+
else:
|
|
114
|
+
console.print(f" [dim]{config_path} does not exist — nothing to delete.[/dim]")
|
|
115
|
+
|
|
116
|
+
if not any_removed:
|
|
117
|
+
console.print(" Nothing to clean.")
|
|
@@ -80,13 +80,24 @@ def _pick_device(devices: list[DetectedDevice]) -> DetectedDevice:
|
|
|
80
80
|
def _register_mcp_claude_code() -> bool:
|
|
81
81
|
"""Register nff with Claude Code CLI via `claude mcp add`.
|
|
82
82
|
|
|
83
|
+
Uses the absolute path of the running nff executable so Claude Code can
|
|
84
|
+
locate it on Windows where bare-name resolution may fail.
|
|
85
|
+
|
|
83
86
|
Returns True on success, False if `claude` is not in PATH or the command fails.
|
|
84
87
|
"""
|
|
85
88
|
if not shutil.which("claude"):
|
|
86
89
|
return False
|
|
90
|
+
|
|
91
|
+
nff_exe = shutil.which("nff") or sys.executable
|
|
92
|
+
# On Windows prefer the .exe alongside the current interpreter if found
|
|
93
|
+
if sys.platform == "win32":
|
|
94
|
+
candidate = Path(sys.executable).parent / "nff.exe"
|
|
95
|
+
if candidate.exists():
|
|
96
|
+
nff_exe = str(candidate)
|
|
97
|
+
|
|
87
98
|
try:
|
|
88
99
|
result = subprocess.run(
|
|
89
|
-
["claude", "mcp", "add", "nff",
|
|
100
|
+
["claude", "mcp", "add", "nff", nff_exe, "mcp"],
|
|
90
101
|
capture_output=True,
|
|
91
102
|
text=True,
|
|
92
103
|
timeout=15,
|
{nff-0.2.1 → nff-0.2.2}/LICENSE
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
|