Rework core integration: validated capability layer, docs, and session state

This commit is contained in:
Fisto
2026-09-11 14:09:04 +02:00
parent 2a15f057df
commit e62d3007d8
33 changed files with 1897 additions and 612 deletions
+36 -83
View File
@@ -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`).