- SidecarManager: spawns claude/codex/ollama runners via Bun.spawn(), NDJSON stdio protocol, Claude CLI auto-detection, env stripping, AbortController stop, Deno/Node runtime detection - MessageAdapter: parses Claude stream-json, Codex ThreadEvent, Ollama chunks into common AgentMessage format - agent-store.svelte.ts: per-project reactive session state, RPC event listeners for agent.message/status/cost - AgentPane: wired to real sessions (start/stop/prompt), stop button, thinking/system message rendering - ProjectCard: status dot from real agent status, cost/tokens from store - 5 new RPC types (agent.start/stop/prompt/list + events)
236 lines
8 KiB
TypeScript
236 lines
8 KiB
TypeScript
/**
|
|
* Shared RPC schema for PTY bridge between Bun process and WebView.
|
|
*
|
|
* Bun holds the Unix socket connection to agor-ptyd; the WebView calls
|
|
* into Bun via requests, and Bun pushes output/close events via messages.
|
|
*/
|
|
|
|
// ── Requests (WebView → Bun, expects a response) ─────────────────────────────
|
|
|
|
export type PtyRPCRequests = {
|
|
/** Create a PTY session and subscribe to its output. */
|
|
"pty.create": {
|
|
params: {
|
|
sessionId: string;
|
|
cols: number;
|
|
rows: number;
|
|
/** Working directory for the shell process. */
|
|
cwd?: string;
|
|
};
|
|
response: { ok: boolean; error?: string };
|
|
};
|
|
/** Write raw input bytes (base64-encoded) to a PTY session. */
|
|
"pty.write": {
|
|
params: {
|
|
sessionId: string;
|
|
/** UTF-8 text typed by the user (xterm onData delivers this). */
|
|
data: string;
|
|
};
|
|
response: { ok: boolean };
|
|
};
|
|
/** Notify the daemon that the terminal dimensions changed. */
|
|
"pty.resize": {
|
|
params: { sessionId: string; cols: number; rows: number };
|
|
response: { ok: boolean };
|
|
};
|
|
/** Unsubscribe from a session's output (session stays alive). */
|
|
"pty.unsubscribe": {
|
|
params: { sessionId: string };
|
|
response: { ok: boolean };
|
|
};
|
|
/** Kill a PTY session. */
|
|
"pty.close": {
|
|
params: { sessionId: string };
|
|
response: { ok: boolean };
|
|
};
|
|
|
|
// ── Settings RPC ───────────────────────────────────────────────────────────
|
|
|
|
/** Get a single setting value by key. Returns null if not set. */
|
|
"settings.get": {
|
|
params: { key: string };
|
|
response: { value: string | null };
|
|
};
|
|
/** Persist a setting key/value pair. */
|
|
"settings.set": {
|
|
params: { key: string; value: string };
|
|
response: { ok: boolean };
|
|
};
|
|
/** Return all settings as a flat object. */
|
|
"settings.getAll": {
|
|
params: Record<string, never>;
|
|
response: { settings: Record<string, string> };
|
|
};
|
|
/** Return all persisted projects. */
|
|
"settings.getProjects": {
|
|
params: Record<string, never>;
|
|
response: { projects: Array<{ id: string; config: string }> };
|
|
};
|
|
/** Persist a project config (JSON-serialised on the caller side). */
|
|
"settings.setProject": {
|
|
params: { id: string; config: string };
|
|
response: { ok: boolean };
|
|
};
|
|
|
|
// ── Custom Themes RPC ──────────────────────────────────────────────────────
|
|
|
|
/** Return all user-saved custom themes. */
|
|
"themes.getCustom": {
|
|
params: Record<string, never>;
|
|
response: { themes: Array<{ id: string; name: string; palette: Record<string, string> }> };
|
|
};
|
|
/** Save (upsert) a custom theme by id. */
|
|
"themes.saveCustom": {
|
|
params: { id: string; name: string; palette: Record<string, string> };
|
|
response: { ok: boolean };
|
|
};
|
|
/** Delete a custom theme by id. */
|
|
"themes.deleteCustom": {
|
|
params: { id: string };
|
|
response: { ok: boolean };
|
|
};
|
|
|
|
// ── Groups RPC ─────────────────────────────────────────────────────────────
|
|
|
|
/** Return all project groups. */
|
|
"groups.list": {
|
|
params: Record<string, never>;
|
|
response: { groups: Array<{ id: string; name: string; icon: string; position: number }> };
|
|
};
|
|
|
|
// ── Project clone RPC ──────────────────────────────────────────────────────
|
|
|
|
/** Clone a project into a git worktree. branchName must match /^[a-zA-Z0-9\/_.-]+$/. */
|
|
"project.clone": {
|
|
params: { projectId: string; branchName: string };
|
|
response: { ok: boolean; project?: { id: string; config: string }; error?: string };
|
|
};
|
|
|
|
// ── Window control RPC ─────────────────────────────────────────────────────
|
|
|
|
/** Minimize the main window. */
|
|
"window.minimize": {
|
|
params: Record<string, never>;
|
|
response: { ok: boolean };
|
|
};
|
|
/** Toggle maximize/restore on the main window. */
|
|
"window.maximize": {
|
|
params: Record<string, never>;
|
|
response: { ok: boolean };
|
|
};
|
|
/** Close the main window. */
|
|
"window.close": {
|
|
params: Record<string, never>;
|
|
response: { ok: boolean };
|
|
};
|
|
/** Get current window frame (x, y, width, height). */
|
|
"window.getFrame": {
|
|
params: Record<string, never>;
|
|
response: { x: number; y: number; width: number; height: number };
|
|
};
|
|
|
|
// ── Keybindings RPC ────────────────────────────────────────────────────────
|
|
|
|
/** Return all persisted custom keybindings (overrides only). */
|
|
"keybindings.getAll": {
|
|
params: Record<string, never>;
|
|
response: { keybindings: Record<string, string> };
|
|
};
|
|
/** Persist a single keybinding override. */
|
|
"keybindings.set": {
|
|
params: { id: string; chord: string };
|
|
response: { ok: boolean };
|
|
};
|
|
/** Reset a keybinding to default (removes override). */
|
|
"keybindings.reset": {
|
|
params: { id: string };
|
|
response: { ok: boolean };
|
|
};
|
|
|
|
// ── Agent RPC ─────────────────────────────────────────────────────────────
|
|
|
|
/** Start an agent session with a given provider. */
|
|
"agent.start": {
|
|
params: {
|
|
sessionId: string;
|
|
provider: "claude" | "codex" | "ollama";
|
|
prompt: string;
|
|
cwd?: string;
|
|
model?: string;
|
|
systemPrompt?: string;
|
|
maxTurns?: number;
|
|
permissionMode?: string;
|
|
claudeConfigDir?: string;
|
|
extraEnv?: Record<string, string>;
|
|
};
|
|
response: { ok: boolean; error?: string };
|
|
};
|
|
/** Stop a running agent session. */
|
|
"agent.stop": {
|
|
params: { sessionId: string };
|
|
response: { ok: boolean; error?: string };
|
|
};
|
|
/** Send a follow-up prompt to a running agent session. */
|
|
"agent.prompt": {
|
|
params: { sessionId: string; prompt: string };
|
|
response: { ok: boolean; error?: string };
|
|
};
|
|
/** List all active agent sessions with their state. */
|
|
"agent.list": {
|
|
params: Record<string, never>;
|
|
response: {
|
|
sessions: Array<{
|
|
sessionId: string;
|
|
provider: string;
|
|
status: string;
|
|
costUsd: number;
|
|
inputTokens: number;
|
|
outputTokens: number;
|
|
startedAt: number;
|
|
}>;
|
|
};
|
|
};
|
|
};
|
|
|
|
// ── Messages (Bun → WebView, fire-and-forget) ────────────────────────────────
|
|
|
|
export type PtyRPCMessages = {
|
|
/** PTY output chunk. data is base64-encoded raw bytes from the daemon. */
|
|
"pty.output": { sessionId: string; data: string };
|
|
/** PTY session exited. */
|
|
"pty.closed": { sessionId: string; exitCode: number | null };
|
|
|
|
// ── Agent events (Bun → WebView) ─────────────────────────────────────────
|
|
|
|
/** Agent message(s) parsed from sidecar NDJSON. */
|
|
"agent.message": {
|
|
sessionId: string;
|
|
messages: Array<{
|
|
id: string;
|
|
type: string;
|
|
parentId?: string;
|
|
content: unknown;
|
|
timestamp: number;
|
|
}>;
|
|
};
|
|
/** Agent session status change. */
|
|
"agent.status": {
|
|
sessionId: string;
|
|
status: string;
|
|
error?: string;
|
|
};
|
|
/** Agent cost/token update. */
|
|
"agent.cost": {
|
|
sessionId: string;
|
|
costUsd: number;
|
|
inputTokens: number;
|
|
outputTokens: number;
|
|
};
|
|
};
|
|
|
|
// ── Combined schema ───────────────────────────────────────────────────────────
|
|
|
|
export type PtyRPCSchema = {
|
|
requests: PtyRPCRequests;
|
|
messages: PtyRPCMessages;
|
|
};
|