mirror of
https://github.com/memohai/Memoh.git
synced 2026-04-27 07:16:19 +09:00
82c8d65a7d
* feat(terminal): add interactive web terminal for bot containers Add WebSocket-based terminal endpoint (/container/terminal/ws) that provides a full PTY shell session inside the bot's MCP container. Extend the gRPC proto with pty and resize fields, implement PTY exec on the container side using creack/pty, and add an xterm.js-based terminal component in the frontend bot detail page. * chore: add /mcp in .gitignore * feat(terminal): add multi-tab support, localStorage cache, and reactivity fixes - Support unlimited terminal tabs with add/close/switch - Cache terminal content to localStorage via SerializeAddon for session persistence - Use shallowReactive for tab objects to ensure status updates trigger UI reactivity - Fix listener leak by tracking and disposing onData/onResize on reconnect - Fix bottom clipping by using inset offsets instead of padding
126 lines
2.2 KiB
Protocol Buffer
126 lines
2.2 KiB
Protocol Buffer
syntax = "proto3";
|
|
|
|
package mcpcontainer;
|
|
|
|
option go_package = "github.com/memohai/memoh/internal/mcp/mcpcontainer";
|
|
|
|
service ContainerService {
|
|
rpc ReadFile(ReadFileRequest) returns (ReadFileResponse);
|
|
rpc WriteFile(WriteFileRequest) returns (WriteFileResponse);
|
|
rpc ListDir(ListDirRequest) returns (ListDirResponse);
|
|
rpc Stat(StatRequest) returns (StatResponse);
|
|
rpc Mkdir(MkdirRequest) returns (MkdirResponse);
|
|
rpc Rename(RenameRequest) returns (RenameResponse);
|
|
rpc Exec(stream ExecInput) returns (stream ExecOutput);
|
|
rpc ReadRaw(ReadRawRequest) returns (stream DataChunk);
|
|
rpc WriteRaw(stream WriteRawChunk) returns (WriteRawResponse);
|
|
rpc DeleteFile(DeleteFileRequest) returns (DeleteFileResponse);
|
|
}
|
|
|
|
message ReadFileRequest {
|
|
string path = 1;
|
|
int32 line_offset = 2;
|
|
int32 n_lines = 3;
|
|
}
|
|
|
|
message ReadFileResponse {
|
|
string content = 1;
|
|
int32 total_lines = 2;
|
|
bool binary = 3;
|
|
}
|
|
|
|
message WriteFileRequest {
|
|
string path = 1;
|
|
bytes content = 2;
|
|
}
|
|
|
|
message WriteFileResponse {}
|
|
|
|
message ListDirRequest {
|
|
string path = 1;
|
|
bool recursive = 2;
|
|
}
|
|
|
|
message FileEntry {
|
|
string path = 1;
|
|
bool is_dir = 2;
|
|
int64 size = 3;
|
|
string mode = 4;
|
|
string mod_time = 5;
|
|
}
|
|
|
|
message ListDirResponse {
|
|
repeated FileEntry entries = 1;
|
|
}
|
|
|
|
message ExecInput {
|
|
string command = 1;
|
|
string work_dir = 2;
|
|
repeated string env = 3;
|
|
int32 timeout_seconds = 4;
|
|
bytes stdin_data = 5;
|
|
bool pty = 6;
|
|
TerminalResize resize = 7;
|
|
}
|
|
|
|
message TerminalResize {
|
|
uint32 cols = 1;
|
|
uint32 rows = 2;
|
|
}
|
|
|
|
message ExecOutput {
|
|
enum Stream {
|
|
STDOUT = 0;
|
|
STDERR = 1;
|
|
EXIT = 2;
|
|
}
|
|
Stream stream = 1;
|
|
bytes data = 2;
|
|
int32 exit_code = 3;
|
|
}
|
|
|
|
message ReadRawRequest {
|
|
string path = 1;
|
|
}
|
|
|
|
message DataChunk {
|
|
bytes data = 1;
|
|
}
|
|
|
|
message WriteRawChunk {
|
|
string path = 1;
|
|
bytes data = 2;
|
|
}
|
|
|
|
message WriteRawResponse {
|
|
int64 bytes_written = 1;
|
|
}
|
|
|
|
message DeleteFileRequest {
|
|
string path = 1;
|
|
bool recursive = 2;
|
|
}
|
|
|
|
message DeleteFileResponse {}
|
|
|
|
message StatRequest {
|
|
string path = 1;
|
|
}
|
|
|
|
message StatResponse {
|
|
FileEntry entry = 1;
|
|
}
|
|
|
|
message MkdirRequest {
|
|
string path = 1;
|
|
}
|
|
|
|
message MkdirResponse {}
|
|
|
|
message RenameRequest {
|
|
string old_path = 1;
|
|
string new_path = 2;
|
|
}
|
|
|
|
message RenameResponse {}
|