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
|
- 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.
|
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
|
## How to proceed
|
||||||
|
|
||||||
**Current milestone — puppeting bridge (testable without Electron).**
|
**Current milestone — puppeting bridge (testable without Electron).**
|
||||||
@@ -101,7 +121,7 @@ MCP clients (agents) ──Streamable HTTP──▶ veskSlop control daemon
|
|||||||
|
|
||||||
## Open questions
|
## 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.
|
- 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.
|
- 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.
|
- 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.
|
- 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`,
|
- MCP bridge path: `initialize`, `tools/list`, `get_state`, `send_message`, `read_messages`,
|
||||||
`send_dm` all round-trip correctly through the mock.
|
`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
|
- Pacing observed live: consecutive commands reached the mock **592 ms**, **1862 ms** and
|
||||||
**1439 ms** apart — inside the 500–2800 ms window.
|
**1439 ms** apart — inside the 500–2800 ms window.
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -129,10 +129,10 @@ if (!app.requestSingleInstanceLock({ IS_DEV })) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function bootstrap() {
|
async function bootstrap() {
|
||||||
if (!Object.hasOwn(State.store, "firstLaunch")) {
|
if (process.env.VESKSLOP_HEADLESS === "1" || Object.hasOwn(State.store, "firstLaunch")) {
|
||||||
createFirstLaunchTour();
|
|
||||||
} else {
|
|
||||||
createWindows();
|
createWindows();
|
||||||
|
} else {
|
||||||
|
createFirstLaunchTour();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ onIpcCommand(IpcCommands.MESSAGE_SEND, async (data: { channelId?: string; conten
|
|||||||
throw new Error("message:send requires { channelId, content }");
|
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 };
|
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`);
|
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 };
|
return { userId: data.userId, channelId, sent: true };
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user