Update docs for the debug web UI, voice plan, and current status
This commit is contained in:
+147
@@ -0,0 +1,147 @@
|
||||
# Web UI
|
||||
|
||||
The daemon serves the debug web control UI. The owner uses it to observe the account the agent
|
||||
sees, read and send messages, search users, and see voice membership. The shell follows the design
|
||||
handoff in `poc/WebUIMockup.zip`; several panels are roadmap placeholders.
|
||||
|
||||
## Run
|
||||
|
||||
The UI starts with the daemon. No extra command is needed.
|
||||
|
||||
```sh
|
||||
cd poc
|
||||
pnpm control:bridge
|
||||
|
||||
# Page
|
||||
http://<host>:8789/
|
||||
|
||||
# API
|
||||
http://<host>:8789/api/health
|
||||
```
|
||||
|
||||
| Setting | Default | Purpose |
|
||||
| --- | --- | --- |
|
||||
| `WEBUI_HOST` | `0.0.0.0` | Listen address |
|
||||
| `WEBUI_PORT` | `8789` | Listen port |
|
||||
|
||||
## Security
|
||||
|
||||
The UI has **no authentication**. Anyone who can reach the port controls the bot, can start and
|
||||
stop the client, and can start a QR login. Bind the daemon to a private LAN or a Tailscale address
|
||||
only. Do not expose the port to the public internet. See [daemon.md](daemon.md).
|
||||
|
||||
The MCP server stays on `127.0.0.1:8788`. Only the UI binds outside localhost.
|
||||
|
||||
## Page
|
||||
|
||||
- Plain HTML, CSS, and JavaScript in `poc/public/`. No build step and no frontend framework.
|
||||
- The look follows the Nocturne design system (`poc/public/nocturne.css`) from the design handoff
|
||||
in `poc/WebUIMockup.zip`. Implemented screen: **7a**, the docked three-column debug shell.
|
||||
- Layout: 50px header, conditional call strip, `236px | 1fr | 306px` body, and the agent console
|
||||
bar (35px collapsed, resizable drawer expanded).
|
||||
- Header: wordmark, guild picker, health indicators, Takeover switch, Settings.
|
||||
- Left rail: guild switcher, text channels, voice channels with inline participants, direct
|
||||
messages, and the account footer.
|
||||
- Center: channel header, message list, composer, and the TTS panel.
|
||||
- Right column: In voice, Favourites, Open DMs & groups.
|
||||
- Console: Tool calls, Events (live SSE), Transcript. The ticker shows the newest event.
|
||||
- Opening a chat fetches the latest 50 messages from Discord into the client cache. The refresh
|
||||
button by the channel header re-fetches. Live message events read the cache.
|
||||
- Attachments render from their Discord CDN links. Images display inline; other files are link
|
||||
chips. The daemon never downloads or stores attachment bytes.
|
||||
- Avatars and guild icons load from the Discord CDN with a monogram fallback.
|
||||
- Composer and TTS drafts persist in `localStorage` per channel. They survive re-renders, the
|
||||
bridge connecting, and a page reload. A successful send clears the channel draft.
|
||||
- When the bridge connects after the page loaded, the page reloads state without touching drafts.
|
||||
- Roadmap gaps are shown, not hidden: TTS, transcript, tool-call tracing, favourites, and voice
|
||||
join/monitor appear as marked placeholders.
|
||||
|
||||
## Takeover
|
||||
|
||||
Takeover is a read-only switch. Off, the composer is locked (a `read-only` tag sits next to the
|
||||
lock) and the page cannot send. On, the composer unlocks and every manual send is written to the
|
||||
action log as a `manual` entry. The choice is stored in `localStorage`. The setting is client-side
|
||||
only; the API itself does not enforce it.
|
||||
|
||||
## Settings
|
||||
|
||||
The Settings button opens a slide-over with the server-side controls:
|
||||
|
||||
- **Core process** — state, last exit, output, Start / Stop / Restart.
|
||||
- **Account login** — token file state, QR login, captcha.
|
||||
- **Visible guilds** — checkboxes for the guild switcher and picker. Stored in `localStorage`;
|
||||
"Show all" clears the filter.
|
||||
- **Action log** — the persistent JSONL log, newest first.
|
||||
|
||||
## Core process
|
||||
|
||||
The Settings panel starts, stops, and restarts the Vesktop client. The daemon spawns the process
|
||||
from the repo root and labels its output with `[core]` in the daemon log.
|
||||
|
||||
- The default command is `node_modules/.bin/electron .` with
|
||||
`--no-sandbox --disable-gpu --disable-dev-shm-usage`.
|
||||
- Override the command with `VESKSLOP_CORE_CMD` and the flags with `VESKSLOP_CORE_ARGS`.
|
||||
- The spawn sets `VESKSLOP_HEADLESS=1` and points `VESKSLOP_TOKEN_FILE` at the daemon token file.
|
||||
- On Linux without a `DISPLAY`, the daemon starts Xvfb automatically. `VESKSLOP_XVFB=0` disables
|
||||
this. A real `DISPLAY` wins.
|
||||
- Only a process started by the current daemon is managed. An externally started client shows as
|
||||
`external` and cannot be stopped from the UI.
|
||||
- The status shows the last exit code or signal and the last 20 output lines. A failed start is
|
||||
visible on the page instead of only in the daemon log.
|
||||
|
||||
## Login
|
||||
|
||||
The Settings panel runs the same QR flow as `pnpm poc:qr`, with the QR rendered as an image.
|
||||
|
||||
1. Click **Start QR login**. The daemon opens the remote-auth gateway and shows the QR.
|
||||
2. Scan the QR with the Discord mobile app and approve.
|
||||
3. On success the token is written to the token file with mode 600. A running managed core
|
||||
restarts with `VESKSLOP_FORCE_TOKEN=1` so the new account takes effect.
|
||||
4. If Discord asks for a captcha, the panel shows the sitekey and a field for the hCaptcha response
|
||||
token. Paste the token and submit.
|
||||
|
||||
The token never leaves the daemon. The API reports the account name and ID, not the token.
|
||||
|
||||
## API
|
||||
|
||||
The JSON API is the migration boundary. A future frontend calls the same routes. The page code is
|
||||
replaceable.
|
||||
|
||||
| Method | Path | Body or query | Result |
|
||||
| --- | --- | --- | --- |
|
||||
| GET | `/api/health` | none | Core state, process state, owner, uptime, event count, query count |
|
||||
| GET | `/api/core/status` | none | Bridge and core process state |
|
||||
| POST | `/api/core/start` | `forceToken?` | Start the client |
|
||||
| POST | `/api/core/stop` | none | Stop the managed client |
|
||||
| POST | `/api/core/restart` | `forceToken?` | Restart the managed client |
|
||||
| GET | `/api/auth` | none | Token file state and the QR session, with `qrDataUrl` when pending |
|
||||
| POST | `/api/auth/qr` | none | Start a QR login session |
|
||||
| POST | `/api/auth/qr/cancel` | none | Cancel the session |
|
||||
| POST | `/api/auth/qr/captcha` | `key` | Submit an hCaptcha response token |
|
||||
| GET | `/api/state` | none | User, guilds, and channels |
|
||||
| GET | `/api/messages` | `channelId`, `limit`, `refresh?` | Messages from a channel. `refresh=1` fetches the latest from Discord and fills the client cache; otherwise cache-only. |
|
||||
| POST | `/api/messages` | `channelId`, `content` | Send a message. Records a `manual` action. |
|
||||
| POST | `/api/dm` | `userId` or `username`, `content` | Send a DM. Records a `manual` action. |
|
||||
| GET | `/api/users` | `q`, `guildId?`, `limit?` | Search the client user cache |
|
||||
| GET | `/api/dms` | `limit?` | Cached DM and group DM channels with recipients |
|
||||
| GET | `/api/voice` | `userId?`, `guildId?` | One user's voice state |
|
||||
| GET | `/api/voice/overview` | `guildId` | Occupied voice channels and members |
|
||||
| POST | `/api/voice/join` | `channelId` | Reserved. Returns `501` |
|
||||
| POST | `/api/voice/leave` | none | Reserved. Returns `501` |
|
||||
| GET | `/api/logs` | `limit` | The persistent action log |
|
||||
| GET | `/api/events` | none | Server-sent events |
|
||||
|
||||
Every response is JSON: `{ "ok": true, "result": ... }` or `{ "ok": false, "error": "..." }`. A
|
||||
core validation error adds `code`.
|
||||
|
||||
The channel detail routes use the same pacing as the MCP tools. Sends are paced; reads take a small
|
||||
gap. See [daemon.md](daemon.md).
|
||||
|
||||
## Not started
|
||||
|
||||
- Web UI authentication and user accounts.
|
||||
- Voice join and leave. The UI elements exist and call the reserved routes.
|
||||
- TTS playback, transcript capture, and MCP tool-call tracing.
|
||||
- Favourites, presence, member counts, and message editing/deletion/reactions.
|
||||
- Pagination of channel history.
|
||||
- The full DM scope from the mockup: the rail always shows text, voice, and direct lists.
|
||||
Reference in New Issue
Block a user