eva-exploit 3.3__tar.gz → 3.3.1__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 (26) hide show
  1. {eva_exploit-3.3 → eva_exploit-3.3.1}/PKG-INFO +16 -17
  2. {eva_exploit-3.3 → eva_exploit-3.3.1}/README.md +15 -16
  3. {eva_exploit-3.3 → eva_exploit-3.3.1}/config.py +3 -2
  4. {eva_exploit-3.3 → eva_exploit-3.3.1}/eva.py +7 -0
  5. {eva_exploit-3.3 → eva_exploit-3.3.1}/eva_exploit.egg-info/PKG-INFO +16 -17
  6. {eva_exploit-3.3 → eva_exploit-3.3.1}/modules/llm.py +38 -1
  7. {eva_exploit-3.3 → eva_exploit-3.3.1}/pyproject.toml +1 -1
  8. {eva_exploit-3.3 → eva_exploit-3.3.1}/utils/system.py +101 -6
  9. {eva_exploit-3.3 → eva_exploit-3.3.1}/eva_exploit.egg-info/SOURCES.txt +0 -0
  10. {eva_exploit-3.3 → eva_exploit-3.3.1}/eva_exploit.egg-info/dependency_links.txt +0 -0
  11. {eva_exploit-3.3 → eva_exploit-3.3.1}/eva_exploit.egg-info/entry_points.txt +0 -0
  12. {eva_exploit-3.3 → eva_exploit-3.3.1}/eva_exploit.egg-info/requires.txt +0 -0
  13. {eva_exploit-3.3 → eva_exploit-3.3.1}/eva_exploit.egg-info/top_level.txt +0 -0
  14. {eva_exploit-3.3 → eva_exploit-3.3.1}/modules/__init__.py +0 -0
  15. {eva_exploit-3.3 → eva_exploit-3.3.1}/modules/attack_map.py +0 -0
  16. {eva_exploit-3.3 → eva_exploit-3.3.1}/modules/exploit_search.py +0 -0
  17. {eva_exploit-3.3 → eva_exploit-3.3.1}/modules/prompt_builder.py +0 -0
  18. {eva_exploit-3.3 → eva_exploit-3.3.1}/modules/reporting.py +0 -0
  19. {eva_exploit-3.3 → eva_exploit-3.3.1}/modules/tooling.py +0 -0
  20. {eva_exploit-3.3 → eva_exploit-3.3.1}/modules/vuln_intel.py +0 -0
  21. {eva_exploit-3.3 → eva_exploit-3.3.1}/modules/workflow.py +0 -0
  22. {eva_exploit-3.3 → eva_exploit-3.3.1}/sessions/__init__.py +0 -0
  23. {eva_exploit-3.3 → eva_exploit-3.3.1}/sessions/eva_session.py +0 -0
  24. {eva_exploit-3.3 → eva_exploit-3.3.1}/setup.cfg +0 -0
  25. {eva_exploit-3.3 → eva_exploit-3.3.1}/utils/__init__.py +0 -0
  26. {eva_exploit-3.3 → eva_exploit-3.3.1}/utils/ui.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: eva-exploit
3
- Version: 3.3
3
+ Version: 3.3.1
4
4
  Summary: Exploit Vector Agent
5
5
  Author: ARCANGEL0
6
6
  License: MIT
@@ -142,20 +142,23 @@ graph TD
142
142
 
143
143
  ### 🍎 Installation
144
144
 
145
+ #### Ollama for local endpoint (required for local models and eva exploit database)
145
146
  ```bash
146
- # Ollama for local endpoint (required for local models and eva exploit database)
147
147
  curl -fsSL https://ollama.ai/install.sh | shr
148
+ ```
148
149
 
149
- # pip installation
150
+ #### pip installation
151
+ ```bash
150
152
  pip install eva-exploit
151
153
  eva
154
+ ```
152
155
 
153
- # EVA installation
156
+ #### EVA github installation
157
+ ```bash
154
158
  git clone https://github.com/ARCANGEL0/EVA.git
155
159
  cd EVA
156
160
  chmod +x eva.py
157
161
  ./eva.py
158
-
159
162
  # Adding it to PATH to be acessible anywhere
160
163
  sudo mv eva.py /usr/local/bin/eva
161
164
  ```
@@ -186,14 +189,10 @@ eva --config
186
189
  │ ├── report1.html
187
190
  │ ├── report1.pdf
188
191
  │ └── ...
189
- ├── attack_maps/ # Attack vector maps in HTML/JS
190
- ├── attack_surface1.html
191
- ├── attack_surface2.html
192
- └── ...
193
- ├── utils/
194
- ├── modules/
195
- ├── eva
196
- └── config.py # API keys (auto-generated/persisted)
192
+ └── attack_maps/ # Attack vector maps in HTML/JS
193
+ ├── attack_surface1.html
194
+ ├── attack_surface2.html
195
+ └── ...
197
196
  ```
198
197
 
199
198
  ### ꀬ Where to change EVA options
@@ -319,11 +318,11 @@ Let me start with basic system reconnaissance to understand the target better...
319
318
  <summary><h2>Ξ AI Backends</h2></summary>
320
319
 
321
320
  ### 🦙 Ollama (Recommended)
322
- - **Model**: `jimscard/whiterabbit-neo:latest` (best one for OffSec)
321
+ - **Model**: `ALIENTELLIGENCE/whiterabbitv2"` (best one for OffSec)
323
322
  - ✅ Complete offline operation
324
323
  - ✅ No API costs
325
324
  - ✅ Privacy-focused
326
- - ❌ Higher CPU/GPU usage, recommended for machines above 16GB VRAM/RAM
325
+ - ❌ Higher CPU/GPU usage, recommended for machines above 8GB+ VRAM/RAM
327
326
  - ❌ Heavier model, ~9.8gb model
328
327
 
329
328
  ### ⬡ OpenAI GPT
@@ -414,7 +413,7 @@ Any and all consequences are the sole responsibility of the user.
414
413
  ```
415
414
  MIT License
416
415
 
417
- Copyright (c) 2025 EVA - Exploit Vector Agent
416
+ Copyright (c) 2026 EVA - Exploit Vector Agent
418
417
 
419
418
  Permission is hereby granted, free of charge, to any person obtaining a copy
420
419
  of this software and associated documentation files (the "Software"), to deal
@@ -450,7 +449,7 @@ SOFTWARE.
450
449
  <a href='https://ko-fi.com/J3J7WTYV7' target='_blank'><img height='36' style='border:0px;height:36px;' src='https://storage.ko-fi.com/cdn/kofi3.png?v=6' border='0' alt='Buy Me a Coffee at ko-fi.com' /></a>
451
450
  <br>
452
451
  <strong>Hack the world. Byte by Byte.</strong> ⛛ <br>
453
- 𝝺𝗿𝗰𝗮𝗻𝗴𝗲𝗹𝗼 @ 2025
452
+ 𝝺𝗿𝗰𝗮𝗻𝗴𝗲𝗹𝗼 @ 2026
454
453
 
455
454
  **[[ꋧ]](#-𝝣𝗩𝝠)**
456
455
 
@@ -130,20 +130,23 @@ graph TD
130
130
 
131
131
  ### 🍎 Installation
132
132
 
133
+ #### Ollama for local endpoint (required for local models and eva exploit database)
133
134
  ```bash
134
- # Ollama for local endpoint (required for local models and eva exploit database)
135
135
  curl -fsSL https://ollama.ai/install.sh | shr
136
+ ```
136
137
 
137
- # pip installation
138
+ #### pip installation
139
+ ```bash
138
140
  pip install eva-exploit
139
141
  eva
142
+ ```
140
143
 
141
- # EVA installation
144
+ #### EVA github installation
145
+ ```bash
142
146
  git clone https://github.com/ARCANGEL0/EVA.git
143
147
  cd EVA
144
148
  chmod +x eva.py
145
149
  ./eva.py
146
-
147
150
  # Adding it to PATH to be acessible anywhere
148
151
  sudo mv eva.py /usr/local/bin/eva
149
152
  ```
@@ -174,14 +177,10 @@ eva --config
174
177
  │ ├── report1.html
175
178
  │ ├── report1.pdf
176
179
  │ └── ...
177
- ├── attack_maps/ # Attack vector maps in HTML/JS
178
- ├── attack_surface1.html
179
- ├── attack_surface2.html
180
- └── ...
181
- ├── utils/
182
- ├── modules/
183
- ├── eva
184
- └── config.py # API keys (auto-generated/persisted)
180
+ └── attack_maps/ # Attack vector maps in HTML/JS
181
+ ├── attack_surface1.html
182
+ ├── attack_surface2.html
183
+ └── ...
185
184
  ```
186
185
 
187
186
  ### ꀬ Where to change EVA options
@@ -307,11 +306,11 @@ Let me start with basic system reconnaissance to understand the target better...
307
306
  <summary><h2>Ξ AI Backends</h2></summary>
308
307
 
309
308
  ### 🦙 Ollama (Recommended)
310
- - **Model**: `jimscard/whiterabbit-neo:latest` (best one for OffSec)
309
+ - **Model**: `ALIENTELLIGENCE/whiterabbitv2"` (best one for OffSec)
311
310
  - ✅ Complete offline operation
312
311
  - ✅ No API costs
313
312
  - ✅ Privacy-focused
314
- - ❌ Higher CPU/GPU usage, recommended for machines above 16GB VRAM/RAM
313
+ - ❌ Higher CPU/GPU usage, recommended for machines above 8GB+ VRAM/RAM
315
314
  - ❌ Heavier model, ~9.8gb model
316
315
 
317
316
  ### ⬡ OpenAI GPT
@@ -402,7 +401,7 @@ Any and all consequences are the sole responsibility of the user.
402
401
  ```
403
402
  MIT License
404
403
 
405
- Copyright (c) 2025 EVA - Exploit Vector Agent
404
+ Copyright (c) 2026 EVA - Exploit Vector Agent
406
405
 
407
406
  Permission is hereby granted, free of charge, to any person obtaining a copy
408
407
  of this software and associated documentation files (the "Software"), to deal
@@ -438,7 +437,7 @@ SOFTWARE.
438
437
  <a href='https://ko-fi.com/J3J7WTYV7' target='_blank'><img height='36' style='border:0px;height:36px;' src='https://storage.ko-fi.com/cdn/kofi3.png?v=6' border='0' alt='Buy Me a Coffee at ko-fi.com' /></a>
439
438
  <br>
440
439
  <strong>Hack the world. Byte by Byte.</strong> ⛛ <br>
441
- 𝝺𝗿𝗰𝗮𝗻𝗴𝗲𝗹𝗼 @ 2025
440
+ 𝝺𝗿𝗰𝗮𝗻𝗴𝗲𝗹𝗼 @ 2026
442
441
 
443
442
  **[[ꋧ]](#-𝝣𝗩𝝠)**
444
443
 
@@ -10,10 +10,11 @@ from pathlib import Path
10
10
 
11
11
  # ================= CONFIG =================
12
12
  APP_NAME = "EVA"
13
- APP_VERSION = "3.3"
13
+ APP_VERSION = "3.3.1"
14
14
  GITHUB_REPO = "arcangel0/EVA"
15
15
  PYPI_PACKAGE = "eva-exploit"
16
- API_ENDPOINT = "NOT_SET" # <--- change to your desired endpoint if needed
16
+ API_ENDPOINT = "https://api.arcangelo.net/api"
17
+ CUSTOM_API_HANDLER = "custom.py"
17
18
  G4F_MODEL="gpt-oss-120b"
18
19
  G4F_URL="https://api.gpt4free.workers.dev/api/novaai/chat/completions"
19
20
  OLLAMA_MODEL = "ALIENTELLIGENCE/whiterabbitv2" # recommended ollama model
@@ -35,6 +35,7 @@ from utils.system import (
35
35
  checkOpenAIKey,
36
36
  checkupdts,
37
37
  command_exists,
38
+ configure_custom_api,
38
39
  get_current_version,
39
40
  model_exists,
40
41
  ollama_running,
@@ -83,6 +84,7 @@ def main():
83
84
  return
84
85
 
85
86
  if sel == len(sessions) + 2:
87
+ print("\n")
86
88
  cyber("[+] Leaving EVA", color=Fore.RED)
87
89
  time.sleep(1.2)
88
90
  raise SystemExit(0)
@@ -164,6 +166,8 @@ def cli():
164
166
  parser.add_argument("-v", "--version", action="store_true", help="Show EVA version")
165
167
  parser.add_argument("-d", "--delete", action="store_true", help="Delete stored sessions & files")
166
168
  parser.add_argument("-c", "--config", action="store_true", help="Open EVA config.py in your default editor")
169
+ parser.add_argument("--custom-api", action="store_true", help="Open custom API configuration wizard")
170
+ parser.add_argument("-cfg", action="store_true", help="Open custom API configuration wizard")
167
171
  parser.add_argument(
168
172
  "-s",
169
173
  "--search",
@@ -180,6 +184,9 @@ def cli():
180
184
  color = Fore.GREEN if ok else Fore.RED
181
185
  cyber(msg, color=color)
182
186
  raise SystemExit(0 if ok else 1)
187
+ if args.custom_api or args.cfg:
188
+ ok = configure_custom_api(open_handler=True)
189
+ raise SystemExit(0 if ok else 1)
183
190
 
184
191
  if args.search is not None:
185
192
  query = " ".join(args.search).strip()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: eva-exploit
3
- Version: 3.3
3
+ Version: 3.3.1
4
4
  Summary: Exploit Vector Agent
5
5
  Author: ARCANGEL0
6
6
  License: MIT
@@ -142,20 +142,23 @@ graph TD
142
142
 
143
143
  ### 🍎 Installation
144
144
 
145
+ #### Ollama for local endpoint (required for local models and eva exploit database)
145
146
  ```bash
146
- # Ollama for local endpoint (required for local models and eva exploit database)
147
147
  curl -fsSL https://ollama.ai/install.sh | shr
148
+ ```
148
149
 
149
- # pip installation
150
+ #### pip installation
151
+ ```bash
150
152
  pip install eva-exploit
151
153
  eva
154
+ ```
152
155
 
153
- # EVA installation
156
+ #### EVA github installation
157
+ ```bash
154
158
  git clone https://github.com/ARCANGEL0/EVA.git
155
159
  cd EVA
156
160
  chmod +x eva.py
157
161
  ./eva.py
158
-
159
162
  # Adding it to PATH to be acessible anywhere
160
163
  sudo mv eva.py /usr/local/bin/eva
161
164
  ```
@@ -186,14 +189,10 @@ eva --config
186
189
  │ ├── report1.html
187
190
  │ ├── report1.pdf
188
191
  │ └── ...
189
- ├── attack_maps/ # Attack vector maps in HTML/JS
190
- ├── attack_surface1.html
191
- ├── attack_surface2.html
192
- └── ...
193
- ├── utils/
194
- ├── modules/
195
- ├── eva
196
- └── config.py # API keys (auto-generated/persisted)
192
+ └── attack_maps/ # Attack vector maps in HTML/JS
193
+ ├── attack_surface1.html
194
+ ├── attack_surface2.html
195
+ └── ...
197
196
  ```
198
197
 
199
198
  ### ꀬ Where to change EVA options
@@ -319,11 +318,11 @@ Let me start with basic system reconnaissance to understand the target better...
319
318
  <summary><h2>Ξ AI Backends</h2></summary>
320
319
 
321
320
  ### 🦙 Ollama (Recommended)
322
- - **Model**: `jimscard/whiterabbit-neo:latest` (best one for OffSec)
321
+ - **Model**: `ALIENTELLIGENCE/whiterabbitv2"` (best one for OffSec)
323
322
  - ✅ Complete offline operation
324
323
  - ✅ No API costs
325
324
  - ✅ Privacy-focused
326
- - ❌ Higher CPU/GPU usage, recommended for machines above 16GB VRAM/RAM
325
+ - ❌ Higher CPU/GPU usage, recommended for machines above 8GB+ VRAM/RAM
327
326
  - ❌ Heavier model, ~9.8gb model
328
327
 
329
328
  ### ⬡ OpenAI GPT
@@ -414,7 +413,7 @@ Any and all consequences are the sole responsibility of the user.
414
413
  ```
415
414
  MIT License
416
415
 
417
- Copyright (c) 2025 EVA - Exploit Vector Agent
416
+ Copyright (c) 2026 EVA - Exploit Vector Agent
418
417
 
419
418
  Permission is hereby granted, free of charge, to any person obtaining a copy
420
419
  of this software and associated documentation files (the "Software"), to deal
@@ -450,7 +449,7 @@ SOFTWARE.
450
449
  <a href='https://ko-fi.com/J3J7WTYV7' target='_blank'><img height='36' style='border:0px;height:36px;' src='https://storage.ko-fi.com/cdn/kofi3.png?v=6' border='0' alt='Buy Me a Coffee at ko-fi.com' /></a>
451
450
  <br>
452
451
  <strong>Hack the world. Byte by Byte.</strong> ⛛ <br>
453
- 𝝺𝗿𝗰𝗮𝗻𝗴𝗲𝗹𝗼 @ 2025
452
+ 𝝺𝗿𝗰𝗮𝗻𝗴𝗲𝗹𝗼 @ 2026
454
453
 
455
454
  **[[ꋧ]](#-𝝣𝗩𝝠)**
456
455
 
@@ -6,19 +6,23 @@
6
6
  # ---------------------------------------------------------------------
7
7
 
8
8
  import json
9
+ import importlib.util
9
10
  import os
10
11
  import re
11
12
  import subprocess
12
13
  import time
14
+ from pathlib import Path
13
15
 
14
16
  import openai
15
17
  import requests
16
18
  from colorama import Fore, Style
19
+ import config as config_module
17
20
 
18
21
  from config import (
19
22
  ANTHROPIC_MODEL,
20
23
  ANTHROPIC_API_KEY,
21
24
  API_ENDPOINT,
25
+ CUSTOM_API_HANDLER,
22
26
  G4F_MODEL,
23
27
  G4F_URL,
24
28
  GEMINI_API_KEY,
@@ -477,7 +481,40 @@ def _query_g4f(history):
477
481
 
478
482
 
479
483
  def _query_custom_api(history):
480
- r = requests.post(API_ENDPOINT, json={"conversation": history}, timeout=None)
484
+ endpoint = str(getattr(config_module, "API_ENDPOINT", API_ENDPOINT) or "").strip()
485
+ handler_path = str(getattr(config_module, "CUSTOM_API_HANDLER", CUSTOM_API_HANDLER) or "").strip()
486
+
487
+ if handler_path and handler_path != "NOT_SET":
488
+ try:
489
+ target = Path(handler_path).expanduser()
490
+ if target.exists():
491
+ mod_name = f"eva_custom_api_{abs(hash(str(target.resolve())))}"
492
+ spec = importlib.util.spec_from_file_location(mod_name, str(target))
493
+ if spec and spec.loader:
494
+ module = importlib.util.module_from_spec(spec)
495
+ spec.loader.exec_module(module)
496
+ query_fn = getattr(module, "query_custom_api", None)
497
+ if callable(query_fn):
498
+ try:
499
+ result = query_fn(history=history, endpoint=endpoint)
500
+ except TypeError:
501
+ try:
502
+ result = query_fn(history, endpoint)
503
+ except TypeError:
504
+ result = query_fn(history)
505
+ if isinstance(result, (dict, list)):
506
+ return json.dumps(result)
507
+ if result is None:
508
+ return ""
509
+ return str(result)
510
+ except Exception as e:
511
+ print(Fore.RED + f"⚠️ Error in custom API handler: {e}")
512
+
513
+ if not endpoint or endpoint == "NOT_SET":
514
+ print(Fore.RED + "⚠️ Custom API endpoint is not configured.")
515
+ return ""
516
+
517
+ r = requests.post(endpoint, json={"conversation": history}, timeout=None)
481
518
  return r.text
482
519
 
483
520
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "eva-exploit"
7
- version = "3.3"
7
+ version = "3.3.1"
8
8
  description = "Exploit Vector Agent"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -27,6 +27,8 @@ from config import (
27
27
  API_ENDPOINT,
28
28
  APP_NAME,
29
29
  APP_VERSION,
30
+ CONFIG_DIR,
31
+ CUSTOM_API_HANDLER,
30
32
  GEMINI_API_KEY,
31
33
  OLLAMA_MODEL,
32
34
  OPENAI_API_KEY,
@@ -40,11 +42,104 @@ from utils.ui import clear, cyber
40
42
  # Utility functions such as ApiKEY verifier and signal handler
41
43
  # ═══════════════════════════════════════════════════════════════
42
44
  def checkAPI():
43
- if API_ENDPOINT == "NOT_SET":
44
- print(Fore.RED + "\nNo custom API set. Please configure in source code at API_ENPOINT")
45
+ endpoint = str(getattr(config_module, "API_ENDPOINT", API_ENDPOINT) or "").strip()
46
+ handler = str(getattr(config_module, "CUSTOM_API_HANDLER", CUSTOM_API_HANDLER) or "").strip()
47
+ endpoint_ok = endpoint and endpoint != "NOT_SET"
48
+ handler_ok = handler and handler != "NOT_SET"
49
+ if not endpoint_ok and not handler_ok:
50
+ configure_custom_api(open_handler=True)
51
+ endpoint = str(getattr(config_module, "API_ENDPOINT", API_ENDPOINT) or "").strip()
52
+ handler = str(getattr(config_module, "CUSTOM_API_HANDLER", CUSTOM_API_HANDLER) or "").strip()
53
+ endpoint_ok = endpoint and endpoint != "NOT_SET"
54
+ handler_ok = handler and handler != "NOT_SET"
55
+ if not endpoint_ok and not handler_ok:
56
+ print(Fore.RED + "\nNo custom API set. Configure it with eva --custom-api")
45
57
  sys.exit(0)
46
58
 
47
59
 
60
+ def _default_custom_api_handler_path():
61
+ return Path(CONFIG_DIR).expanduser().resolve() / "custom_api_handler.py"
62
+
63
+
64
+ def _custom_api_template(endpoint):
65
+ target = str(endpoint or "").strip()
66
+ if not target or target == "NOT_SET":
67
+ target = "http://127.0.0.1:8000/gpt4"
68
+ return (
69
+ "#!/usr/bin/env python3\n"
70
+ "import requests\n\n"
71
+ f"API_ENDPOINT = {json.dumps(target)}\n\n"
72
+ "def query_custom_api(history, endpoint=None):\n"
73
+ " target = endpoint or API_ENDPOINT\n"
74
+ " question = \"\"\n"
75
+ " for item in reversed(history):\n"
76
+ " if item.get(\"role\") == \"user\":\n"
77
+ " question = str(item.get(\"content\", \"\"))\n"
78
+ " break\n"
79
+ " payload = {\"prompt\": question, \"session\": \"eva-session\"}\n"
80
+ " r = requests.post(target, json=payload, timeout=None)\n"
81
+ " try:\n"
82
+ " data = r.json()\n"
83
+ " except ValueError:\n"
84
+ " return r.text\n"
85
+ " if isinstance(data, dict):\n"
86
+ " for key in (\"analysis\", \"response\", \"answer\", \"text\", \"content\", \"message\"):\n"
87
+ " value = data.get(key)\n"
88
+ " if isinstance(value, str) and value.strip():\n"
89
+ " return value\n"
90
+ " return str(data)\n"
91
+ )
92
+
93
+
94
+ def _ensure_custom_api_handler_file(path, endpoint):
95
+ target = Path(path).expanduser()
96
+ target.parent.mkdir(parents=True, exist_ok=True)
97
+ if not target.exists():
98
+ target.write_text(_custom_api_template(endpoint), encoding="utf-8")
99
+ return target
100
+
101
+
102
+ def configure_custom_api(open_handler=True):
103
+ endpoint_current = str(getattr(config_module, "API_ENDPOINT", API_ENDPOINT) or "").strip()
104
+ if endpoint_current == "NOT_SET":
105
+ endpoint_current = ""
106
+ handler_current = str(getattr(config_module, "CUSTOM_API_HANDLER", CUSTOM_API_HANDLER) or "").strip()
107
+ if not handler_current or handler_current == "NOT_SET":
108
+ handler_current = str(_default_custom_api_handler_path())
109
+
110
+ clear()
111
+ cyber("CUSTOM API CONFIGURATION", color=Fore.CYAN)
112
+ endpoint_input = input(f"Custom API endpoint [{endpoint_current}] > ").strip()
113
+ endpoint_value = endpoint_input or endpoint_current or "NOT_SET"
114
+ _persist_key_to_config("API_ENDPOINT", endpoint_value)
115
+ setattr(config_module, "API_ENDPOINT", endpoint_value)
116
+
117
+ handler_input = input(f"Custom API handler file [{handler_current}] > ").strip()
118
+ handler_value = handler_input or handler_current
119
+ _persist_key_to_config("CUSTOM_API_HANDLER", handler_value)
120
+ setattr(config_module, "CUSTOM_API_HANDLER", handler_value)
121
+
122
+ try:
123
+ handler_path = _ensure_custom_api_handler_file(handler_value, endpoint_value)
124
+ except OSError:
125
+ fallback_handler = Path(config_module.__file__).resolve().parent / "custom_api_handler.py"
126
+ handler_value = str(fallback_handler)
127
+ _persist_key_to_config("CUSTOM_API_HANDLER", handler_value)
128
+ setattr(config_module, "CUSTOM_API_HANDLER", handler_value)
129
+ try:
130
+ handler_path = _ensure_custom_api_handler_file(handler_value, endpoint_value)
131
+ except OSError as exc:
132
+ cyber(f"Could not prepare custom API handler: {exc}", color=Fore.RED)
133
+ return False
134
+
135
+ if open_handler:
136
+ ok, msg = open_in_default_editor(handler_path)
137
+ color = Fore.GREEN if ok else Fore.YELLOW
138
+ cyber(msg, color=color)
139
+
140
+ return True
141
+
142
+
48
143
  def _read_key(name, config_value):
49
144
  env_key = os.getenv(name, "").strip()
50
145
  if env_key:
@@ -201,7 +296,7 @@ def run_self_update():
201
296
  updated = False
202
297
 
203
298
  pip_result = subprocess.run(
204
- ["sudo",sys.executable, "-m", "pip", "install", "--upgrade", PYPI_PACKAGE],
299
+ [sys.executable, "-m", "pip", "install", "--upgrade", PYPI_PACKAGE,"--break-system-packages"],
205
300
  text=True
206
301
  )
207
302
  if pip_result.returncode == 0:
@@ -291,11 +386,11 @@ def open_in_default_editor(path):
291
386
  if sys.stdin.isatty() and sys.stdout.isatty():
292
387
  proc = subprocess.run([*editor_args, str(target)])
293
388
  if proc.returncode == 0:
294
- return True, f"Edited with $EDITOR: {target}"
295
- return False, f"$EDITOR exited with status {proc.returncode}"
389
+ return True, f"::EVA Configuration Saved"
390
+ return False, f":: Error [{proc.returncode}]::"
296
391
  else:
297
392
  subprocess.Popen([*editor_args, str(target)])
298
- return True, f"Opened with $EDITOR: {target}"
393
+ return True, f"::Opened EVA config files::"
299
394
  except OSError:
300
395
  pass
301
396
 
File without changes
File without changes
File without changes