neuroncli 2.2.0__tar.gz → 2.3.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.
- {neuroncli-2.2.0 → neuroncli-2.3.0}/PKG-INFO +3 -20
- {neuroncli-2.2.0 → neuroncli-2.3.0}/README.md +2 -19
- {neuroncli-2.2.0 → neuroncli-2.3.0}/neuroncli/auth.py +140 -70
- {neuroncli-2.2.0 → neuroncli-2.3.0}/neuroncli/config.py +1 -1
- {neuroncli-2.2.0 → neuroncli-2.3.0}/neuroncli.egg-info/PKG-INFO +3 -20
- {neuroncli-2.2.0 → neuroncli-2.3.0}/pyproject.toml +1 -1
- {neuroncli-2.2.0 → neuroncli-2.3.0}/neuroncli/__init__.py +0 -0
- {neuroncli-2.2.0 → neuroncli-2.3.0}/neuroncli/__main__.py +0 -0
- {neuroncli-2.2.0 → neuroncli-2.3.0}/neuroncli/agent.py +0 -0
- {neuroncli-2.2.0 → neuroncli-2.3.0}/neuroncli/cli.py +0 -0
- {neuroncli-2.2.0 → neuroncli-2.3.0}/neuroncli/git_integration.py +0 -0
- {neuroncli-2.2.0 → neuroncli-2.3.0}/neuroncli/ollama_client.py +0 -0
- {neuroncli-2.2.0 → neuroncli-2.3.0}/neuroncli/openrouter_client.py +0 -0
- {neuroncli-2.2.0 → neuroncli-2.3.0}/neuroncli/prompts.py +0 -0
- {neuroncli-2.2.0 → neuroncli-2.3.0}/neuroncli/provider.py +0 -0
- {neuroncli-2.2.0 → neuroncli-2.3.0}/neuroncli/session.py +0 -0
- {neuroncli-2.2.0 → neuroncli-2.3.0}/neuroncli/tools.py +0 -0
- {neuroncli-2.2.0 → neuroncli-2.3.0}/neuroncli/ui.py +0 -0
- {neuroncli-2.2.0 → neuroncli-2.3.0}/neuroncli.egg-info/SOURCES.txt +0 -0
- {neuroncli-2.2.0 → neuroncli-2.3.0}/neuroncli.egg-info/dependency_links.txt +0 -0
- {neuroncli-2.2.0 → neuroncli-2.3.0}/neuroncli.egg-info/entry_points.txt +0 -0
- {neuroncli-2.2.0 → neuroncli-2.3.0}/neuroncli.egg-info/requires.txt +0 -0
- {neuroncli-2.2.0 → neuroncli-2.3.0}/neuroncli.egg-info/top_level.txt +0 -0
- {neuroncli-2.2.0 → neuroncli-2.3.0}/setup.cfg +0 -0
- {neuroncli-2.2.0 → neuroncli-2.3.0}/tests/test_agent.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: neuroncli
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.3.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,25 +34,8 @@ Requires-Dist: requests>=2.28.0
|
|
|
34
34
|
## Install
|
|
35
35
|
|
|
36
36
|
```bash
|
|
37
|
-
# Windows
|
|
38
|
-
pip install neuroncli
|
|
39
|
-
|
|
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)
|
|
49
|
-
git clone https://github.com/RAHUL-DevelopeRR/neuroncli.git
|
|
50
|
-
cd neuroncli && pip install -e .
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
```bash
|
|
54
|
-
# Linux/macOS auto-install script
|
|
55
|
-
curl -fsSL https://raw.githubusercontent.com/RAHUL-DevelopeRR/neuroncli/master/install.sh | bash
|
|
37
|
+
pip install neuroncli # Windows / macOS / Cloud VMs
|
|
38
|
+
pip install neuroncli --break-system-packages # Linux (Ubuntu 23+, Debian 12+, Fedora 38+)
|
|
56
39
|
```
|
|
57
40
|
|
|
58
41
|
## Quick Start
|
|
@@ -9,25 +9,8 @@
|
|
|
9
9
|
## Install
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
|
-
# Windows
|
|
13
|
-
pip install neuroncli
|
|
14
|
-
|
|
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)
|
|
24
|
-
git clone https://github.com/RAHUL-DevelopeRR/neuroncli.git
|
|
25
|
-
cd neuroncli && pip install -e .
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
```bash
|
|
29
|
-
# Linux/macOS auto-install script
|
|
30
|
-
curl -fsSL https://raw.githubusercontent.com/RAHUL-DevelopeRR/neuroncli/master/install.sh | bash
|
|
12
|
+
pip install neuroncli # Windows / macOS / Cloud VMs
|
|
13
|
+
pip install neuroncli --break-system-packages # Linux (Ubuntu 23+, Debian 12+, Fedora 38+)
|
|
31
14
|
```
|
|
32
15
|
|
|
33
16
|
## Quick Start
|
|
@@ -179,16 +179,11 @@ def _exchange_code_for_key(code: str, code_verifier: str) -> str:
|
|
|
179
179
|
|
|
180
180
|
def run_oauth_flow() -> str | None:
|
|
181
181
|
"""
|
|
182
|
-
Run
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
4. Exchange code for API key
|
|
187
|
-
5. Store key locally
|
|
188
|
-
|
|
189
|
-
Returns the API key on success, None on failure.
|
|
182
|
+
Run OAuth PKCE + manual paste IN PARALLEL:
|
|
183
|
+
- Background thread: localhost server waits for callback (10 min)
|
|
184
|
+
- Foreground: user can paste key manually while waiting
|
|
185
|
+
- Whichever succeeds first wins.
|
|
190
186
|
"""
|
|
191
|
-
# Reset
|
|
192
187
|
_OAuthCallbackHandler.auth_code = None
|
|
193
188
|
|
|
194
189
|
# Generate PKCE pair
|
|
@@ -203,83 +198,160 @@ def run_oauth_flow() -> str | None:
|
|
|
203
198
|
f"&code_challenge_method=S256"
|
|
204
199
|
)
|
|
205
200
|
|
|
206
|
-
# Start callback server in background
|
|
201
|
+
# Start callback server in background thread
|
|
202
|
+
server = None
|
|
207
203
|
try:
|
|
208
204
|
server = http.server.HTTPServer(("127.0.0.1", CALLBACK_PORT), _OAuthCallbackHandler)
|
|
209
205
|
except OSError:
|
|
210
|
-
# Port in use —
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
server
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
206
|
+
pass # Port in use — skip background listener
|
|
207
|
+
|
|
208
|
+
server_thread = None
|
|
209
|
+
if server:
|
|
210
|
+
server.timeout = 600 # 10 MINUTES — enough for signup + email verify + survey
|
|
211
|
+
def _listen():
|
|
212
|
+
try:
|
|
213
|
+
server.handle_request()
|
|
214
|
+
except Exception:
|
|
215
|
+
pass
|
|
216
|
+
finally:
|
|
217
|
+
server.server_close()
|
|
218
|
+
server_thread = threading.Thread(target=_listen, daemon=True)
|
|
219
|
+
server_thread.start()
|
|
218
220
|
|
|
219
221
|
# Open browser
|
|
222
|
+
print("\n \033[96m\033[1m[AUTH]\033[0m Opening browser for OpenRouter login...")
|
|
220
223
|
try:
|
|
221
224
|
webbrowser.open(auth_url)
|
|
222
225
|
except Exception:
|
|
223
|
-
|
|
226
|
+
pass
|
|
224
227
|
|
|
225
|
-
|
|
228
|
+
# Show user-friendly instructions
|
|
229
|
+
print(f" \033[90m──────────────────────────────────────────────\033[0m")
|
|
230
|
+
print(f" \033[97mSign up / log in to OpenRouter in your browser.\033[0m")
|
|
231
|
+
print(f" \033[97mAfter login, you'll be redirected back here.\033[0m")
|
|
232
|
+
print(f" \033[90m──────────────────────────────────────────────\033[0m")
|
|
233
|
+
print(f" \033[90mIf auto-redirect doesn't work:\033[0m")
|
|
234
|
+
print(f" \033[90m1. Go to: \033[4mhttps://openrouter.ai/settings/keys\033[0m")
|
|
235
|
+
print(f" \033[90m2. Click 'Create Key' -> copy the key\033[0m")
|
|
236
|
+
print(f" \033[90m3. Paste it below\033[0m")
|
|
237
|
+
print(f" \033[90m──────────────────────────────────────────────\033[0m\n")
|
|
238
|
+
|
|
239
|
+
# PARALLEL: Wait for EITHER OAuth callback OR manual paste
|
|
240
|
+
# Poll every 2 seconds to check if background OAuth succeeded
|
|
241
|
+
import time
|
|
242
|
+
import sys
|
|
243
|
+
import select
|
|
244
|
+
|
|
245
|
+
api_key = None
|
|
246
|
+
|
|
247
|
+
# On Windows, we can't use select() on stdin. Use a simpler approach.
|
|
248
|
+
if sys.platform == "win32":
|
|
249
|
+
api_key = _windows_parallel_auth(server_thread, code_verifier)
|
|
250
|
+
else:
|
|
251
|
+
api_key = _unix_parallel_auth(server_thread, code_verifier)
|
|
226
252
|
|
|
227
|
-
#
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
253
|
+
# Clean up server
|
|
254
|
+
if server:
|
|
255
|
+
try:
|
|
256
|
+
server.server_close()
|
|
257
|
+
except Exception:
|
|
258
|
+
pass
|
|
259
|
+
|
|
260
|
+
if api_key:
|
|
261
|
+
store_api_key(api_key)
|
|
262
|
+
print(f"\n \033[92m\033[1m[OK] API key saved to {CONFIG_FILE}\033[0m")
|
|
263
|
+
print(f" \033[92m\033[1m You won't be asked again.\033[0m\n")
|
|
264
|
+
return api_key
|
|
265
|
+
|
|
266
|
+
print(f"\n \033[90mNo API key provided. Using Ollama fallback if available.\033[0m\n")
|
|
267
|
+
return None
|
|
234
268
|
|
|
269
|
+
|
|
270
|
+
def _check_oauth_result(code_verifier: str) -> str | None:
|
|
271
|
+
"""Check if the background OAuth server received a code."""
|
|
235
272
|
code = _OAuthCallbackHandler.auth_code
|
|
236
273
|
if not code:
|
|
237
|
-
|
|
238
|
-
|
|
274
|
+
return None
|
|
275
|
+
try:
|
|
276
|
+
return _exchange_code_for_key(code, code_verifier)
|
|
277
|
+
except RuntimeError:
|
|
278
|
+
return None
|
|
239
279
|
|
|
240
|
-
print(f" \033[92mv\033[0m")
|
|
241
|
-
print(" \033[96mExchanging code for API key...\033[0m", end="", flush=True)
|
|
242
280
|
|
|
243
|
-
|
|
281
|
+
def _validate_key(key: str) -> bool:
|
|
282
|
+
"""Check if a pasted key looks valid."""
|
|
283
|
+
key = key.strip()
|
|
284
|
+
return len(key) > 10 and (key.startswith("sk-or-") or key.startswith("sk-"))
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
def _windows_parallel_auth(server_thread, code_verifier: str) -> str | None:
|
|
288
|
+
"""Windows: prompt for manual paste while checking OAuth in background."""
|
|
289
|
+
import time
|
|
290
|
+
|
|
291
|
+
print(" \033[93mPaste your API key below (or wait for auto-redirect):\033[0m")
|
|
292
|
+
print(" \033[93m> \033[0m", end="", flush=True)
|
|
293
|
+
|
|
244
294
|
try:
|
|
245
|
-
|
|
246
|
-
except
|
|
247
|
-
|
|
248
|
-
|
|
295
|
+
key = input().strip()
|
|
296
|
+
except (EOFError, KeyboardInterrupt):
|
|
297
|
+
key = ""
|
|
298
|
+
|
|
299
|
+
if key and _validate_key(key):
|
|
300
|
+
return key
|
|
301
|
+
|
|
302
|
+
# Check if OAuth completed while user was typing
|
|
303
|
+
result = _check_oauth_result(code_verifier)
|
|
304
|
+
if result:
|
|
305
|
+
print(" \033[92m[v] Auto-redirect succeeded!\033[0m")
|
|
306
|
+
return result
|
|
307
|
+
|
|
308
|
+
# Neither worked — wait up to 30 more seconds for OAuth
|
|
309
|
+
print(" \033[90mWaiting for browser redirect...\033[0m", end="", flush=True)
|
|
310
|
+
for _ in range(15):
|
|
311
|
+
time.sleep(2)
|
|
312
|
+
result = _check_oauth_result(code_verifier)
|
|
313
|
+
if result:
|
|
314
|
+
print(f" \033[92mv\033[0m")
|
|
315
|
+
return result
|
|
316
|
+
print(".", end="", flush=True)
|
|
249
317
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
print(f" \033[92mv\033[0m")
|
|
253
|
-
print(f" \033[92m\033[1m[OK] API key saved to {CONFIG_FILE}\033[0m\n")
|
|
318
|
+
print(f" \033[91mx\033[0m")
|
|
319
|
+
return None
|
|
254
320
|
|
|
255
|
-
return api_key
|
|
256
321
|
|
|
322
|
+
def _unix_parallel_auth(server_thread, code_verifier: str) -> str | None:
|
|
323
|
+
"""Unix: prompt for manual paste while checking OAuth in background."""
|
|
324
|
+
import time
|
|
257
325
|
|
|
258
|
-
|
|
259
|
-
""
|
|
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")
|
|
326
|
+
print(" \033[93mPaste your API key below (or wait for auto-redirect):\033[0m")
|
|
327
|
+
print(" \033[93m> \033[0m", end="", flush=True)
|
|
265
328
|
|
|
266
329
|
try:
|
|
267
|
-
key = input(
|
|
330
|
+
key = input().strip()
|
|
268
331
|
except (EOFError, KeyboardInterrupt):
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
if not key:
|
|
272
|
-
print(f"\n \033[90mSkipped. Using Ollama fallback if available.\033[0m\n")
|
|
273
|
-
return None
|
|
332
|
+
key = ""
|
|
274
333
|
|
|
275
|
-
if key
|
|
276
|
-
store_api_key(key)
|
|
277
|
-
print(f" \033[92m\033[1m[OK] API key saved to {CONFIG_FILE}\033[0m\n")
|
|
334
|
+
if key and _validate_key(key):
|
|
278
335
|
return key
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
336
|
+
|
|
337
|
+
# Check if OAuth completed while user was typing
|
|
338
|
+
result = _check_oauth_result(code_verifier)
|
|
339
|
+
if result:
|
|
340
|
+
print(" \033[92m[v] Auto-redirect succeeded!\033[0m")
|
|
341
|
+
return result
|
|
342
|
+
|
|
343
|
+
# Neither worked — wait up to 30 more seconds for OAuth
|
|
344
|
+
print(" \033[90mWaiting for browser redirect...\033[0m", end="", flush=True)
|
|
345
|
+
for _ in range(15):
|
|
346
|
+
time.sleep(2)
|
|
347
|
+
result = _check_oauth_result(code_verifier)
|
|
348
|
+
if result:
|
|
349
|
+
print(f" \033[92mv\033[0m")
|
|
350
|
+
return result
|
|
351
|
+
print(".", end="", flush=True)
|
|
352
|
+
|
|
353
|
+
print(f" \033[91mx\033[0m")
|
|
354
|
+
return None
|
|
283
355
|
|
|
284
356
|
|
|
285
357
|
# ── Public API ────────────────────────────────────────────────────
|
|
@@ -289,12 +361,11 @@ def ensure_api_key() -> str | None:
|
|
|
289
361
|
Ensure an API key is available. Checks in order:
|
|
290
362
|
1. OPENROUTER_API_KEY env var
|
|
291
363
|
2. ~/.neuroncli/config.json
|
|
292
|
-
3.
|
|
293
|
-
4. Manual key paste (fallback if OAuth fails)
|
|
364
|
+
3. OAuth PKCE (background) + manual paste (foreground) — in parallel
|
|
294
365
|
|
|
295
366
|
Returns the API key or None if all methods fail.
|
|
296
367
|
"""
|
|
297
|
-
# Check env var
|
|
368
|
+
# Check env var
|
|
298
369
|
env_key = os.environ.get("OPENROUTER_API_KEY")
|
|
299
370
|
if env_key:
|
|
300
371
|
return env_key
|
|
@@ -304,12 +375,11 @@ def ensure_api_key() -> str | None:
|
|
|
304
375
|
if stored_key:
|
|
305
376
|
return stored_key
|
|
306
377
|
|
|
307
|
-
# First run —
|
|
308
|
-
print("\n \033[96m\033[1m
|
|
309
|
-
print(" ║ Welcome to NeuronCLI!
|
|
310
|
-
print(" ║
|
|
311
|
-
print("
|
|
312
|
-
print(" ╚════════════════════════════════════════════════╝\033[0m")
|
|
378
|
+
# First run — welcome message
|
|
379
|
+
print("\n \033[96m\033[1m╔══════════════════════════════════════════════════╗")
|
|
380
|
+
print(" ║ Welcome to NeuronCLI! ║")
|
|
381
|
+
print(" ║ Free AI coding agent — one-time setup below. ║")
|
|
382
|
+
print(" ╚══════════════════════════════════════════════════╝\033[0m")
|
|
313
383
|
|
|
314
384
|
return run_oauth_flow()
|
|
315
385
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: neuroncli
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.3.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,25 +34,8 @@ Requires-Dist: requests>=2.28.0
|
|
|
34
34
|
## Install
|
|
35
35
|
|
|
36
36
|
```bash
|
|
37
|
-
# Windows
|
|
38
|
-
pip install neuroncli
|
|
39
|
-
|
|
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)
|
|
49
|
-
git clone https://github.com/RAHUL-DevelopeRR/neuroncli.git
|
|
50
|
-
cd neuroncli && pip install -e .
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
```bash
|
|
54
|
-
# Linux/macOS auto-install script
|
|
55
|
-
curl -fsSL https://raw.githubusercontent.com/RAHUL-DevelopeRR/neuroncli/master/install.sh | bash
|
|
37
|
+
pip install neuroncli # Windows / macOS / Cloud VMs
|
|
38
|
+
pip install neuroncli --break-system-packages # Linux (Ubuntu 23+, Debian 12+, Fedora 38+)
|
|
56
39
|
```
|
|
57
40
|
|
|
58
41
|
## Quick Start
|
|
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
|