nimcode 0.1.18__tar.gz → 0.1.21__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.
- {nimcode-0.1.18 → nimcode-0.1.21}/PKG-INFO +1 -1
- {nimcode-0.1.18 → nimcode-0.1.21}/setup.py +1 -1
- {nimcode-0.1.18 → nimcode-0.1.21}/src/nimcode/cli.py +12 -8
- {nimcode-0.1.18 → nimcode-0.1.21}/src/nimcode/config.py +1 -14
- {nimcode-0.1.18 → nimcode-0.1.21}/src/nimcode.egg-info/PKG-INFO +1 -1
- {nimcode-0.1.18 → nimcode-0.1.21}/tests/test_cli.py +16 -12
- {nimcode-0.1.18 → nimcode-0.1.21}/README.md +0 -0
- {nimcode-0.1.18 → nimcode-0.1.21}/setup.cfg +0 -0
- {nimcode-0.1.18 → nimcode-0.1.21}/src/nimcode/__init__.py +0 -0
- {nimcode-0.1.18 → nimcode-0.1.21}/src/nimcode/agent.py +0 -0
- {nimcode-0.1.18 → nimcode-0.1.21}/src/nimcode/analytics.py +0 -0
- {nimcode-0.1.18 → nimcode-0.1.21}/src/nimcode/lenient_parser.py +0 -0
- {nimcode-0.1.18 → nimcode-0.1.21}/src/nimcode/mcp_client.py +0 -0
- {nimcode-0.1.18 → nimcode-0.1.21}/src/nimcode/memory.py +0 -0
- {nimcode-0.1.18 → nimcode-0.1.21}/src/nimcode/nim_client.py +0 -0
- {nimcode-0.1.18 → nimcode-0.1.21}/src/nimcode/permissions.py +0 -0
- {nimcode-0.1.18 → nimcode-0.1.21}/src/nimcode/plugin_manager.py +0 -0
- {nimcode-0.1.18 → nimcode-0.1.21}/src/nimcode/repl.py +0 -0
- {nimcode-0.1.18 → nimcode-0.1.21}/src/nimcode/repo_map.py +0 -0
- {nimcode-0.1.18 → nimcode-0.1.21}/src/nimcode/secret_scanner.py +0 -0
- {nimcode-0.1.18 → nimcode-0.1.21}/src/nimcode/stdio_server.py +0 -0
- {nimcode-0.1.18 → nimcode-0.1.21}/src/nimcode/swarm.py +0 -0
- {nimcode-0.1.18 → nimcode-0.1.21}/src/nimcode/tools.py +0 -0
- {nimcode-0.1.18 → nimcode-0.1.21}/src/nimcode/updater.py +0 -0
- {nimcode-0.1.18 → nimcode-0.1.21}/src/nimcode/watcher.py +0 -0
- {nimcode-0.1.18 → nimcode-0.1.21}/src/nimcode.egg-info/SOURCES.txt +0 -0
- {nimcode-0.1.18 → nimcode-0.1.21}/src/nimcode.egg-info/dependency_links.txt +0 -0
- {nimcode-0.1.18 → nimcode-0.1.21}/src/nimcode.egg-info/entry_points.txt +0 -0
- {nimcode-0.1.18 → nimcode-0.1.21}/src/nimcode.egg-info/requires.txt +0 -0
- {nimcode-0.1.18 → nimcode-0.1.21}/src/nimcode.egg-info/top_level.txt +0 -0
- {nimcode-0.1.18 → nimcode-0.1.21}/tests/test_agent.py +0 -0
- {nimcode-0.1.18 → nimcode-0.1.21}/tests/test_analytics.py +0 -0
- {nimcode-0.1.18 → nimcode-0.1.21}/tests/test_config.py +0 -0
- {nimcode-0.1.18 → nimcode-0.1.21}/tests/test_lenient_parser.py +0 -0
- {nimcode-0.1.18 → nimcode-0.1.21}/tests/test_mcp_client.py +0 -0
- {nimcode-0.1.18 → nimcode-0.1.21}/tests/test_memory.py +0 -0
- {nimcode-0.1.18 → nimcode-0.1.21}/tests/test_nim_client.py +0 -0
- {nimcode-0.1.18 → nimcode-0.1.21}/tests/test_nimcoderules.py +0 -0
- {nimcode-0.1.18 → nimcode-0.1.21}/tests/test_permissions.py +0 -0
- {nimcode-0.1.18 → nimcode-0.1.21}/tests/test_plugin_manager.py +0 -0
- {nimcode-0.1.18 → nimcode-0.1.21}/tests/test_repl.py +0 -0
- {nimcode-0.1.18 → nimcode-0.1.21}/tests/test_repl_extra.py +0 -0
- {nimcode-0.1.18 → nimcode-0.1.21}/tests/test_repl_trust.py +0 -0
- {nimcode-0.1.18 → nimcode-0.1.21}/tests/test_repo_map.py +0 -0
- {nimcode-0.1.18 → nimcode-0.1.21}/tests/test_secret_scanner.py +0 -0
- {nimcode-0.1.18 → nimcode-0.1.21}/tests/test_tools.py +0 -0
- {nimcode-0.1.18 → nimcode-0.1.21}/tests/test_updater.py +0 -0
|
@@ -14,15 +14,20 @@ def run_login():
|
|
|
14
14
|
console.print("Get your API key from [bold underline blue]https://build.nvidia.com/[/bold underline blue]")
|
|
15
15
|
|
|
16
16
|
import getpass
|
|
17
|
-
import
|
|
17
|
+
from .config import save_global_setting
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
try:
|
|
20
|
+
api_key = getpass.getpass("Enter your NVIDIA NIM API Key: ")
|
|
21
|
+
except (EOFError, Exception):
|
|
22
|
+
console.print("[red]Could not prompt for API key. Please set NIM_API_KEY environment variable or run 'nimcode login' in a regular terminal.[/red]")
|
|
23
|
+
sys.exit(1)
|
|
24
|
+
|
|
20
25
|
if not api_key.strip():
|
|
21
26
|
console.print("[red]API Key cannot be empty.[/red]")
|
|
22
27
|
return
|
|
23
28
|
|
|
24
|
-
|
|
25
|
-
console.print("[green][OK] API Key saved securely to
|
|
29
|
+
save_global_setting("api_key", api_key.strip())
|
|
30
|
+
console.print("[green][OK] API Key saved securely to settings[/green]")
|
|
26
31
|
|
|
27
32
|
def run_doctor():
|
|
28
33
|
console.print("[bold cyan]NimCode Doctor[/bold cyan] - Diagnostics")
|
|
@@ -69,7 +74,7 @@ def main():
|
|
|
69
74
|
elif sys.argv[1] == "install-hook":
|
|
70
75
|
install_hook()
|
|
71
76
|
return
|
|
72
|
-
elif sys.argv[1] == "login":
|
|
77
|
+
elif sys.argv[1] == "login" or sys.argv[1] == "/login":
|
|
73
78
|
run_login()
|
|
74
79
|
return
|
|
75
80
|
|
|
@@ -86,13 +91,12 @@ def main():
|
|
|
86
91
|
|
|
87
92
|
settings = load_settings()
|
|
88
93
|
|
|
89
|
-
|
|
90
|
-
final_key = args.api_key or os.environ.get("NIM_API_KEY") or keyring.get_password("nimcode", "api_key") or settings.get("api_key")
|
|
94
|
+
final_key = args.api_key or os.environ.get("NIM_API_KEY") or settings.get("api_key")
|
|
91
95
|
if not final_key:
|
|
92
96
|
console.print("[yellow]No API Key found. Let's get you set up![/yellow]")
|
|
93
97
|
run_login()
|
|
94
98
|
settings = load_settings()
|
|
95
|
-
final_key =
|
|
99
|
+
final_key = settings.get("api_key")
|
|
96
100
|
if not final_key:
|
|
97
101
|
console.print("[bold red]API Key is required to use NimCode. Exiting.[/bold red]")
|
|
98
102
|
sys.exit(1)
|
|
@@ -22,20 +22,7 @@ def load_settings() -> Dict[str, Any]:
|
|
|
22
22
|
except Exception as e:
|
|
23
23
|
logger.error(f"Failed to load global settings: {e}")
|
|
24
24
|
|
|
25
|
-
#
|
|
26
|
-
if "api_key" in settings:
|
|
27
|
-
import keyring
|
|
28
|
-
try:
|
|
29
|
-
if not keyring.get_password("nimcode", "api_key"):
|
|
30
|
-
keyring.set_password("nimcode", "api_key", settings["api_key"])
|
|
31
|
-
|
|
32
|
-
# Remove from file
|
|
33
|
-
del settings["api_key"]
|
|
34
|
-
with open(global_path, "w", encoding="utf-8") as f:
|
|
35
|
-
json.dump(settings, f, indent=4)
|
|
36
|
-
except Exception:
|
|
37
|
-
pass
|
|
38
|
-
|
|
25
|
+
# Keyring caused 30-second hangs on Windows, so we no longer scrub api_key from settings.
|
|
39
26
|
# Local settings
|
|
40
27
|
local_path = os.path.join(os.getcwd(), ".nimcode", "settings.json")
|
|
41
28
|
if os.path.exists(local_path):
|
|
@@ -6,10 +6,10 @@ from nimcode.cli import main, run_login, run_doctor, install_hook
|
|
|
6
6
|
|
|
7
7
|
def test_run_login():
|
|
8
8
|
with patch("getpass.getpass", return_value="my_key"):
|
|
9
|
-
with patch("
|
|
9
|
+
with patch("nimcode.config.save_global_setting") as mock_save:
|
|
10
10
|
with patch("nimcode.cli.console.print") as mock_print:
|
|
11
11
|
run_login()
|
|
12
|
-
mock_save.assert_called_with("
|
|
12
|
+
mock_save.assert_called_with("api_key", "my_key")
|
|
13
13
|
|
|
14
14
|
def test_run_login_empty():
|
|
15
15
|
with patch("getpass.getpass", return_value=" "):
|
|
@@ -67,10 +67,11 @@ def test_main_install_hook():
|
|
|
67
67
|
mock_hook.assert_called_once()
|
|
68
68
|
|
|
69
69
|
def test_main_login():
|
|
70
|
-
with patch("sys.argv", ["nimcode", "login"]):
|
|
70
|
+
with patch("sys.argv", ["nimcode", "/login"]):
|
|
71
71
|
with patch("nimcode.cli.run_login") as mock_log:
|
|
72
|
-
|
|
73
|
-
|
|
72
|
+
with patch("sys.exit"):
|
|
73
|
+
main()
|
|
74
|
+
mock_log.assert_called_once()
|
|
74
75
|
|
|
75
76
|
def test_main_no_key():
|
|
76
77
|
with patch("sys.argv", ["nimcode", "my prompt"]):
|
|
@@ -79,7 +80,7 @@ def test_main_no_key():
|
|
|
79
80
|
with patch("os.environ.get", side_effect=lambda k, d=None: None if k == "NIM_API_KEY" else real_env_get(k, d)):
|
|
80
81
|
with patch("nimcode.cli.run_login"):
|
|
81
82
|
with patch("sys.stdin.isatty", return_value=True):
|
|
82
|
-
with patch("
|
|
83
|
+
with patch("builtins.input", side_effect=EOFError):
|
|
83
84
|
with pytest.raises(SystemExit):
|
|
84
85
|
main()
|
|
85
86
|
|
|
@@ -91,8 +92,9 @@ def test_main_with_key():
|
|
|
91
92
|
mock_agent_class.return_value = mock_agent
|
|
92
93
|
with patch("nimcode.cli.asyncio.run") as mock_run:
|
|
93
94
|
with patch("sys.stdin.isatty", return_value=True):
|
|
94
|
-
with patch("
|
|
95
|
-
with patch("
|
|
95
|
+
with patch("rich.prompt.Prompt.ask", return_value="1"):
|
|
96
|
+
with patch("nimcode.nim_client.NimClient") as mock_client:
|
|
97
|
+
mock_client.return_value.get_available_models.return_value = []
|
|
96
98
|
main()
|
|
97
99
|
assert mock_run.called
|
|
98
100
|
|
|
@@ -103,8 +105,9 @@ def test_main_piped_input():
|
|
|
103
105
|
with patch("sys.stdin.isatty", return_value=False):
|
|
104
106
|
with patch("sys.stdin.read", return_value="piped"):
|
|
105
107
|
with patch("nimcode.cli.asyncio.run") as mock_run:
|
|
106
|
-
with patch("
|
|
107
|
-
with patch("
|
|
108
|
+
with patch("rich.prompt.Prompt.ask", return_value="1"):
|
|
109
|
+
with patch("nimcode.nim_client.NimClient") as mock_client:
|
|
110
|
+
mock_client.return_value.get_available_models.return_value = []
|
|
108
111
|
main()
|
|
109
112
|
assert mock_run.called
|
|
110
113
|
|
|
@@ -114,7 +117,8 @@ def test_main_repl():
|
|
|
114
117
|
with patch("nimcode.agent.Agent") as mock_agent_class:
|
|
115
118
|
with patch("sys.stdin.isatty", return_value=True):
|
|
116
119
|
with patch("nimcode.cli.asyncio.run") as mock_run:
|
|
117
|
-
with patch("
|
|
118
|
-
with patch("
|
|
120
|
+
with patch("rich.prompt.Prompt.ask", return_value="1"):
|
|
121
|
+
with patch("nimcode.nim_client.NimClient") as mock_client:
|
|
122
|
+
mock_client.return_value.get_available_models.return_value = []
|
|
119
123
|
main()
|
|
120
124
|
assert mock_run.called
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|