// Package workspace is the Workspace (agent sandbox / files) bounded // context: the single shared ENKLY_WORKSPACE directory the coding agent // reads, writes and runs commands in, and that the "Files" panel in the // UI lets a human upload into / download from. Every path-jailing rule // from internal/llm/sandbox.go (ResolvePath, the bash allowlist, the // filesystem guards) is enforced here and nowhere else — no other // service is allowed to touch the workspace volume directly. // // Mirrors internal/llm/tools.go (filesystem + bash tools) and // internal/handlers/files.go / ui.go (upload, download, tree). syntax = "proto3"; package enkly.workspace.v1; option go_package = "enkly/gen/workspace/v1;workspacev1"; import "google/protobuf/timestamp.proto"; service WorkspaceService { // --- agent filesystem/bash tools (internal/llm/tools.go, sandbox.go) --- rpc ReadFile(ReadFileRequest) returns (ReadFileResponse); rpc WriteFile(WriteFileRequest) returns (WriteFileResponse); rpc EditFile(EditFileRequest) returns (EditFileResponse); rpc MultiEditFile(MultiEditFileRequest) returns (MultiEditFileResponse); rpc ListDirectory(ListDirectoryRequest) returns (ListDirectoryResponse); rpc GlobSearch(GlobSearchRequest) returns (GlobSearchResponse); rpc Grep(GrepRequest) returns (GrepResponse); rpc RunBashCommand(RunBashCommandRequest) returns (RunBashCommandResponse); // --- human-facing files panel (internal/handlers/files.go, ui.go) --- rpc UploadFile(UploadFileRequest) returns (UploadFileResponse); rpc DownloadFile(DownloadFileRequest) returns (DownloadFileResponse); rpc Tree(TreeRequest) returns (TreeResponse); rpc StatFile(StatFileRequest) returns (StatFileResponse); // backs deliverable cards } message ReadFileRequest { string path = 1; int32 offset = 2; // 0-based line offset int32 limit = 3; // 0 = default (maxReadLines) } message ReadFileResponse { string content = 1; bool truncated = 2; bool is_error = 3; string error_message = 4; } message WriteFileRequest { string path = 1; string content = 2; } message WriteFileResponse { int64 bytes_written = 1; bool is_error = 2; string error_message = 3; } message EditFileRequest { string path = 1; string old_string = 2; string new_string = 3; bool replace_all = 4; } message EditFileResponse { string diff_preview = 1; int32 occurrences = 2; bool is_error = 3; string error_message = 4; } message TextEdit { string old_string = 1; string new_string = 2; bool replace_all = 3; } message MultiEditFileRequest { string path = 1; repeated TextEdit edits = 2; } message MultiEditFileResponse { string diff_preview = 1; bool is_error = 2; string error_message = 3; } message ListDirectoryRequest { string path = 1; } message ListDirectoryResponse { string listing = 1; // pre-rendered, matching the monolith's tool output format bool is_error = 2; string error_message = 3; } message GlobSearchRequest { string pattern = 1; string path = 2; } message GlobSearchResponse { // Pre-rendered exactly like every other tool's text output (a // newline-separated path list, "no files matched that pattern", or a // truncation notice) — deliberately NOT a repeated string, since that // would require guessing which lines are paths vs. a status message, // a lossy transformation the original tool output never needed. string output = 1; bool is_error = 2; string error_message = 3; } message GrepRequest { string pattern = 1; string path = 2; string glob = 3; bool case_insensitive = 4; } message GrepResponse { string output = 1; bool is_error = 2; string error_message = 3; } message RunBashCommandRequest { string command = 1; int32 timeout_seconds = 2; // 0 = service default } message RunBashCommandResponse { string output = 1; int32 exit_code = 2; bool is_error = 3; string error_message = 4; } message UploadFileRequest { string path = 1; // destination relative path bytes content = 2; } message UploadFileResponse { int64 bytes_written = 1; } message DownloadFileRequest { string path = 1; } message DownloadFileResponse { bytes content = 1; string filename = 2; } message TreeRequest { string path = 1; // "" = workspace root // one_level: list only the immediate children of path (both files // and directories, directories included as entries in their own // right) instead of recursing — backs the gateway's lazy-expanding // file explorer panel (internal/handlers/ui.go's FileTree), where // each folder click fetches just that folder. false (the default) // recurses fully and returns only files, for the flat "Workspace // files" upload/download panel (internal/handlers/files.go). bool one_level = 2; } message TreeNode { string name = 1; string rel_path = 2; bool is_dir = 3; int64 size = 4; google.protobuf.Timestamp modified_at = 5; // download_url is left empty by this service — the gateway owns URL // construction (it knows its own public route prefix), not workspace. } message TreeResponse { repeated TreeNode nodes = 1; } message StatFileRequest { string path = 1; } message StatFileResponse { bool exists = 1; bool is_dir = 2; int64 size = 3; google.protobuf.Timestamp modified_at = 4; }