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:
parent
f3456bd09d
commit
4676fc2c94
6 changed files with 343 additions and 86 deletions
|
|
@ -25,7 +25,8 @@ export interface SessionInfo {
|
|||
export type DaemonEvent =
|
||||
| { type: "auth_result"; ok: boolean }
|
||||
| { type: "session_created"; session_id: string; pid: number }
|
||||
| { type: "session_output"; session_id: string; data: number[] }
|
||||
/** data is base64-encoded bytes from the PTY. */
|
||||
| { type: "session_output"; session_id: string; data: string }
|
||||
| { type: "session_closed"; session_id: string; exit_code: number | null }
|
||||
| { type: "session_list"; sessions: SessionInfo[] }
|
||||
| { type: "pong" }
|
||||
|
|
@ -131,13 +132,15 @@ export class PtyClient extends EventEmitter {
|
|||
});
|
||||
}
|
||||
|
||||
/** Write input to a session's PTY. */
|
||||
/** Write input to a session's PTY. data is encoded as base64 for transport. */
|
||||
writeInput(sessionId: string, data: string | Uint8Array): void {
|
||||
const bytes =
|
||||
typeof data === "string"
|
||||
? Array.from(new TextEncoder().encode(data))
|
||||
: Array.from(data);
|
||||
this.send({ type: "write_input", session_id: sessionId, data: bytes });
|
||||
? new TextEncoder().encode(data)
|
||||
: data;
|
||||
// Daemon expects base64 string per protocol.rs WriteInput { data: String }
|
||||
const b64 = btoa(String.fromCharCode(...bytes));
|
||||
this.send({ type: "write_input", session_id: sessionId, data: b64 });
|
||||
}
|
||||
|
||||
/** Resize a session's terminal. */
|
||||
|
|
@ -199,10 +202,18 @@ export class PtyClient extends EventEmitter {
|
|||
* terminal.write(new Uint8Array(chunk));
|
||||
* }
|
||||
*/
|
||||
/**
|
||||
* Connect to daemon, create a session, and return output as an async iterator.
|
||||
* Each yielded chunk is a Uint8Array of raw PTY bytes (decoded from base64).
|
||||
* Usage:
|
||||
* for await (const chunk of ptySession("my-shell", { cols: 120, rows: 40 })) {
|
||||
* terminal.write(chunk);
|
||||
* }
|
||||
*/
|
||||
export async function* ptySession(
|
||||
sessionId: string,
|
||||
opts?: { shell?: string; cwd?: string; cols?: number; rows?: number; socketDir?: string }
|
||||
): AsyncGenerator<number[], void, void> {
|
||||
): AsyncGenerator<Uint8Array, void, void> {
|
||||
const client = new PtyClient(opts?.socketDir);
|
||||
await client.connect();
|
||||
|
||||
|
|
@ -222,7 +233,11 @@ export async function* ptySession(
|
|||
});
|
||||
|
||||
if (msg.type === "session_output" && msg.session_id === sessionId) {
|
||||
yield msg.data;
|
||||
// Decode base64 → raw bytes
|
||||
const binary = atob(msg.data);
|
||||
const bytes = new Uint8Array(binary.length);
|
||||
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
||||
yield bytes;
|
||||
} else if (msg.type === "session_closed" && msg.session_id === sessionId) {
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue