feat(electrobun): wire PTY daemon into terminal tabs via Electrobun RPC

- Bun process connects to agor-ptyd via PtyClient (5 retries, exponential backoff)
- RPC bridge: 5 request handlers (create/write/resize/unsubscribe/close)
- Daemon output forwarded to WebView as pty.output messages (base64 passthrough)
- Terminal.svelte: real PTY sessions via RPC instead of echo mode
- Shared RPC schema at src/shared/pty-rpc-schema.ts
- Fixed pty-client.ts protocol: base64 string for data (was number array)
- TerminalTabs passes sessionId to Terminal component
This commit is contained in:
Hibryda 2026-03-20 03:20:13 +01:00
parent f3456bd09d
commit 4676fc2c94
6 changed files with 343 additions and 86 deletions

View file

@ -2,9 +2,39 @@ import "./app.css";
import "@xterm/xterm/css/xterm.css";
import App from "./App.svelte";
import { mount } from "svelte";
import { Electroview } from "electrobun/view";
import type { PtyRPCSchema } from "../shared/pty-rpc-schema.ts";
/**
* Set up Electroview RPC.
*
* The schema is split from the Bun side's perspective:
* - "requests" in PtyRPCSchema = what WE (WebView) call on Bun these become
* methods on electrobun.rpc.request.*
* - "messages" in PtyRPCSchema = what BUN pushes to us we listen via
* electrobun.rpc.addMessageListener(name, handler)
*
* Electroview.defineRPC takes the schema where handlers.requests = what the
* WebView handles (i.e., requests FROM Bun to us). Since Bun never calls us
* with requests (only messages), that section is empty.
*/
const rpc = Electroview.defineRPC<PtyRPCSchema>({
maxRequestTime: 10_000,
handlers: {
requests: {
// No request handlers needed — Bun only pushes messages to us, not requests.
},
messages: {
// These are messages that WE send to Bun (fire-and-forget).
// Empty: WebView doesn't initiate any fire-and-forget messages.
},
},
});
export const electrobun = new Electroview({ rpc });
const app = mount(App, {
target: document.getElementById("app")!,
target: document.getElementById("app")!,
});
export default app;