Skip to content

Commit 34e136f

Browse files
committed
release: merge develop into main for v0.20.3
2 parents 38f573c + f34fb03 commit 34e136f

10 files changed

Lines changed: 262 additions & 110 deletions

File tree

CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,21 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [0.20.3] - 2026-04-13
9+
10+
### Added
11+
12+
- **File tab context menu** — right-click on workspace file tabs for: Close, Close others, Close all to the left, Close all to the right, Close all
13+
- **Scheduler in systemd**`start-services.sh` and `ExecStop` now manage the scheduler process. Restarts properly kill and relaunch the scheduler so `routines.yaml` changes take effect
14+
15+
### Fixed
16+
17+
- **Licensing product slug** — changed `PRODUCT` and `TIER` from `"evonexus"` to `"evo-nexus"` to match the licensing server's product registry. This was causing 400 `INVALID_TIER` on new installations
18+
- **Licensing error logging**`_post()` now logs the server's error body (e.g., `MISSING_FIELD: email is required`) instead of the generic `400 Bad Request`
19+
- **Setup requires email** — the initial setup endpoint now validates that email is provided (required for license registration)
20+
- **Auto-register skips missing email**`auto_register_if_needed()` no longer attempts registration if the admin user has no email
21+
- **Makefile pkill self-kill** — applied `[p]attern` bracket trick to prevent `pkill -f` from matching its own shell process on Linux/WSL (PR #5 by @gomessguii)
22+
823
## [0.20.2] - 2026-04-13
924

1025
### Added

Makefile

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ scheduler: ## ⏰ Start routine scheduler (runs in background)
9494
dashboard-app: ## 🖥️ Start Dashboard App (React + Flask + terminal-server, localhost:8080)
9595
@cd dashboard/frontend && npm install --silent && npm run build
9696
@echo "▶ Starting terminal-server on :32352 (background)..."
97-
@pkill -f "dashboard/terminal-server/bin/server.js" 2>/dev/null || true
97+
@pkill -f "[d]ashboard/terminal-server/bin/server.js" 2>/dev/null || true
9898
@node dashboard/terminal-server/bin/server.js --dev > /tmp/terminal-server.log 2>&1 & echo $$! > /tmp/terminal-server.pid
9999
@trap 'echo "▶ Stopping terminal-server..."; kill $$(cat /tmp/terminal-server.pid) 2>/dev/null; rm -f /tmp/terminal-server.pid' EXIT INT TERM; \
100100
cd dashboard/backend && $(PYTHON) app.py
@@ -103,14 +103,14 @@ terminal-logs: ## 📜 Tail terminal-server logs
103103
@tail -f /tmp/terminal-server.log
104104

105105
terminal-stop: ## 🛑 Stop terminal-server (if orphaned)
106-
@pkill -f "dashboard/terminal-server/bin/server.js" 2>/dev/null && echo "✅ terminal-server stopped" || echo "ℹ terminal-server not running"
106+
@pkill -f "[d]ashboard/terminal-server/bin/server.js" 2>/dev/null && echo "✅ terminal-server stopped" || echo "ℹ terminal-server not running"
107107
@rm -f /tmp/terminal-server.pid
108108

109109
stop: ## 🛑 Stop all EvoNexus services (dashboard + terminal-server)
110110
@echo "Stopping EvoNexus services..."
111-
@pkill -f "dashboard/terminal-server/bin/server.js" 2>/dev/null || true
112-
@pkill -f "dashboard/backend.*app.py" 2>/dev/null || true
113-
@pkill -f "app.py" 2>/dev/null || true
111+
@pkill -f "[d]ashboard/terminal-server/bin/server.js" 2>/dev/null || true
112+
@pkill -f "[d]ashboard/backend.*app.py" 2>/dev/null || true
113+
@pkill -f "[a]pp.py" 2>/dev/null || true
114114
@echo "✅ All services stopped"
115115

116116
uninstall: ## 🗑️ Full cleanup — stop services, remove nginx, data, deps (DESTRUCTIVE)
@@ -128,9 +128,9 @@ uninstall: ## 🗑️ Full cleanup — stop services, remove nginx, da
128128
if [ "$$confirm" = "UNINSTALL" ]; then \
129129
echo ""; \
130130
echo "Stopping services..."; \
131-
pkill -f "dashboard/terminal-server/bin/server.js" 2>/dev/null || true; \
132-
pkill -f "dashboard/backend.*app.py" 2>/dev/null || true; \
133-
pkill -f "app.py" 2>/dev/null || true; \
131+
pkill -f "[d]ashboard/terminal-server/bin/server.js" 2>/dev/null || true; \
132+
pkill -f "[d]ashboard/backend.*app.py" 2>/dev/null || true; \
133+
pkill -f "[a]pp.py" 2>/dev/null || true; \
134134
echo "Removing nginx config..."; \
135135
rm -f /etc/nginx/sites-enabled/evonexus 2>/dev/null || true; \
136136
systemctl reload nginx 2>/dev/null || true; \
@@ -205,8 +205,8 @@ backup-s3: ## ☁️ Backup workspace data to local ZIP + S3 upload
205205

206206
restore: ## 📥 Restore workspace from backup ZIP: make restore FILE=<path> [MODE=merge|replace]
207207
@echo "▶ Stopping services before restore..."
208-
@pkill -f "dashboard/terminal-server/bin/server.js" 2>/dev/null || true
209-
@pkill -f "app.py" 2>/dev/null || true
208+
@pkill -f "[d]ashboard/terminal-server/bin/server.js" 2>/dev/null || true
209+
@pkill -f "[a]pp.py" 2>/dev/null || true
210210
@sleep 1
211211
$(PYTHON) backup.py restore $(FILE) --mode $(or $(MODE),merge)
212212
@echo "▶ Restarting services..."

cli/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@evoapi/evo-nexus",
3-
"version": "0.20.2",
3+
"version": "0.20.3",
44
"description": "Unofficial open source toolkit for Claude Code — AI-powered business operating system",
55
"keywords": [
66
"claude-code",

dashboard/backend/licensing.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@
2020
logger = logging.getLogger("licensing")
2121

2222
LICENSING_SERVER = "https://license.evolutionfoundation.com.br"
23-
PRODUCT = "evonexus"
24-
TIER = "evonexus"
23+
PRODUCT = "evo-nexus"
24+
TIER = "evo-nexus"
2525
TIMEOUT = 10
2626

2727

@@ -103,7 +103,12 @@ def _post(path: str, payload: dict, api_key: str | None = None) -> dict:
103103
headers["Authorization"] = f"HMAC {signature}"
104104

105105
resp = requests.post(url, data=body, headers=headers, timeout=TIMEOUT)
106-
resp.raise_for_status()
106+
if not resp.ok:
107+
try:
108+
detail = resp.json().get("detail", resp.text[:200])
109+
except Exception:
110+
detail = resp.text[:200]
111+
raise requests.HTTPError(f"{resp.status_code} {resp.reason}: {detail}", response=resp)
107112
return resp.json()
108113

109114

@@ -270,7 +275,7 @@ def auto_register_if_needed():
270275
return
271276

272277
admin = User.query.filter_by(role="admin").first()
273-
if not admin:
278+
if not admin or not admin.email:
274279
return
275280

276281
if not instance_id:

dashboard/backend/routes/auth_routes.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ def setup():
4747

4848
if not username or not password:
4949
abort(400, description="Username and password are required")
50+
if not email:
51+
abort(400, description="Email is required for license registration")
5052
if len(password) < 6:
5153
abort(400, description="Password must be at least 6 characters")
5254

0 commit comments

Comments
 (0)