feat(electrobun): file management — CodeMirror editor, PDF viewer, CSV table, real file I/O

- CodeEditor: CodeMirror 6 with Catppuccin theme, 15+ languages, Ctrl+S save,
  dirty tracking, save-on-blur
- PdfViewer: pdfjs-dist canvas rendering, zoom 0.5-3x, HiDPI, lazy page load
- CsvTable: RFC 4180 parser, delimiter auto-detect, sortable columns, sticky header
- FileBrowser: real filesystem via files.list/read/write RPC, lazy dir loading,
  file type routing (code→editor, pdf→viewer, csv→table, images→display)
- 10MB size gate, binary detection, base64 encoding for non-text files
This commit is contained in:
Hibryda 2026-03-22 01:36:02 +01:00
parent 29a3370e79
commit 252fca70df
22 changed files with 8116 additions and 227 deletions

View file

@ -90,6 +90,36 @@ export type PtyRPCRequests = {
response: { ok: boolean };
};
// ── File I/O RPC ──────────────────────────────────────────────────────────
/** List directory children (files + subdirs). Returns sorted entries. */
"files.list": {
params: { path: string };
response: {
entries: Array<{
name: string;
type: "file" | "dir";
size: number;
}>;
error?: string;
};
};
/** Read a file's content. Returns text for text files, base64 for binary. */
"files.read": {
params: { path: string };
response: {
content?: string;
encoding: "utf8" | "base64";
size: number;
error?: string;
};
};
/** Write text content to a file. */
"files.write": {
params: { path: string; content: string };
response: { ok: boolean; error?: string };
};
// ── Groups RPC ─────────────────────────────────────────────────────────────
/** Return all project groups. */
@ -190,6 +220,268 @@ export type PtyRPCRequests = {
}>;
};
};
// ── Session persistence RPC ────────────────────────────────────────────
/** Save/update a session record. */
"session.save": {
params: {
projectId: string; sessionId: string; provider: string;
status: string; costUsd: number; inputTokens: number;
outputTokens: number; model: string; error?: string;
createdAt: number; updatedAt: number;
};
response: { ok: boolean };
};
/** Load the most recent session for a project. */
"session.load": {
params: { projectId: string };
response: {
session: {
projectId: string; sessionId: string; provider: string;
status: string; costUsd: number; inputTokens: number;
outputTokens: number; model: string; error?: string;
createdAt: number; updatedAt: number;
} | null;
};
};
/** List sessions for a project (max 20). */
"session.list": {
params: { projectId: string };
response: {
sessions: Array<{
projectId: string; sessionId: string; provider: string;
status: string; costUsd: number; inputTokens: number;
outputTokens: number; model: string; error?: string;
createdAt: number; updatedAt: number;
}>;
};
};
/** Save agent messages (batch). */
"session.messages.save": {
params: {
messages: Array<{
sessionId: string; msgId: string; role: string; content: string;
toolName?: string; toolInput?: string; timestamp: number;
costUsd?: number; inputTokens?: number; outputTokens?: number;
}>;
};
response: { ok: boolean };
};
/** Load all messages for a session. */
"session.messages.load": {
params: { sessionId: string };
response: {
messages: Array<{
sessionId: string; msgId: string; role: string; content: string;
toolName?: string; toolInput?: string; timestamp: number;
costUsd: number; inputTokens: number; outputTokens: number;
}>;
};
};
// ── btmsg RPC ──────────────────────────────────────────────────────────
/** Register an agent in btmsg. */
"btmsg.registerAgent": {
params: {
id: string; name: string; role: string;
groupId: string; tier: number; model?: string;
};
response: { ok: boolean };
};
/** List agents for a group. */
"btmsg.getAgents": {
params: { groupId: string };
response: {
agents: Array<{
id: string; name: string; role: string; groupId: string;
tier: number; model: string | null; status: string; unreadCount: number;
}>;
};
};
/** Send a direct message between agents. */
"btmsg.sendMessage": {
params: { fromAgent: string; toAgent: string; content: string };
response: { ok: boolean; messageId?: string; error?: string };
};
/** Get message history between two agents. */
"btmsg.listMessages": {
params: { agentId: string; otherId: string; limit?: number };
response: {
messages: Array<{
id: string; fromAgent: string; toAgent: string; content: string;
read: boolean; replyTo: string | null; createdAt: string;
senderName: string | null; senderRole: string | null;
}>;
};
};
/** Mark messages as read. */
"btmsg.markRead": {
params: { agentId: string; messageIds: string[] };
response: { ok: boolean };
};
/** List channels for a group. */
"btmsg.listChannels": {
params: { groupId: string };
response: {
channels: Array<{
id: string; name: string; groupId: string; createdBy: string;
memberCount: number; createdAt: string;
}>;
};
};
/** Create a channel. */
"btmsg.createChannel": {
params: { name: string; groupId: string; createdBy: string };
response: { ok: boolean; channelId?: string };
};
/** Get channel messages. */
"btmsg.getChannelMessages": {
params: { channelId: string; limit?: number };
response: {
messages: Array<{
id: string; channelId: string; fromAgent: string; content: string;
createdAt: string; senderName: string; senderRole: string;
}>;
};
};
/** Send a channel message. */
"btmsg.sendChannelMessage": {
params: { channelId: string; fromAgent: string; content: string };
response: { ok: boolean; messageId?: string };
};
/** Record agent heartbeat. */
"btmsg.heartbeat": {
params: { agentId: string };
response: { ok: boolean };
};
/** Get dead letter queue entries. */
"btmsg.getDeadLetters": {
params: { limit?: number };
response: {
letters: Array<{
id: number; fromAgent: string; toAgent: string;
content: string; error: string; createdAt: string;
}>;
};
};
/** Log an audit event. */
"btmsg.logAudit": {
params: { agentId: string; eventType: string; detail: string };
response: { ok: boolean };
};
/** Get audit log. */
"btmsg.getAuditLog": {
params: { limit?: number };
response: {
entries: Array<{
id: number; agentId: string; eventType: string;
detail: string; createdAt: string;
}>;
};
};
// ── bttask RPC ─────────────────────────────────────────────────────────
/** List tasks for a group. */
"bttask.listTasks": {
params: { groupId: string };
response: {
tasks: Array<{
id: string; title: string; description: string; status: string;
priority: string; assignedTo: string | null; createdBy: string;
groupId: string; parentTaskId: string | null; sortOrder: number;
createdAt: string; updatedAt: string; version: number;
}>;
};
};
/** Create a task. */
"bttask.createTask": {
params: {
title: string; description: string; priority: string;
groupId: string; createdBy: string; assignedTo?: string;
};
response: { ok: boolean; taskId?: string; error?: string };
};
/** Update task status with optimistic locking. */
"bttask.updateTaskStatus": {
params: { taskId: string; status: string; expectedVersion: number };
response: { ok: boolean; newVersion?: number; error?: string };
};
/** Delete a task. */
"bttask.deleteTask": {
params: { taskId: string };
response: { ok: boolean };
};
/** Add a comment to a task. */
"bttask.addComment": {
params: { taskId: string; agentId: string; content: string };
response: { ok: boolean; commentId?: string };
};
/** List comments for a task. */
"bttask.listComments": {
params: { taskId: string };
response: {
comments: Array<{
id: string; taskId: string; agentId: string;
content: string; createdAt: string;
}>;
};
};
/** Count tasks in 'review' status. */
"bttask.reviewQueueCount": {
params: { groupId: string };
response: { count: number };
};
// ── Search RPC ──────────────────────────────────────────────────────────
/** Full-text search across messages, tasks, and btmsg. */
"search.query": {
params: { query: string; limit?: number };
response: {
results: Array<{
resultType: string;
id: string;
title: string;
snippet: string;
score: number;
}>;
};
};
/** Index a message for search. */
"search.indexMessage": {
params: { sessionId: string; role: string; content: string };
response: { ok: boolean };
};
/** Rebuild the entire search index. */
"search.rebuild": {
params: Record<string, never>;
response: { ok: boolean };
};
// ── Plugin RPC ──────────────────────────────────────────────────────────
/** Discover plugins from ~/.config/agor/plugins/. */
"plugin.discover": {
params: Record<string, never>;
response: {
plugins: Array<{
id: string;
name: string;
version: string;
description: string;
main: string;
permissions: string[];
}>;
};
};
/** Read a plugin file (path-traversal-safe). */
"plugin.readFile": {
params: { pluginId: string; filePath: string };
response: { ok: boolean; content: string; error?: string };
};
};
// ── Messages (Bun → WebView, fire-and-forget) ────────────────────────────────