Add headless mode flag and fix queued sends; verify live end-to-end
This commit is contained in:
@@ -55,6 +55,26 @@ direction.
|
||||
- Discord deletes the stored token when it thinks devtools opened; keep Vesktop's devtools detector
|
||||
patch (`src/renderer/patches/devtoolsFixes.ts`) so this cannot cause random logouts.
|
||||
|
||||
## Headless run (verified 2026-09-11)
|
||||
|
||||
The real client has been run with no visible window and successfully driven end-to-end:
|
||||
|
||||
```sh
|
||||
Xvfb :99 -screen 0 1280x720x24 &
|
||||
DISPLAY=:99 VESKSLOP_HEADLESS=1 \
|
||||
VESKSLOP_TOKEN_FILE=~/.config/veskslop/token \
|
||||
electron . --no-sandbox --disable-gpu --disable-dev-shm-usage
|
||||
```
|
||||
|
||||
- A display server is still required; Xvfb works.
|
||||
- `VESKSLOP_HEADLESS=1` skips the first-launch tour so the main window is created directly.
|
||||
- The token file is seeded before the client boots (verified: logged in with the puppet account).
|
||||
- Outbound sends must pass `waitForChannelReady = false` (`sendMessage(channelId, data, false)` in
|
||||
`src/renderer/ipcCommands.ts`). Otherwise the client's MessageQueue waits forever for channels
|
||||
that are never opened in a headless session.
|
||||
- `message:read` is cache-only; channels the client never opened return zero messages. A
|
||||
fetch-based read (through the client) is still to be added.
|
||||
|
||||
## How to proceed
|
||||
|
||||
**Current milestone — puppeting bridge (testable without Electron).**
|
||||
@@ -101,7 +121,7 @@ MCP clients (agents) ──Streamable HTTP──▶ veskSlop control daemon
|
||||
|
||||
## Open questions
|
||||
|
||||
- Headless Electron strategy: Xvfb vs offscreen rendering, and what to strip to lighten the client.
|
||||
- What to strip to lighten the client once the daemon path is stable.
|
||||
- Voice/video: what the client's native stack can be driven to do without UI interaction.
|
||||
- Scope and auth model of the future remote proxy client and web debug UI.
|
||||
- How much of the Vesktop Electron tree gets deleted once the daemon is self-sufficient.
|
||||
|
||||
@@ -79,6 +79,10 @@ sanctioned live-send target, user **zzib** (`TEST_DM_USER_ID` overrides).
|
||||
- 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.
|
||||
|
||||
|
||||
+3
-3
@@ -129,10 +129,10 @@ if (!app.requestSingleInstanceLock({ IS_DEV })) {
|
||||
}
|
||||
|
||||
async function bootstrap() {
|
||||
if (!Object.hasOwn(State.store, "firstLaunch")) {
|
||||
createFirstLaunchTour();
|
||||
} else {
|
||||
if (process.env.VESKSLOP_HEADLESS === "1" || Object.hasOwn(State.store, "firstLaunch")) {
|
||||
createWindows();
|
||||
} else {
|
||||
createFirstLaunchTour();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@ onIpcCommand(IpcCommands.MESSAGE_SEND, async (data: { channelId?: string; conten
|
||||
throw new Error("message:send requires { channelId, content }");
|
||||
}
|
||||
|
||||
await sendMessage(data.channelId, { content: data.content });
|
||||
await sendMessage(data.channelId, { content: data.content }, false);
|
||||
return { channelId: data.channelId, sent: true };
|
||||
});
|
||||
|
||||
@@ -115,6 +115,6 @@ onIpcCommand(IpcCommands.DM_SEND, async (data: { userId?: string; content?: stri
|
||||
|
||||
if (!channelId) throw new Error(`No DM channel for user ${data.userId} yet`);
|
||||
|
||||
await sendMessage(channelId, { content: data.content });
|
||||
await sendMessage(channelId, { content: data.content }, false);
|
||||
return { userId: data.userId, channelId, sent: true };
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user