Skip to content

Commit 2361718

Browse files
committed
Merge branch 'remote'
2 parents b94e5ab + 5c7b91f commit 2361718

25 files changed

Lines changed: 1914 additions & 19 deletions

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
- Auto-retry Anthropic streams that end prematurely with empty responses, and auto-continue when response is truncated (e.g. unclosed code blocks).
66
- Fix resume crash when conversation contained server-side tool use (e.g. web search).
7+
- Add remote web control server for browser-based chat observation and control via `web.eca.dev`. #333
78

89
## 0.115.5
910

docs/config.json

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,41 @@
332332
]
333333
}
334334
},
335+
"remote": {
336+
"type": "object",
337+
"description": "Remote web control server configuration. When enabled, starts an embedded HTTP server allowing a web frontend (web.eca.dev) to observe and control chat sessions in real-time.",
338+
"markdownDescription": "Remote web control server configuration. When enabled, starts an embedded HTTP server allowing a web frontend (`web.eca.dev`) to observe and control chat sessions in real-time.",
339+
"additionalProperties": false,
340+
"properties": {
341+
"enabled": {
342+
"type": "boolean",
343+
"description": "Enables the remote HTTP server.",
344+
"markdownDescription": "Enables the remote HTTP server."
345+
},
346+
"host": {
347+
"type": "string",
348+
"description": "Host used in the logged URL for web.eca.dev to connect back to. Can be a LAN IP, public IP, domain, or tunnel URL. When unset, auto-detected via InetAddress/getLocalHost.",
349+
"markdownDescription": "Host used in the logged URL for `web.eca.dev` to connect back to. Can be a LAN IP, public IP, domain, or tunnel URL. When unset, auto-detected via `InetAddress/getLocalHost`.",
350+
"examples": [
351+
"192.168.1.42",
352+
"myserver.example.com"
353+
]
354+
},
355+
"port": {
356+
"type": "integer",
357+
"description": "Port the HTTP server listens on. When unset, tries port 7777, then 7778, 7779, etc. up to 10 attempts.",
358+
"markdownDescription": "Port the HTTP server listens on. When unset, tries port `7777`, then `7778`, `7779`, etc. up to 10 attempts.",
359+
"examples": [
360+
7777
361+
]
362+
},
363+
"password": {
364+
"type": "string",
365+
"description": "Auth token for Bearer authentication. When unset, a 32-byte hex token is auto-generated and logged to stderr.",
366+
"markdownDescription": "Auth token for Bearer authentication. When unset, a 32-byte hex token is auto-generated and logged to stderr."
367+
}
368+
}
369+
},
335370
"network": {
336371
"type": "object",
337372
"description": "Network configuration for custom CA certificates and mTLS client certificates. Values support dynamic string interpolation (e.g. '${env:SSL_CERT_FILE}').",

docs/config/remote.md

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
---
2+
description: "Configure ECA Remote: control your ECA session from a web browser via Tailscale or LAN."
3+
---
4+
5+
# Remote
6+
7+
ECA Remote lets you control and observe your ECA session from a web browser. When enabled, ECA starts an embedded HTTP server that a web frontend can connect to in real-time.
8+
9+
## Configuration
10+
11+
```javascript title="~/.config/eca/config.json"
12+
{
13+
"remote": {
14+
"enabled": true,
15+
// optional — useful for specifying custom dns like tailscale or your local ip
16+
"host": "192.168.1.42",
17+
// optional — defaults to 7777 (auto-increments if busy)
18+
"port": 7777,
19+
// optional — a random pass is auto-generated when unset
20+
"password": "my-secret-token"
21+
}
22+
}
23+
```
24+
25+
Minimal setup — just enable it and ECA handles the rest:
26+
27+
```javascript title="~/.config/eca/config.json"
28+
{
29+
"remote": {
30+
"enabled": true
31+
}
32+
}
33+
```
34+
35+
When the server starts, ECA logs the connection URL and auth token to stderr and welcome message. The URL is a deep-link that you can open directly in the browser:
36+
37+
```
38+
https://web.eca.dev?host=192.168.1.42:7777&pass=a3f8b2c1...&protocol=https
39+
```
40+
41+
## Connection Methods
42+
43+
There are three ways to connect the web frontend to your ECA session.
44+
45+
### Direct (LAN / Private IP)
46+
47+
The simplest approach — connect directly from `https://web.eca.dev` to your machine's private IP.
48+
49+
1. Enable remote in your config:
50+
51+
```javascript title="~/.config/eca/config.json"
52+
{
53+
"remote": {
54+
"enabled": true,
55+
"password": "something" // optioal - or ${env:MY_PASS}
56+
}
57+
}
58+
```
59+
60+
2. Start ECA — it will log the connection URL or auth token with random pass.
61+
3. Open `https://web.eca.dev` and enter your machine's LAN IP (e.g. `192.168.1.42`) and password
62+
4. Chrome will show a **Local Network Access** permission prompt — click **Allow**
63+
64+
!!! note "Firewall"
65+
Make sure your firewall allows incoming TCP connections on ports `7777`–`7787` (the default ECA port range) from your LAN.
66+
ECA start using `7777` and so one for each server running in your machine.
67+
68+
### Tailscale / VPN
69+
70+
For a seamless HTTPS-to-HTTPS connection with no browser prompts. [Tailscale](https://tailscale.com) (free) creates a secure private network between your devices with valid HTTPS certificates.
71+
72+
1. Install Tailscale and enable [HTTPS certificates](https://tailscale.com/kb/1153/enabling-https)
73+
2. Set `host` to your machine's Tailscale domain name:
74+
75+
```javascript title="~/.config/eca/config.json"
76+
{
77+
"remote": {
78+
"enabled": true,
79+
"password": "something-here",
80+
"host": "my-machine.tail1234.ts.net" // optional - just to get url easily when starting
81+
}
82+
}
83+
```
84+
85+
3. Start ECA — it will log a connection URL
86+
4. Open `https://web.eca.dev` and paste the connection URL or manually enter host and password
87+
88+
Because Tailscale provides valid HTTPS certificates for your machine, the browser connects without any mixed-content issues or permission prompts.
89+
90+
### Local Docker
91+
92+
If you prefer to keep everything over plain HTTP, you can run the web frontend locally. This avoids all browser security restrictions.
93+
94+
1. Enable remote in your config:
95+
96+
```javascript title="~/.config/eca/config.json"
97+
{
98+
"remote": {
99+
"enabled": true,
100+
"password": "something-here"
101+
}
102+
}
103+
```
104+
105+
2. Run the web frontend locally via Docker, usually in the same machine where server is running:
106+
107+
```bash
108+
docker run --pull=always -p 8080:80 ghcr.io/editor-code-assistant/eca-web
109+
```
110+
111+
3. Start ECA — it will log the connection URL and auth token
112+
4. Open `http://localhost:8080` and paste the connection URL
113+
114+
## Web UI
115+
116+
The web frontend provides a connect form where you enter the host and password (or use the deep-link URL logged by ECA).
117+
118+
**Auto-discovery** — When you enter a host and click "Discover", the web UI scans ports `7777``7787` in parallel and finds all running ECA instances automatically. This is the default port range ECA uses when auto-assigning ports.
119+
120+
**Multi-session** — You can connect to multiple ECA instances simultaneously. Each connection appears as a tab in the top bar, letting you switch between sessions.

docs/overrides/home.html

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1719,6 +1719,13 @@ <h3 class="eca-feature__title">Plugins</h3>
17191719
<p class="eca-feature__desc">Extend ECA with community plugins &mdash; bundles of tools, rules, skills, and more from the marketplace.</p>
17201720
</div>
17211721
</a>
1722+
<a href="config/remote" class="eca-feature">
1723+
<div class="eca-feature__icon">🌐</div>
1724+
<div class="eca-feature__body">
1725+
<h3 class="eca-feature__title">Remote</h3>
1726+
<p class="eca-feature__desc">Observe and control your chat session from a browser via an embedded web server and web.eca.dev.</p>
1727+
</div>
1728+
</a>
17221729
</div>
17231730
</div>
17241731

0 commit comments

Comments
 (0)