Rework core integration: validated capability layer, docs, and session state
This commit is contained in:
+36
-83
@@ -1,7 +1,8 @@
|
||||
# Veskslop Phase 0 spikes
|
||||
# Veskslop daemon
|
||||
|
||||
Timeboxed proof-of-concept scripts, not production code. Project direction lives in
|
||||
[../AGENTS.md](../AGENTS.md).
|
||||
The external daemon and the development spikes. The daemon holds all logic and exposes MCP.
|
||||
|
||||
Read the project docs first: [../docs/INDEX.md](../docs/INDEX.md).
|
||||
|
||||
## Setup
|
||||
|
||||
@@ -9,98 +10,50 @@ Timeboxed proof-of-concept scripts, not production code. Project direction lives
|
||||
pnpm install
|
||||
```
|
||||
|
||||
## Current query policy
|
||||
## Run commands
|
||||
|
||||
- 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.
|
||||
| Command | Purpose |
|
||||
| --- | --- |
|
||||
| `pnpm poc:qr` | QR login. Writes the token file. |
|
||||
| `pnpm control:bridge` | Start the daemon. It listens on `http://127.0.0.1:8788/mcp`. |
|
||||
| `pnpm poc:dm` | Send one test DM to zzib. |
|
||||
| `pnpm test:comm` | Run the unit tests for the pure logic. |
|
||||
| `pnpm cdp:probe` | Check CDP access and event delivery. |
|
||||
| `pnpm check` | Type check the daemon code. |
|
||||
|
||||
## Spikes
|
||||
## Transport
|
||||
|
||||
### 0. QR login / token acquisition — `src/qr-login.ts`
|
||||
The daemon uses Chrome DevTools Protocol at this time. Start the client with
|
||||
`--remote-debugging-port=9222`. The daemon connects to the Discord page and runs the actions in the
|
||||
real client.
|
||||
|
||||
```sh
|
||||
pnpm poc:qr
|
||||
TOKEN_FILE=/path/to/token DEBUG=1 pnpm poc:qr
|
||||
```
|
||||
The target transport is the validated core bridge. See
|
||||
[../docs/core-bridge.md](../docs/core-bridge.md). The daemon logic is the same on both transports.
|
||||
|
||||
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`). This is the **puppet account's**
|
||||
token. 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).
|
||||
## Pacing
|
||||
|
||||
The headless client consumes this file on startup via `VESKSLOP_TOKEN_FILE` (default
|
||||
`<DATA_DIR>/token`, see [../AGENTS.md](../AGENTS.md) → Auth persistence).
|
||||
Every command gets a random delay of 500 to 2800 ms. One queue serializes the commands. The queue
|
||||
coalesces identical concurrent reads. State reads use the cache. `DEBUG=1` logs each command and
|
||||
its delay.
|
||||
|
||||
### 1. Vesktop control bridge — `src/control-bridge.ts`
|
||||
## Live test target
|
||||
|
||||
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
|
||||
pnpm poc:dm
|
||||
TEST_DM_CONTENT="hello" pnpm poc:dm
|
||||
```
|
||||
|
||||
Talks to a **real** running Vesktop's control socket and sends one paced DM. Defaults to the only
|
||||
sanctioned live-send target, user **zzib** (`TEST_DM_USER_ID` overrides).
|
||||
The only permitted live-send target is user zzib. See
|
||||
[../docs/testing.md](../docs/testing.md) for the full setup.
|
||||
|
||||
## 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.
|
||||
- **Live end-to-end (2026-09-11)**: a real Vesktop client was run headless under Xvfb with the
|
||||
token seeded from `~/.config/veskslop/token`. `get_state` returned the real account and 7 guilds,
|
||||
and `send_dm` delivered a real DM to zzib (`sent: true`). Cache-only `read_messages` on that
|
||||
never-opened DM returned zero messages, as expected.
|
||||
- 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.
|
||||
- QR login works end-to-end. The token came from a phone scan.
|
||||
- The CDP transport works. `get_state` returned the real account and 7 guilds. `send_dm` delivered
|
||||
a real DM to zzib.
|
||||
- Pacing stayed inside the 500 to 2800 ms window.
|
||||
|
||||
## 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`
|
||||
- Official `discord.js` is bot-only. It fails at login with a user token. The popular selfbot fork
|
||||
is archived. Do not use either. The core is the real Vesktop client.
|
||||
- MCP SDK `1.30.0` Streamable HTTP works as used here.
|
||||
- CDP gives control and events with no Vesktop patch. Raw CDP has no guardrails. The validated core
|
||||
bridge is the target for this reason.
|
||||
- pnpm 11: this folder is its own workspace root. Build approvals live in `pnpm-workspace.yaml`
|
||||
(`allowBuilds`).
|
||||
|
||||
Reference in New Issue
Block a user