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.
Files changed (47) hide show
  1. {nimcode-0.1.18 → nimcode-0.1.21}/PKG-INFO +1 -1
  2. {nimcode-0.1.18 → nimcode-0.1.21}/setup.py +1 -1
  3. {nimcode-0.1.18 → nimcode-0.1.21}/src/nimcode/cli.py +12 -8
  4. {nimcode-0.1.18 → nimcode-0.1.21}/src/nimcode/config.py +1 -14
  5. {nimcode-0.1.18 → nimcode-0.1.21}/src/nimcode.egg-info/PKG-INFO +1 -1
  6. {nimcode-0.1.18 → nimcode-0.1.21}/tests/test_cli.py +16 -12
  7. {nimcode-0.1.18 → nimcode-0.1.21}/README.md +0 -0
  8. {nimcode-0.1.18 → nimcode-0.1.21}/setup.cfg +0 -0
  9. {nimcode-0.1.18 → nimcode-0.1.21}/src/nimcode/__init__.py +0 -0
  10. {nimcode-0.1.18 → nimcode-0.1.21}/src/nimcode/agent.py +0 -0
  11. {nimcode-0.1.18 → nimcode-0.1.21}/src/nimcode/analytics.py +0 -0
  12. {nimcode-0.1.18 → nimcode-0.1.21}/src/nimcode/lenient_parser.py +0 -0
  13. {nimcode-0.1.18 → nimcode-0.1.21}/src/nimcode/mcp_client.py +0 -0
  14. {nimcode-0.1.18 → nimcode-0.1.21}/src/nimcode/memory.py +0 -0
  15. {nimcode-0.1.18 → nimcode-0.1.21}/src/nimcode/nim_client.py +0 -0
  16. {nimcode-0.1.18 → nimcode-0.1.21}/src/nimcode/permissions.py +0 -0
  17. {nimcode-0.1.18 → nimcode-0.1.21}/src/nimcode/plugin_manager.py +0 -0
  18. {nimcode-0.1.18 → nimcode-0.1.21}/src/nimcode/repl.py +0 -0
  19. {nimcode-0.1.18 → nimcode-0.1.21}/src/nimcode/repo_map.py +0 -0
  20. {nimcode-0.1.18 → nimcode-0.1.21}/src/nimcode/secret_scanner.py +0 -0
  21. {nimcode-0.1.18 → nimcode-0.1.21}/src/nimcode/stdio_server.py +0 -0
  22. {nimcode-0.1.18 → nimcode-0.1.21}/src/nimcode/swarm.py +0 -0
  23. {nimcode-0.1.18 → nimcode-0.1.21}/src/nimcode/tools.py +0 -0
  24. {nimcode-0.1.18 → nimcode-0.1.21}/src/nimcode/updater.py +0 -0
  25. {nimcode-0.1.18 → nimcode-0.1.21}/src/nimcode/watcher.py +0 -0
  26. {nimcode-0.1.18 → nimcode-0.1.21}/src/nimcode.egg-info/SOURCES.txt +0 -0
  27. {nimcode-0.1.18 → nimcode-0.1.21}/src/nimcode.egg-info/dependency_links.txt +0 -0
  28. {nimcode-0.1.18 → nimcode-0.1.21}/src/nimcode.egg-info/entry_points.txt +0 -0
  29. {nimcode-0.1.18 → nimcode-0.1.21}/src/nimcode.egg-info/requires.txt +0 -0
  30. {nimcode-0.1.18 → nimcode-0.1.21}/src/nimcode.egg-info/top_level.txt +0 -0
  31. {nimcode-0.1.18 → nimcode-0.1.21}/tests/test_agent.py +0 -0
  32. {nimcode-0.1.18 → nimcode-0.1.21}/tests/test_analytics.py +0 -0
  33. {nimcode-0.1.18 → nimcode-0.1.21}/tests/test_config.py +0 -0
  34. {nimcode-0.1.18 → nimcode-0.1.21}/tests/test_lenient_parser.py +0 -0
  35. {nimcode-0.1.18 → nimcode-0.1.21}/tests/test_mcp_client.py +0 -0
  36. {nimcode-0.1.18 → nimcode-0.1.21}/tests/test_memory.py +0 -0
  37. {nimcode-0.1.18 → nimcode-0.1.21}/tests/test_nim_client.py +0 -0
  38. {nimcode-0.1.18 → nimcode-0.1.21}/tests/test_nimcoderules.py +0 -0
  39. {nimcode-0.1.18 → nimcode-0.1.21}/tests/test_permissions.py +0 -0
  40. {nimcode-0.1.18 → nimcode-0.1.21}/tests/test_plugin_manager.py +0 -0
  41. {nimcode-0.1.18 → nimcode-0.1.21}/tests/test_repl.py +0 -0
  42. {nimcode-0.1.18 → nimcode-0.1.21}/tests/test_repl_extra.py +0 -0
  43. {nimcode-0.1.18 → nimcode-0.1.21}/tests/test_repl_trust.py +0 -0
  44. {nimcode-0.1.18 → nimcode-0.1.21}/tests/test_repo_map.py +0 -0
  45. {nimcode-0.1.18 → nimcode-0.1.21}/tests/test_secret_scanner.py +0 -0
  46. {nimcode-0.1.18 → nimcode-0.1.21}/tests/test_tools.py +0 -0
  47. {nimcode-0.1.18 → nimcode-0.1.21}/tests/test_updater.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nimcode
3
- Version: 0.1.18
3
+ Version: 0.1.21
4
4
  Summary: A standalone, robust coding agent for NVIDIA NIM models.
5
5
  Author: Autonomous Agent
6
6
  Requires-Dist: httpx>=0.27.0
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
2
2
 
3
3
  setup(
4
4
  name="nimcode",
5
- version="0.1.18",
5
+ version="0.1.21",
6
6
  packages=find_packages(where="src"),
7
7
  package_dir={"": "src"},
8
8
  install_requires=[
@@ -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 keyring
17
+ from .config import save_global_setting
18
18
 
19
- api_key = getpass.getpass("Enter your NVIDIA NIM API Key: ")
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
- keyring.set_password("nimcode", "api_key", api_key.strip())
25
- console.print("[green][OK] API Key saved securely to OS Keyring[/green]")
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
- import keyring
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 = keyring.get_password("nimcode", "api_key") or settings.get("api_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
- # Scrub legacy api_key if found to ensure it uses keyring
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):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nimcode
3
- Version: 0.1.18
3
+ Version: 0.1.21
4
4
  Summary: A standalone, robust coding agent for NVIDIA NIM models.
5
5
  Author: Autonomous Agent
6
6
  Requires-Dist: httpx>=0.27.0
@@ -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("keyring.set_password") as mock_save:
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("nimcode", "api_key", "my_key")
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
- main()
73
- mock_log.assert_called_once()
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("keyring.get_password", return_value=None):
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("keyring.get_password", return_value=None):
95
- with patch("rich.prompt.Prompt.ask", return_value="1"):
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("keyring.get_password", return_value=None):
107
- with patch("rich.prompt.Prompt.ask", return_value="1"):
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("keyring.get_password", return_value=None):
118
- with patch("rich.prompt.Prompt.ask", return_value="1"):
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