Add headless puppet bridge: control socket, renderer handlers, MCP daemon
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
# Veskslop Phase 0 spikes
|
||||
|
||||
Timeboxed proof-of-concept scripts, not production code. Project direction lives in
|
||||
[../AGENTS.md](../AGENTS.md).
|
||||
|
||||
## Setup
|
||||
|
||||
```sh
|
||||
pnpm install
|
||||
```
|
||||
|
||||
## Current query policy
|
||||
|
||||
- Every command sent to the client is spaced by a random **500–2800 ms** and serialized through one
|
||||
queue (`src/pacing.ts`).
|
||||
- Identical concurrent reads are coalesced (`dedupe`), and state reads are cache-only.
|
||||
- `DEBUG=1` logs every command and its delay.
|
||||
|
||||
## Spikes
|
||||
|
||||
### 0. QR login / token acquisition — `src/qr-login.ts`
|
||||
|
||||
```sh
|
||||
pnpm poc:qr
|
||||
TOKEN_FILE=/path/to/token DEBUG=1 pnpm poc:qr
|
||||
```
|
||||
|
||||
Connects to `wss://remote-auth-gateway.discord.gg/?v=2`, renders the approval QR directly in the
|
||||
terminal, waits for a phone scan, exchanges the login ticket and writes the token to
|
||||
`poc/.token` (mode 600, gitignored; override with `TOKEN_FILE`). No existing token required.
|
||||
If Discord responds with an hCaptcha challenge, the script prints the challenge and prompts for a
|
||||
`HCAPTCHA_KEY` (or takes it from the environment).
|
||||
|
||||
### 1. Vesktop control bridge — `src/control-bridge.ts`
|
||||
|
||||
The MCP daemon. Exposes Streamable HTTP and forwards tool calls over the JSON-lines protocol on
|
||||
Vesktop's control socket (default `$XDG_RUNTIME_DIR/vesktop.sock`, override with `VESKSLOP_SOCKET`).
|
||||
|
||||
```sh
|
||||
pnpm control:bridge # http://127.0.0.1:8788/mcp
|
||||
VESKSLOP_SOCKET=... MCP_PORT=... pnpm control:bridge
|
||||
```
|
||||
|
||||
Tools: `get_state` (cache-only), `send_message`, `read_messages` (coalesced), `send_dm`.
|
||||
|
||||
Vesktop side lives in this repo:
|
||||
|
||||
- `src/main/ipcSocket.ts` — parses JSON lines `{ id, command, data }` and forwards them through
|
||||
`sendRendererCommand`.
|
||||
- `src/renderer/ipcCommands.ts` — handlers that use official client interactions (`sendMessage`,
|
||||
`openPrivateChannel`, guild/channel/message stores).
|
||||
|
||||
Protocol commands: `ping`, `state:get`, `message:send`, `message:read`, `dm:send`.
|
||||
|
||||
### 2. Mock Vesktop — `src/mock-vesktop.ts`
|
||||
|
||||
```sh
|
||||
VESKSLOP_SOCKET=/tmp/veskslop-mock.sock pnpm control:mock
|
||||
```
|
||||
|
||||
Stands in for the real Vesktop process so the bridge can be developed without Electron/Xvfb.
|
||||
|
||||
### 3. Live DM test — `src/test-dm.ts`
|
||||
|
||||
```sh
|
||||
TEST_DM_USER_ID=... pnpm poc:dm
|
||||
```
|
||||
|
||||
Talks to a **real** running Vesktop's control socket and sends one paced DM. The only sanctioned
|
||||
live-send target is user **zzib** (provide their user ID).
|
||||
|
||||
## Verified
|
||||
|
||||
- QR login works end-to-end; the token in `.token` came from a phone scan.
|
||||
- MCP bridge path: `initialize`, `tools/list`, `get_state`, `send_message`, `read_messages`,
|
||||
`send_dm` all round-trip correctly through the mock.
|
||||
- Pacing observed live: consecutive commands reached the mock **592 ms**, **1862 ms** and
|
||||
**1439 ms** apart — inside the 500–2800 ms window.
|
||||
|
||||
## Deferred (not testable in this container)
|
||||
|
||||
- Real renderer handlers against a live Discord session (needs Electron + display).
|
||||
- Headless display strategy (Xvfb/offscreen) and client lightening.
|
||||
- Token injection into the official client.
|
||||
- Voice join/leave and audio/video pipelines (need a voice channel; ffmpeg/PipeWire absent).
|
||||
- Remote client auth over LAN/Tailscale and the web debug UI.
|
||||
|
||||
## Findings
|
||||
|
||||
- Official `discord.js` is bot-only (`/gateway/bot` → 401 with a user token), and
|
||||
`discord.js-selfbot-v13` is archived — do not build on either. The core is the real Vesktop
|
||||
client, puppeted through its own interactions.
|
||||
- MCP SDK `1.30.0` stateless Streamable HTTP works as used here.
|
||||
- Vesktop's existing `sendRendererCommand`/`onIpcCommand` bus is enough to puppet interactions; the
|
||||
socket only needed a JSON-lines framing and a command map.
|
||||
- pnpm 11: this folder is its own workspace root; build approvals live in `pnpm-workspace.yaml`
|
||||
(`allowBuilds`).
|
||||
Reference in New Issue
Block a user