neuroncli 2.1.0__tar.gz → 2.2.0__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 (25) hide show
  1. {neuroncli-2.1.0 → neuroncli-2.2.0}/PKG-INFO +13 -6
  2. {neuroncli-2.1.0 → neuroncli-2.2.0}/README.md +12 -5
  3. {neuroncli-2.1.0 → neuroncli-2.2.0}/neuroncli/auth.py +63 -11
  4. {neuroncli-2.1.0 → neuroncli-2.2.0}/neuroncli/config.py +1 -1
  5. {neuroncli-2.1.0 → neuroncli-2.2.0}/neuroncli.egg-info/PKG-INFO +13 -6
  6. {neuroncli-2.1.0 → neuroncli-2.2.0}/pyproject.toml +1 -1
  7. {neuroncli-2.1.0 → neuroncli-2.2.0}/neuroncli/__init__.py +0 -0
  8. {neuroncli-2.1.0 → neuroncli-2.2.0}/neuroncli/__main__.py +0 -0
  9. {neuroncli-2.1.0 → neuroncli-2.2.0}/neuroncli/agent.py +0 -0
  10. {neuroncli-2.1.0 → neuroncli-2.2.0}/neuroncli/cli.py +0 -0
  11. {neuroncli-2.1.0 → neuroncli-2.2.0}/neuroncli/git_integration.py +0 -0
  12. {neuroncli-2.1.0 → neuroncli-2.2.0}/neuroncli/ollama_client.py +0 -0
  13. {neuroncli-2.1.0 → neuroncli-2.2.0}/neuroncli/openrouter_client.py +0 -0
  14. {neuroncli-2.1.0 → neuroncli-2.2.0}/neuroncli/prompts.py +0 -0
  15. {neuroncli-2.1.0 → neuroncli-2.2.0}/neuroncli/provider.py +0 -0
  16. {neuroncli-2.1.0 → neuroncli-2.2.0}/neuroncli/session.py +0 -0
  17. {neuroncli-2.1.0 → neuroncli-2.2.0}/neuroncli/tools.py +0 -0
  18. {neuroncli-2.1.0 → neuroncli-2.2.0}/neuroncli/ui.py +0 -0
  19. {neuroncli-2.1.0 → neuroncli-2.2.0}/neuroncli.egg-info/SOURCES.txt +0 -0
  20. {neuroncli-2.1.0 → neuroncli-2.2.0}/neuroncli.egg-info/dependency_links.txt +0 -0
  21. {neuroncli-2.1.0 → neuroncli-2.2.0}/neuroncli.egg-info/entry_points.txt +0 -0
  22. {neuroncli-2.1.0 → neuroncli-2.2.0}/neuroncli.egg-info/requires.txt +0 -0
  23. {neuroncli-2.1.0 → neuroncli-2.2.0}/neuroncli.egg-info/top_level.txt +0 -0
  24. {neuroncli-2.1.0 → neuroncli-2.2.0}/setup.cfg +0 -0
  25. {neuroncli-2.1.0 → neuroncli-2.2.0}/tests/test_agent.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: neuroncli
3
- Version: 2.1.0
3
+ Version: 2.2.0
4
4
  Summary: AI Coding Agent — Free Claude Code alternative powered by Kimi K2.5 + Ollama
5
5
  Author-email: Rahul S <rahultech72216@gmail.com>
6
6
  License: MIT
@@ -34,17 +34,24 @@ Requires-Dist: requests>=2.28.0
34
34
  ## Install
35
35
 
36
36
  ```bash
37
- # From PyPI (all platforms)
37
+ # Windows
38
38
  pip install neuroncli
39
39
 
40
- # Or from source
40
+ # Linux / macOS (modern distros use pipx)
41
+ pipx install neuroncli
42
+
43
+ # If pipx not installed:
44
+ # sudo apt install pipx && pipx ensurepath (Debian/Ubuntu)
45
+ # sudo dnf install pipx && pipx ensurepath (Fedora)
46
+ # brew install pipx && pipx ensurepath (macOS)
47
+
48
+ # From source (any platform)
41
49
  git clone https://github.com/RAHUL-DevelopeRR/neuroncli.git
42
- cd neuroncli
43
- pip install -e .
50
+ cd neuroncli && pip install -e .
44
51
  ```
45
52
 
46
53
  ```bash
47
- # Linux/macOS one-liner
54
+ # Linux/macOS auto-install script
48
55
  curl -fsSL https://raw.githubusercontent.com/RAHUL-DevelopeRR/neuroncli/master/install.sh | bash
49
56
  ```
50
57
 
@@ -9,17 +9,24 @@
9
9
  ## Install
10
10
 
11
11
  ```bash
12
- # From PyPI (all platforms)
12
+ # Windows
13
13
  pip install neuroncli
14
14
 
15
- # Or from source
15
+ # Linux / macOS (modern distros use pipx)
16
+ pipx install neuroncli
17
+
18
+ # If pipx not installed:
19
+ # sudo apt install pipx && pipx ensurepath (Debian/Ubuntu)
20
+ # sudo dnf install pipx && pipx ensurepath (Fedora)
21
+ # brew install pipx && pipx ensurepath (macOS)
22
+
23
+ # From source (any platform)
16
24
  git clone https://github.com/RAHUL-DevelopeRR/neuroncli.git
17
- cd neuroncli
18
- pip install -e .
25
+ cd neuroncli && pip install -e .
19
26
  ```
20
27
 
21
28
  ```bash
22
- # Linux/macOS one-liner
29
+ # Linux/macOS auto-install script
23
30
  curl -fsSL https://raw.githubusercontent.com/RAHUL-DevelopeRR/neuroncli/master/install.sh | bash
24
31
  ```
25
32
 
@@ -27,8 +27,10 @@ from pathlib import Path
27
27
 
28
28
  CONFIG_DIR = Path.home() / ".neuroncli"
29
29
  CONFIG_FILE = CONFIG_DIR / "config.json"
30
- CALLBACK_PORT = 19284 # Obscure port to avoid collisions
31
- CALLBACK_URL = f"http://localhost:{CALLBACK_PORT}"
30
+ CALLBACK_PORT = 19284 # Local server port to catch the redirect from zero-x.live
31
+ LOCAL_CALLBACK = f"http://localhost:{CALLBACK_PORT}"
32
+ # OpenRouter callback → zero-x.live → redirects to localhost with ?code=
33
+ CALLBACK_URL = "https://zero-x.live/neuroncli/callback"
32
34
 
33
35
 
34
36
  # ── PKCE helpers ──────────────────────────────────────────────────
@@ -78,10 +80,22 @@ def store_api_key(key: str) -> None:
78
80
  # ── OAuth PKCE flow ──────────────────────────────────────────────
79
81
 
80
82
  class _OAuthCallbackHandler(http.server.BaseHTTPRequestHandler):
81
- """Tiny HTTP handler that captures the OAuth redirect code."""
83
+ """Tiny HTTP handler that captures the OAuth redirect code.
84
+ Handles redirects from zero-x.live callback page."""
82
85
 
83
86
  auth_code: str | None = None
84
87
 
88
+ def _send_cors_headers(self):
89
+ """Allow cross-origin requests from zero-x.live."""
90
+ self.send_header("Access-Control-Allow-Origin", "*")
91
+ self.send_header("Access-Control-Allow-Methods", "GET, OPTIONS")
92
+
93
+ def do_OPTIONS(self):
94
+ """Handle CORS preflight."""
95
+ self.send_response(200)
96
+ self._send_cors_headers()
97
+ self.end_headers()
98
+
85
99
  def do_GET(self):
86
100
  parsed = urllib.parse.urlparse(self.path)
87
101
  params = urllib.parse.parse_qs(parsed.query)
@@ -93,6 +107,7 @@ class _OAuthCallbackHandler(http.server.BaseHTTPRequestHandler):
93
107
  # Show success page
94
108
  self.send_response(200)
95
109
  self.send_header("Content-Type", "text/html")
110
+ self._send_cors_headers()
96
111
  self.end_headers()
97
112
  self.wfile.write(b"""
98
113
  <html>
@@ -112,7 +127,7 @@ class _OAuthCallbackHandler(http.server.BaseHTTPRequestHandler):
112
127
  border-radius: 24px;
113
128
  backdrop-filter: blur(20px);
114
129
  }
115
- h1 { color: #00ff88; font-size: 2em; }
130
+ h1 { color: #f0a028; font-size: 2em; }
116
131
  p { color: #aaa; font-size: 1.1em; }
117
132
  </style>
118
133
  </head>
@@ -189,7 +204,12 @@ def run_oauth_flow() -> str | None:
189
204
  )
190
205
 
191
206
  # Start callback server in background
192
- server = http.server.HTTPServer(("127.0.0.1", CALLBACK_PORT), _OAuthCallbackHandler)
207
+ try:
208
+ server = http.server.HTTPServer(("127.0.0.1", CALLBACK_PORT), _OAuthCallbackHandler)
209
+ except OSError:
210
+ # Port in use — another instance is running
211
+ print(f"\n \033[91m[X] Port {CALLBACK_PORT} is in use. Close other instances first.\033[0m")
212
+ return None
193
213
  server.timeout = 120 # 2 minute timeout
194
214
 
195
215
  print("\n \033[96m\033[1m[AUTH]\033[0m Opening browser for OpenRouter login...")
@@ -197,7 +217,10 @@ def run_oauth_flow() -> str | None:
197
217
  print(f" \033[90m{auth_url[:80]}...\033[0m\n")
198
218
 
199
219
  # Open browser
200
- webbrowser.open(auth_url)
220
+ try:
221
+ webbrowser.open(auth_url)
222
+ except Exception:
223
+ print(" \033[90m(Browser could not be opened. Use the URL above.)\033[0m")
201
224
 
202
225
  print(" \033[93mWaiting for authentication...\033[0m", end="", flush=True)
203
226
 
@@ -211,10 +234,10 @@ def run_oauth_flow() -> str | None:
211
234
 
212
235
  code = _OAuthCallbackHandler.auth_code
213
236
  if not code:
214
- print(f"\n \033[91m[X] Authentication timed out or failed.\033[0m")
215
- return None
237
+ print(f"\n \033[91m[X] OAuth timed out or failed.\033[0m")
238
+ return _manual_key_fallback()
216
239
 
217
- print(f" \033[92m✓\033[0m")
240
+ print(f" \033[92mv\033[0m")
218
241
  print(" \033[96mExchanging code for API key...\033[0m", end="", flush=True)
219
242
 
220
243
  # Exchange code for key
@@ -222,16 +245,43 @@ def run_oauth_flow() -> str | None:
222
245
  api_key = _exchange_code_for_key(code, code_verifier)
223
246
  except RuntimeError as e:
224
247
  print(f"\n \033[91m[X] {e}\033[0m")
225
- return None
248
+ return _manual_key_fallback()
226
249
 
227
250
  # Store
228
251
  store_api_key(api_key)
229
- print(f" \033[92m✓\033[0m")
252
+ print(f" \033[92mv\033[0m")
230
253
  print(f" \033[92m\033[1m[OK] API key saved to {CONFIG_FILE}\033[0m\n")
231
254
 
232
255
  return api_key
233
256
 
234
257
 
258
+ def _manual_key_fallback() -> str | None:
259
+ """Fallback: let user manually paste their OpenRouter API key."""
260
+ print(f"\n \033[96m\033[1m[MANUAL SETUP]\033[0m")
261
+ print(f" \033[90mOAuth didn't work. You can paste your key instead:\033[0m")
262
+ print(f" \033[90m1. Go to: https://openrouter.ai/settings/keys\033[0m")
263
+ print(f" \033[90m2. Click 'Create Key'\033[0m")
264
+ print(f" \033[90m3. Copy the key (starts with sk-or-...)\033[0m\n")
265
+
266
+ try:
267
+ key = input(" \033[93mPaste your API key (or Enter to skip): \033[0m").strip()
268
+ except (EOFError, KeyboardInterrupt):
269
+ return None
270
+
271
+ if not key:
272
+ print(f"\n \033[90mSkipped. Using Ollama fallback if available.\033[0m\n")
273
+ return None
274
+
275
+ if key.startswith("sk-or-") or key.startswith("sk-"):
276
+ store_api_key(key)
277
+ print(f" \033[92m\033[1m[OK] API key saved to {CONFIG_FILE}\033[0m\n")
278
+ return key
279
+ else:
280
+ print(f" \033[91m[X] Invalid key format. Expected 'sk-or-...' \033[0m")
281
+ print(f" \033[90mGet one at: https://openrouter.ai/settings/keys\033[0m\n")
282
+ return None
283
+
284
+
235
285
  # ── Public API ────────────────────────────────────────────────────
236
286
 
237
287
  def ensure_api_key() -> str | None:
@@ -240,6 +290,7 @@ def ensure_api_key() -> str | None:
240
290
  1. OPENROUTER_API_KEY env var
241
291
  2. ~/.neuroncli/config.json
242
292
  3. Interactive OAuth PKCE flow (first-run)
293
+ 4. Manual key paste (fallback if OAuth fails)
243
294
 
244
295
  Returns the API key or None if all methods fail.
245
296
  """
@@ -261,3 +312,4 @@ def ensure_api_key() -> str | None:
261
312
  print(" ╚════════════════════════════════════════════════╝\033[0m")
262
313
 
263
314
  return run_oauth_flow()
315
+
@@ -109,4 +109,4 @@ class AgentConfig:
109
109
  # ── App-wide constants ────────────────────────────────────────────
110
110
 
111
111
  APP_NAME = "NeuronCLI"
112
- VERSION = "2.1.0"
112
+ VERSION = "2.2.0"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: neuroncli
3
- Version: 2.1.0
3
+ Version: 2.2.0
4
4
  Summary: AI Coding Agent — Free Claude Code alternative powered by Kimi K2.5 + Ollama
5
5
  Author-email: Rahul S <rahultech72216@gmail.com>
6
6
  License: MIT
@@ -34,17 +34,24 @@ Requires-Dist: requests>=2.28.0
34
34
  ## Install
35
35
 
36
36
  ```bash
37
- # From PyPI (all platforms)
37
+ # Windows
38
38
  pip install neuroncli
39
39
 
40
- # Or from source
40
+ # Linux / macOS (modern distros use pipx)
41
+ pipx install neuroncli
42
+
43
+ # If pipx not installed:
44
+ # sudo apt install pipx && pipx ensurepath (Debian/Ubuntu)
45
+ # sudo dnf install pipx && pipx ensurepath (Fedora)
46
+ # brew install pipx && pipx ensurepath (macOS)
47
+
48
+ # From source (any platform)
41
49
  git clone https://github.com/RAHUL-DevelopeRR/neuroncli.git
42
- cd neuroncli
43
- pip install -e .
50
+ cd neuroncli && pip install -e .
44
51
  ```
45
52
 
46
53
  ```bash
47
- # Linux/macOS one-liner
54
+ # Linux/macOS auto-install script
48
55
  curl -fsSL https://raw.githubusercontent.com/RAHUL-DevelopeRR/neuroncli/master/install.sh | bash
49
56
  ```
50
57
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "neuroncli"
7
- version = "2.1.0"
7
+ version = "2.2.0"
8
8
  description = "AI Coding Agent — Free Claude Code alternative powered by Kimi K2.5 + Ollama"
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes