first pass of merging in warp (doesn't build)
This commit is contained in:
@@ -0,0 +1,511 @@
|
||||
// Diff state protocol messages for communication between
|
||||
// the Warp client and the remote server binary.
|
||||
//
|
||||
// These messages are used by the diff state subsystem to synchronize
|
||||
// code review diff data between a remote daemon and the Warp client.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package remote_server;
|
||||
|
||||
// ── Diff state sub-messages ───────────────────────────────────────
|
||||
// Mirror the Rust domain types in code_review/diff_state.rs.
|
||||
|
||||
// Mirrors DiffMode in Rust.
|
||||
message DiffMode {
|
||||
oneof mode {
|
||||
DiffModeHead head = 1;
|
||||
DiffModeMainBranch main_branch = 2;
|
||||
DiffModeOtherBranch other_branch = 3;
|
||||
}
|
||||
}
|
||||
message DiffModeHead {}
|
||||
message DiffModeMainBranch {}
|
||||
message DiffModeOtherBranch {
|
||||
string branch_name = 1;
|
||||
}
|
||||
|
||||
// Mirrors DiffState in Rust. After the wrapper split (§1), Loaded is a
|
||||
// unit variant — the diff payload is carried separately in
|
||||
// DiffStateSnapshot.diffs.
|
||||
message DiffState {
|
||||
oneof state {
|
||||
DiffStateNotInRepository not_in_repository = 1;
|
||||
DiffStateLoading loading = 2;
|
||||
DiffStateErrorValue error = 3;
|
||||
DiffStateLoaded loaded = 4;
|
||||
}
|
||||
}
|
||||
message DiffStateNotInRepository {}
|
||||
message DiffStateLoading {}
|
||||
message DiffStateErrorValue {
|
||||
string message = 1;
|
||||
}
|
||||
message DiffStateLoaded {}
|
||||
|
||||
// Mirrors DiffLineType in Rust.
|
||||
enum DiffLineType {
|
||||
DIFF_LINE_TYPE_UNSPECIFIED = 0;
|
||||
DIFF_LINE_TYPE_CONTEXT = 1;
|
||||
DIFF_LINE_TYPE_ADD = 2;
|
||||
DIFF_LINE_TYPE_DELETE = 3;
|
||||
DIFF_LINE_TYPE_HUNK_HEADER = 4;
|
||||
}
|
||||
|
||||
// Represents a single line in a diff hunk, as rendered by `git diff`. Mirrors DiffLine in Rust.
|
||||
message DiffLine {
|
||||
DiffLineType line_type = 1;
|
||||
optional uint64 old_line_number = 2;
|
||||
optional uint64 new_line_number = 3;
|
||||
string text = 4;
|
||||
bool no_trailing_newline = 5;
|
||||
}
|
||||
|
||||
// Represents a hunk of changes in a file diff, as rendered by `git diff`. Mirrors DiffHunk in Rust.
|
||||
message DiffHunk {
|
||||
uint64 old_start_line = 1;
|
||||
uint64 old_line_count = 2;
|
||||
uint64 new_start_line = 3;
|
||||
uint64 new_line_count = 4;
|
||||
repeated DiffLine lines = 5;
|
||||
uint64 unified_diff_start = 6;
|
||||
uint64 unified_diff_end = 7;
|
||||
}
|
||||
|
||||
// Represents the status of a file in the git working directory. Mirrors GitFileStatus in Rust.
|
||||
message GitFileStatus {
|
||||
oneof status {
|
||||
GitFileStatusNew new_file = 1;
|
||||
GitFileStatusModified modified = 2;
|
||||
GitFileStatusDeleted deleted = 3;
|
||||
GitFileStatusRenamed renamed = 4;
|
||||
GitFileStatusCopied copied = 5;
|
||||
GitFileStatusUntracked untracked = 6;
|
||||
GitFileStatusConflicted conflicted = 7;
|
||||
}
|
||||
}
|
||||
message GitFileStatusNew {}
|
||||
message GitFileStatusModified {}
|
||||
message GitFileStatusDeleted {}
|
||||
message GitFileStatusRenamed {
|
||||
string old_path = 1;
|
||||
}
|
||||
message GitFileStatusCopied {
|
||||
string old_path = 1;
|
||||
}
|
||||
message GitFileStatusUntracked {}
|
||||
message GitFileStatusConflicted {}
|
||||
|
||||
// Mirrors DiffSize in Rust (diff_size_limits.rs).
|
||||
enum DiffSize {
|
||||
DIFF_SIZE_UNSPECIFIED = 0;
|
||||
DIFF_SIZE_NORMAL = 1;
|
||||
DIFF_SIZE_LARGE = 2;
|
||||
// The diff/patch itself is too large to render. (Was DIFF_SIZE_UNRENDERABLE;
|
||||
// value 3 is preserved for wire compatibility.)
|
||||
DIFF_SIZE_UNRENDERABLE_DIFF_TOO_LARGE = 3;
|
||||
// The base file content was withheld because it exceeded the per-file wire
|
||||
// budget; the client renders a "file too large" placeholder.
|
||||
DIFF_SIZE_UNRENDERABLE_FILE_TOO_LARGE = 4;
|
||||
}
|
||||
|
||||
// Mirrors FileDiff + FileDiffAndContent in Rust.
|
||||
// The two types are collapsed into a single message with an optional content_at_base field,
|
||||
// since every wire context that sends a FileDiff also needs base content for editor rendering.
|
||||
message FileDiff {
|
||||
string file_path = 1;
|
||||
GitFileStatus status = 2;
|
||||
repeated DiffHunk hunks = 3;
|
||||
bool is_binary = 4;
|
||||
bool is_autogenerated = 5;
|
||||
uint64 max_line_number = 6;
|
||||
bool has_hidden_bidi_chars = 7;
|
||||
DiffSize size = 8;
|
||||
// File content at HEAD or merge-base, used by the code review editor to
|
||||
// render inline diff decorations (set_base). Absent for binary files, for
|
||||
// files whose content exceeds the per-file wire budget (size =
|
||||
// DIFF_SIZE_UNRENDERABLE_FILE_TOO_LARGE), or when git show fails.
|
||||
optional string content_at_base = 9;
|
||||
}
|
||||
|
||||
// Represents the complete git diff information for a repository. Mirrors GitDiffData in Rust.
|
||||
message GitDiffData {
|
||||
repeated FileDiff files = 1;
|
||||
uint64 total_additions = 2;
|
||||
uint64 total_deletions = 3;
|
||||
uint64 files_changed = 4;
|
||||
}
|
||||
|
||||
// Mirrors DiffStats in Rust.
|
||||
message DiffStats {
|
||||
uint64 files_changed = 1;
|
||||
uint64 total_additions = 2;
|
||||
uint64 total_deletions = 3;
|
||||
}
|
||||
|
||||
// Mirrors DiffMetadataAgainstBase in Rust.
|
||||
message DiffMetadataAgainstBase {
|
||||
DiffStats aggregate_stats = 1;
|
||||
// Per-file change entries for this base, captured from the same numstat that
|
||||
// produces aggregate_stats so the git dialog's Changes box can render
|
||||
// without a working-tree read (lets the box populate for remote repos).
|
||||
repeated FileChangeEntry files = 2;
|
||||
}
|
||||
|
||||
// Mirrors Commit in Rust (util/git.rs).
|
||||
message Commit {
|
||||
string hash = 1;
|
||||
string subject = 2;
|
||||
uint64 files_changed = 3;
|
||||
uint64 additions = 4;
|
||||
uint64 deletions = 5;
|
||||
// Per-file changes in this commit, captured up front so the push dialog can
|
||||
// render a commit's file list on expansion without a follow-up RPC.
|
||||
repeated FileChangeEntry files = 6;
|
||||
}
|
||||
|
||||
// Mirrors FileChangeEntry in Rust (util/git.rs).
|
||||
message FileChangeEntry {
|
||||
string path = 1;
|
||||
uint64 additions = 2;
|
||||
uint64 deletions = 3;
|
||||
}
|
||||
|
||||
// Mirrors PrInfo in Rust (util/git.rs).
|
||||
message PrInfo {
|
||||
uint64 number = 1;
|
||||
string url = 2;
|
||||
string state = 3;
|
||||
bool draft = 4;
|
||||
string base_branch = 5;
|
||||
}
|
||||
|
||||
// Mirrors DiffMetadata in Rust.
|
||||
message DiffMetadata {
|
||||
string main_branch_name = 1;
|
||||
string current_branch_name = 2;
|
||||
DiffMetadataAgainstBase against_head = 3;
|
||||
optional DiffMetadataAgainstBase against_base_branch = 4;
|
||||
bool has_head_commit = 5;
|
||||
repeated Commit unpushed_commits = 6;
|
||||
optional string upstream_ref = 7;
|
||||
}
|
||||
|
||||
// Mirrors FileStatusInfo in Rust. Identifies a file and its git status
|
||||
// for discard operations (git restore / git stash / git rm).
|
||||
message FileStatusInfo {
|
||||
string path = 1;
|
||||
GitFileStatus status = 2;
|
||||
}
|
||||
|
||||
// ── Diff state client → server ────────────────────────────────────
|
||||
|
||||
// Client → server: subscribe to diff state for a (repo, mode) pair.
|
||||
// The server responds with GetDiffStateResponse, then pushes subsequent changes.
|
||||
message GetDiffState {
|
||||
string repo_path = 1;
|
||||
DiffMode mode = 2;
|
||||
}
|
||||
|
||||
// Client → server: unsubscribe from diff state updates for a (repo, mode) pair.
|
||||
// Fire-and-forget — the server does not send a response.
|
||||
message UnsubscribeDiffState {
|
||||
string repo_path = 1;
|
||||
DiffMode mode = 2;
|
||||
}
|
||||
|
||||
// Client → server: discard changes for one or more files.
|
||||
// Runs git restore/stash/rm on the remote filesystem.
|
||||
message DiscardFilesRequest {
|
||||
string repo_path = 1;
|
||||
repeated FileStatusInfo files = 2;
|
||||
bool should_stash = 3;
|
||||
// Branch to restore against. Absent means HEAD.
|
||||
optional string branch_name = 4;
|
||||
// The diff mode identifying which DiffStateModel to use.
|
||||
DiffMode mode = 5;
|
||||
}
|
||||
|
||||
// ── Diff state server → client ────────────────────────────────────
|
||||
|
||||
// Error payload for GetDiffStateResponse.
|
||||
message DiffStateError {
|
||||
string message = 1;
|
||||
}
|
||||
|
||||
// Full diff state snapshot for a (repo, mode) pair.
|
||||
// Pushed on structural changes (NewDiffsComputed events).
|
||||
message DiffStateSnapshot {
|
||||
string repo_path = 1;
|
||||
DiffMode mode = 2;
|
||||
DiffMetadata metadata = 3;
|
||||
DiffState state = 4;
|
||||
// Present when state is Loaded.
|
||||
optional GitDiffData diffs = 5;
|
||||
}
|
||||
|
||||
// Response to GetDiffState.
|
||||
message GetDiffStateResponse {
|
||||
oneof result {
|
||||
DiffStateSnapshot snapshot = 1;
|
||||
DiffStateError error = 2;
|
||||
}
|
||||
}
|
||||
|
||||
// Metadata-only update pushed for MetadataRefreshed and
|
||||
// CurrentBranchChanged events. Avoids re-serializing the entire diff
|
||||
// payload on every throttled refresh.
|
||||
message DiffStateMetadataUpdate {
|
||||
string repo_path = 1;
|
||||
DiffMode mode = 2;
|
||||
DiffMetadata metadata = 3;
|
||||
}
|
||||
|
||||
// Single-file diff delta pushed for SingleFileUpdated events.
|
||||
// Carries one FileDiff + file path + updated metadata.
|
||||
// Debounced at 2s on the server.
|
||||
message DiffStateFileDelta {
|
||||
string repo_path = 1;
|
||||
DiffMode mode = 2;
|
||||
string file_path = 3;
|
||||
optional FileDiff diff = 4;
|
||||
optional DiffMetadata metadata = 5;
|
||||
}
|
||||
|
||||
// Server → client: result of a DiscardFilesRequest.
|
||||
message DiscardFilesResponse {
|
||||
oneof result {
|
||||
DiscardFilesSuccess success = 1;
|
||||
DiscardFilesError error = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message DiscardFilesSuccess {}
|
||||
|
||||
message DiscardFilesError {
|
||||
string message = 1;
|
||||
}
|
||||
|
||||
// ── Branch listing ────────────────────────────────────────────────
|
||||
|
||||
// Client → server: list branches for a repository.
|
||||
message GetBranches {
|
||||
string repo_path = 1;
|
||||
// Maximum number of branches to return. Absent = server default (100).
|
||||
optional uint32 max_branch_count = 2;
|
||||
// Whether to include remote-tracking branches (refs/remotes).
|
||||
bool include_remotes = 3;
|
||||
}
|
||||
|
||||
// A single branch entry.
|
||||
message BranchInfo {
|
||||
string name = 1;
|
||||
bool is_main = 2;
|
||||
}
|
||||
|
||||
// Server → client: result of a GetBranches request.
|
||||
message GetBranchesResponse {
|
||||
oneof result {
|
||||
GetBranchesSuccess success = 1;
|
||||
GetBranchesError error = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message GetBranchesSuccess {
|
||||
repeated BranchInfo branches = 1;
|
||||
}
|
||||
|
||||
message GetBranchesError {
|
||||
string message = 1;
|
||||
}
|
||||
|
||||
// ── Git operations (commit / push / create-PR) ────────────────────
|
||||
// Run git / gh on the remote filesystem. These mirror the local code
|
||||
// review git dialog operations in app/src/code_review/git_dialog/*.
|
||||
|
||||
// Shared error payload for git operation responses. The message is the
|
||||
// raw git/gh error, mapped to user-facing copy on the client.
|
||||
message GitOpError {
|
||||
string message = 1;
|
||||
}
|
||||
|
||||
// Post-operation delta applied to DiffMetadata so the client refreshes the
|
||||
// header immediately, without waiting for the next watcher-driven snapshot.
|
||||
message GitOpDelta {
|
||||
repeated Commit unpushed_commits = 1;
|
||||
optional string upstream_ref = 2;
|
||||
}
|
||||
|
||||
// Client → server: run the commit chain (commit, then optionally push, then
|
||||
// optionally create-PR) host-local in a single round trip. The daemon
|
||||
// sequences the underlying git / gh subprocesses (see handle_git_commit_chain), so
|
||||
// the SSH link carries one request/response instead of the 2–3 a client-side
|
||||
// chain would send.
|
||||
message GitCommitChainRequest {
|
||||
string repo_path = 1;
|
||||
string message = 2;
|
||||
bool include_unstaged = 3;
|
||||
// Branch to push / open the PR against. Ignored for COMMIT_ONLY.
|
||||
string branch = 4;
|
||||
GitCommitChainMode mode = 5;
|
||||
// When mode is COMMIT_AND_CREATE_PR, generate the PR title/body via AI on the
|
||||
// daemon (get_diff_for_pr + generate_code_review_content), falling back to
|
||||
// `gh pr create --fill`. Ignored for the other modes.
|
||||
bool autogenerate_pr_content = 6;
|
||||
}
|
||||
|
||||
// What to run after the commit succeeds.
|
||||
enum GitCommitChainMode {
|
||||
GIT_COMMIT_CHAIN_MODE_COMMIT_ONLY = 0;
|
||||
GIT_COMMIT_CHAIN_MODE_COMMIT_AND_PUSH = 1;
|
||||
GIT_COMMIT_CHAIN_MODE_COMMIT_AND_CREATE_PR = 2;
|
||||
}
|
||||
|
||||
message GitCommitChainResponse {
|
||||
oneof result {
|
||||
GitCommitChainSuccess success = 1;
|
||||
GitOpError error = 2;
|
||||
}
|
||||
}
|
||||
|
||||
// Final post-chain delta plus the PR when one was created (absent for
|
||||
// COMMIT_ONLY / COMMIT_AND_PUSH).
|
||||
message GitCommitChainSuccess {
|
||||
GitOpDelta delta = 1;
|
||||
optional PrInfo pr_info = 2;
|
||||
}
|
||||
|
||||
// Client → server: push `branch` to origin, setting upstream tracking.
|
||||
message GitPushRequest {
|
||||
string repo_path = 1;
|
||||
string branch = 2;
|
||||
}
|
||||
|
||||
message GitPushResponse {
|
||||
oneof result {
|
||||
GitOpDelta success = 1;
|
||||
GitOpError error = 2;
|
||||
}
|
||||
}
|
||||
|
||||
// Client → server: create a PR for the current branch (must be pushed).
|
||||
// Absent title/body => `gh pr create --fill`, unless autogenerate_content is
|
||||
// set (then the daemon generates the title/body via AI first).
|
||||
message GitCreatePrRequest {
|
||||
string repo_path = 1;
|
||||
// Current branch name, passed as context to daemon-side AI generation.
|
||||
string branch = 2;
|
||||
// When true and title/body are both absent, the daemon generates the PR
|
||||
// title + body via AI (get_diff_for_pr + generate_code_review_content)
|
||||
// before running `gh pr create`, falling back to `--fill` on failure.
|
||||
bool autogenerate_content = 3;
|
||||
}
|
||||
|
||||
message GitCreatePrResponse {
|
||||
oneof result {
|
||||
PrInfo success = 1;
|
||||
GitOpError error = 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Client → server: list the committed file changes for the current branch's
|
||||
// PR-ready diff (merge_base(HEAD, main)..HEAD). Backs the Create PR dialog's
|
||||
// Changes box; deliberately committed-only (no working-tree edits, no
|
||||
// untracked files) so it matches what `gh pr create` would include.
|
||||
message GitGetCommittedBranchFilesRequest {
|
||||
string repo_path = 1;
|
||||
}
|
||||
|
||||
message GitGetCommittedBranchFilesResponse {
|
||||
oneof result {
|
||||
GitGetCommittedBranchFilesSuccess success = 1;
|
||||
GitOpError error = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message GitGetCommittedBranchFilesSuccess {
|
||||
repeated FileChangeEntry files = 1;
|
||||
}
|
||||
|
||||
// Client → server: generate a commit message via AI on the remote host.
|
||||
// The daemon computes the working-tree diff locally and calls the Warp
|
||||
// server's code-review content endpoint, returning the message string. Sent
|
||||
// at commit-dialog open time, mirroring the local open-time autogen.
|
||||
message GitGenerateCommitMessageRequest {
|
||||
string repo_path = 1;
|
||||
// Whether to include unstaged changes in the diff sent to AI (mirrors the
|
||||
// commit dialog's include-unstaged toggle).
|
||||
bool include_unstaged = 2;
|
||||
// Current branch name, passed as context to the AI request.
|
||||
string branch_name = 3;
|
||||
}
|
||||
|
||||
message GitGenerateCommitMessageResponse {
|
||||
oneof result {
|
||||
// The generated commit message (already trimmed, non-empty).
|
||||
string message = 1;
|
||||
GitOpError error = 2;
|
||||
}
|
||||
}
|
||||
|
||||
// ── Git and GitHub info ──────────────────────────────────────────────────
|
||||
|
||||
// Mirrors RepositoryInfo in Rust (util/git.rs). Returned by `gh repo view`.
|
||||
message RepositoryInfo {
|
||||
string name = 1;
|
||||
optional string owner = 2;
|
||||
}
|
||||
|
||||
// Mirrors GitStatusMetadata in Rust (code_review/git_repo_model/mod.rs).
|
||||
message GitStatusMetadata {
|
||||
string current_branch_name = 1;
|
||||
string main_branch_name = 2;
|
||||
DiffStats stats_against_head = 3;
|
||||
optional string tracking_upstream = 4;
|
||||
uint32 tracking_ahead = 5;
|
||||
uint32 tracking_behind = 6;
|
||||
bool tracking_counts_available = 7;
|
||||
}
|
||||
|
||||
// Server -> client push: aggregate git status for a repo. Sent on every
|
||||
// watcher tick, opportunistically after navigation resolves a git root, and
|
||||
// when a client requests a current snapshot.
|
||||
message GitStatusPush {
|
||||
string repo_path = 1;
|
||||
GitStatusMetadata metadata = 2;
|
||||
}
|
||||
|
||||
// Client -> server notification: ask the daemon to create the per-repo git
|
||||
// status model if needed and push the current GitStatusPush snapshot when
|
||||
// available. Fire-and-forget; no response is sent.
|
||||
message UpdateGitStatus {
|
||||
string repo_path = 1;
|
||||
}
|
||||
|
||||
// Server -> client push: PR info for a repo's current branch. Sent when the
|
||||
// daemon's `GitHubRepoModel` recomputes PR info.
|
||||
message GitHubPrInfoPush {
|
||||
string repo_path = 1;
|
||||
optional PrInfo pr_info = 2;
|
||||
}
|
||||
// Server -> client push: repository name/owner info for a repo. Sent when the
|
||||
// daemon's `GitHubRepoModel` recomputes repository info.
|
||||
message GitHubRepositoryInfoPush {
|
||||
string repo_path = 1;
|
||||
optional RepositoryInfo repository_info = 2;
|
||||
}
|
||||
// Client -> server notification: ask the daemon to create the per-repo
|
||||
// GitHubRepoModel if needed and refresh PR info for the current branch. The
|
||||
// result is delivered as a `GitHubPrInfoPush` broadcast (single source of
|
||||
// truth: the daemon's `GitHubRepoModel`). Fire-and-forget; no response.
|
||||
message UpdateGitHubPrInfo {
|
||||
string repo_path = 1;
|
||||
}
|
||||
// Client -> server notification: ask the daemon to create the per-repo
|
||||
// GitHubRepoModel if needed and refresh repository name/owner. The result is
|
||||
// delivered as a `GitHubRepositoryInfoPush` broadcast. Fire-and-forget; no
|
||||
// response.
|
||||
message UpdateGitHubRepoInfo {
|
||||
string repo_path = 1;
|
||||
}
|
||||
@@ -7,22 +7,81 @@ syntax = "proto3";
|
||||
|
||||
package remote_server;
|
||||
|
||||
import "diff_state.proto";
|
||||
|
||||
// ── Top-level envelopes ───────────────────────────────────────────
|
||||
|
||||
// Top-level envelope for all client → server messages.
|
||||
message ClientMessage {
|
||||
string request_id = 1;
|
||||
oneof message {
|
||||
Initialize initialize = 2;
|
||||
Abort abort = 3;
|
||||
NavigatedToDirectory navigated_to_directory = 4;
|
||||
LoadRepoMetadataDirectory load_repo_metadata_directory = 5;
|
||||
SessionBootstrapped session_bootstrapped = 6;
|
||||
WriteFile write_file = 7;
|
||||
DeleteFile delete_file = 8;
|
||||
RunCommandRequest run_command = 9;
|
||||
ReadFileContextRequest read_file_context = 10;
|
||||
Authenticate authenticate = 11;
|
||||
HostScopedRequest host_scoped = 2;
|
||||
SessionScopedRequest session_scoped = 3;
|
||||
Notification notification = 4;
|
||||
}
|
||||
}
|
||||
|
||||
// Request that targets the host, not a specific connection.
|
||||
// The daemon may deliver the response on any open connection
|
||||
// if the originating connection disconnects before the response
|
||||
// is ready.
|
||||
message HostScopedRequest {
|
||||
// 4 (open_buffer) and 7 (get_diff_state) moved to SessionScopedRequest:
|
||||
// they establish per-connection subscription state, so they must be
|
||||
// delivered on (and answered by) a specific connection, never failed over.
|
||||
reserved 4, 7;
|
||||
oneof message {
|
||||
WriteFile write_file = 1;
|
||||
DeleteFile delete_file = 2;
|
||||
ReadFileContextRequest read_file_context = 3;
|
||||
SaveBuffer save_buffer = 5;
|
||||
ResolveConflict resolve_conflict = 6;
|
||||
DiscardFilesRequest discard_files = 8;
|
||||
IndexCodebase index_codebase = 9;
|
||||
DropCodebaseIndex drop_codebase_index = 10;
|
||||
GetFragmentMetadataFromHash get_fragment_metadata_from_hash = 11;
|
||||
GetBranches get_branches = 12;
|
||||
ResyncCodebase resync_codebase = 13;
|
||||
UploadHandoffSnapshot upload_handoff_snapshot = 14;
|
||||
GitCommitChainRequest git_commit_chain = 15;
|
||||
GitPushRequest git_push = 16;
|
||||
GitCreatePrRequest git_create_pr = 17;
|
||||
GitGenerateCommitMessageRequest git_generate_commit_message = 18;
|
||||
GitGetCommittedBranchFilesRequest git_get_committed_branch_files = 19;
|
||||
RipgrepSearchRequest ripgrep_search = 21;
|
||||
}
|
||||
}
|
||||
|
||||
// Request that targets a specific connection/session.
|
||||
// The response is always delivered on the originating connection.
|
||||
message SessionScopedRequest {
|
||||
oneof message {
|
||||
Initialize initialize = 1;
|
||||
NavigatedToDirectory navigated_to_directory = 2;
|
||||
LoadRepoMetadataDirectory load_repo_metadata_directory = 3;
|
||||
RunCommandRequest run_command = 4;
|
||||
// Subscription-establishing requests: the daemon registers per-connection
|
||||
// state (buffer / diff-state subscriptions) keyed to the originating
|
||||
// connection, so the response must come back on that same connection.
|
||||
OpenBuffer open_buffer = 5;
|
||||
GetDiffState get_diff_state = 6;
|
||||
}
|
||||
}
|
||||
|
||||
// Fire-and-forget message. No response is expected.
|
||||
// The daemon processes these inline and does not track them.
|
||||
message Notification {
|
||||
oneof message {
|
||||
Abort abort = 1;
|
||||
Authenticate authenticate = 2;
|
||||
UpdatePreferences update_preferences = 3;
|
||||
SessionBootstrapped session_bootstrapped = 4;
|
||||
BufferEdit buffer_edit = 5;
|
||||
CloseBuffer close_buffer = 6;
|
||||
UnsubscribeDiffState unsubscribe_diff_state = 7;
|
||||
UpdateGitStatus update_git_status = 8;
|
||||
UpdateGitHubPrInfo update_github_pr_info = 9;
|
||||
UpdateGitHubRepoInfo update_github_repo_info = 10;
|
||||
}
|
||||
}
|
||||
// Top-level envelope for all server → client messages.
|
||||
@@ -41,17 +100,48 @@ message ServerMessage {
|
||||
DeleteFileResponse delete_file_response = 9;
|
||||
RunCommandResponse run_command_response = 10;
|
||||
ReadFileContextResponse read_file_context_response = 11;
|
||||
CodebaseIndexStatusesSnapshot codebase_index_statuses_snapshot = 12;
|
||||
CodebaseIndexStatusUpdated codebase_index_status_updated = 13;
|
||||
OpenBufferResponse open_buffer_response = 14;
|
||||
BufferUpdatedPush buffer_updated = 15;
|
||||
SaveBufferResponse save_buffer_response = 16;
|
||||
ResolveConflictResponse resolve_conflict_response = 17;
|
||||
GetDiffStateResponse get_diff_state_response = 18;
|
||||
DiffStateSnapshot diff_state_snapshot = 19;
|
||||
DiffStateMetadataUpdate diff_state_metadata_update = 20;
|
||||
DiffStateFileDelta diff_state_file_delta = 21;
|
||||
DiscardFilesResponse discard_files_response = 22;
|
||||
BufferConflictDetected buffer_conflict_detected = 23;
|
||||
GetFragmentMetadataFromHashResponse get_fragment_metadata_from_hash_response = 24;
|
||||
GetBranchesResponse get_branches_response = 25;
|
||||
UploadHandoffSnapshotResponse upload_handoff_snapshot_response = 26;
|
||||
GitCommitChainResponse git_commit_chain_response = 27;
|
||||
GitPushResponse git_push_response = 28;
|
||||
GitCreatePrResponse git_create_pr_response = 29;
|
||||
GitGenerateCommitMessageResponse git_generate_commit_message_response = 31;
|
||||
GitGetCommittedBranchFilesResponse git_get_committed_branch_files_response = 32;
|
||||
GitStatusPush git_status_push = 34;
|
||||
GitHubPrInfoPush github_pr_info_push = 35;
|
||||
GitHubRepositoryInfoPush github_repository_info_push = 36;
|
||||
RipgrepSearchResponse ripgrep_search_response = 37;
|
||||
RemoteAgentContextSnapshot remote_agent_context_snapshot = 33;
|
||||
}
|
||||
}
|
||||
|
||||
// ── Initialize handshake
|
||||
|
||||
// Sent by the client immediately after connecting to negotiate the protocol.
|
||||
message Initialize {
|
||||
// Optional bearer token used by the daemon for Warp-server requests.
|
||||
// Empty means no credential was available and does not clear an existing
|
||||
// daemon credential.
|
||||
string auth_token = 1;
|
||||
// User identity for Sentry crash reports. Empty when not logged in.
|
||||
string user_id = 2;
|
||||
string user_email = 3;
|
||||
// Whether the user has enabled crash reporting in their privacy settings.
|
||||
bool crash_reporting_enabled = 4;
|
||||
// Client-resolved codebase index limits for parity with local indexing.
|
||||
optional CodebaseIndexLimits codebase_index_limits = 5;
|
||||
}
|
||||
|
||||
// Sent by the client when its bearer credential rotates after initialization.
|
||||
@@ -63,6 +153,20 @@ message Authenticate {
|
||||
string auth_token = 1;
|
||||
}
|
||||
|
||||
// Sent by the client when the user's privacy preferences change.
|
||||
// This is a notification (fire-and-forget) — the server does not send a response.
|
||||
message UpdatePreferences {
|
||||
bool crash_reporting_enabled = 1;
|
||||
optional CodebaseIndexLimits codebase_index_limits = 2;
|
||||
}
|
||||
|
||||
message CodebaseIndexLimits {
|
||||
// Empty means unlimited.
|
||||
optional uint64 max_indices_allowed = 1;
|
||||
uint64 max_files_per_repo = 2;
|
||||
uint64 embedding_generation_batch_size = 3;
|
||||
}
|
||||
|
||||
// Sent by the client to cancel an in-progress request.
|
||||
// This is a notification (fire-and-forget) — the server does not send a response.
|
||||
message Abort {
|
||||
@@ -142,6 +246,47 @@ message ErrorResponse {
|
||||
string message = 2;
|
||||
}
|
||||
|
||||
// ── Remote Agent Mode context ─────────────────────────────────────
|
||||
|
||||
// Metadata specific to a skill bundled with Warp.
|
||||
message BundledSkillMetadata {
|
||||
// Directory-based skill ID, unique within the bundled catalog.
|
||||
string id = 1;
|
||||
// When set, the skill is only active while the named MCP integration
|
||||
// is running on the client (e.g. "figma"). Evaluated client-side.
|
||||
optional string requires_mcp = 2;
|
||||
}
|
||||
|
||||
// Marker metadata for a file-based skill from the daemon host's home directory.
|
||||
message HomeSkillMetadata {}
|
||||
|
||||
// One already-read remote skill published by the daemon.
|
||||
message RemoteSkillProto {
|
||||
// Absolute path to the file on this host.
|
||||
string path = 1;
|
||||
string content = 2;
|
||||
oneof source {
|
||||
BundledSkillMetadata bundled = 3;
|
||||
HomeSkillMetadata home = 4;
|
||||
}
|
||||
}
|
||||
|
||||
// One already-read remote context file published by the daemon.
|
||||
message RemoteContextFileProto {
|
||||
// Absolute path to the file on this host.
|
||||
string path = 1;
|
||||
string content = 2;
|
||||
}
|
||||
|
||||
// Revisioned full replacement of the daemon host's Agent Mode context. Source
|
||||
// discovery and reading happen daemon-side before this snapshot is published.
|
||||
message RemoteAgentContextSnapshot {
|
||||
uint64 revision = 1;
|
||||
string home_dir = 2;
|
||||
repeated RemoteSkillProto skills = 3;
|
||||
repeated RemoteContextFileProto global_rules = 4;
|
||||
}
|
||||
|
||||
// ── Shared repo metadata sub-messages ─────────────────────────────
|
||||
// Mirror the Rust types in repo_metadata/src/file_tree_update.rs.
|
||||
|
||||
@@ -174,6 +319,18 @@ message RepoMetadataEntryUpdate {
|
||||
repeated RepoNodeMetadata subtree_metadata = 2;
|
||||
}
|
||||
|
||||
message StandingQueryContent {
|
||||
string path = 1;
|
||||
bool is_directory = 2;
|
||||
}
|
||||
|
||||
message StandingQueryResultsDelta {
|
||||
repeated StandingQueryContent upserted_project_skills = 1;
|
||||
repeated StandingQueryContent removed_project_skills = 2;
|
||||
repeated StandingQueryContent upserted_project_rules = 3;
|
||||
repeated StandingQueryContent removed_project_rules = 4;
|
||||
}
|
||||
|
||||
// ── NavigatedToDirectory ──────────────────────────────────────────
|
||||
|
||||
// Client → server: "I navigated to this directory, please index it."
|
||||
@@ -294,6 +451,151 @@ message FileContextProto {
|
||||
uint32 line_count = 7;
|
||||
}
|
||||
|
||||
// ── Ripgrep search (global search) ────────────────────────────────
|
||||
|
||||
// Client → server: run a ripgrep search over the given root directories
|
||||
// on the host. Used by global search for remote sessions.
|
||||
message RipgrepSearchRequest {
|
||||
// Regex pattern. Already escaped client-side for literal (non-regex)
|
||||
// searches, matching local global search behavior.
|
||||
string pattern = 1;
|
||||
// Absolute directories on the host to search.
|
||||
repeated string roots = 2;
|
||||
bool ignore_case = 3;
|
||||
bool multiline = 4;
|
||||
// Maximum number of matched lines to return. The server also applies its
|
||||
// own match and approximate payload caps.
|
||||
uint32 max_matches = 5;
|
||||
}
|
||||
|
||||
// Server → client: result of a RipgrepSearchRequest.
|
||||
message RipgrepSearchResponse {
|
||||
oneof result {
|
||||
RipgrepSearchSuccess success = 1;
|
||||
RipgrepSearchError error = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message RipgrepSearchSuccess {
|
||||
repeated RipgrepSearchMatch matches = 1;
|
||||
// True when the search stopped early because the match cap was reached.
|
||||
bool capped = 2;
|
||||
}
|
||||
|
||||
message RipgrepSearchError {
|
||||
string message = 1;
|
||||
}
|
||||
|
||||
// A single matched line in a file. A line may contain multiple submatches;
|
||||
// the client expands them into per-submatch result rows.
|
||||
message RipgrepSearchMatch {
|
||||
string file_path = 1;
|
||||
uint32 line_number = 2;
|
||||
string line_text = 3;
|
||||
repeated RipgrepSearchSubmatch submatches = 4;
|
||||
}
|
||||
|
||||
// Byte offsets into `line_text` for one submatch (end exclusive).
|
||||
message RipgrepSearchSubmatch {
|
||||
uint64 byte_start = 1;
|
||||
uint64 byte_end = 2;
|
||||
}
|
||||
|
||||
// ── Remote codebase indexing status ───────────────────────────────
|
||||
|
||||
message IndexCodebase {
|
||||
string repo_path = 1;
|
||||
string auth_token = 2;
|
||||
}
|
||||
message ResyncCodebase {
|
||||
string repo_path = 1;
|
||||
string auth_token = 2;
|
||||
CodebaseResyncMode mode = 3;
|
||||
}
|
||||
enum CodebaseResyncMode {
|
||||
CODEBASE_RESYNC_MODE_FULL = 0;
|
||||
CODEBASE_RESYNC_MODE_INCREMENTAL = 1;
|
||||
}
|
||||
|
||||
message DropCodebaseIndex {
|
||||
string repo_path = 1;
|
||||
string auth_token = 2;
|
||||
}
|
||||
message GetFragmentMetadataFromHash {
|
||||
string repo_path = 1;
|
||||
string root_hash = 2;
|
||||
repeated string content_hashes = 3;
|
||||
}
|
||||
|
||||
message FragmentMetadata {
|
||||
string content_hash = 1;
|
||||
string path = 2;
|
||||
uint32 start_line = 3;
|
||||
uint32 end_line = 4;
|
||||
uint64 byte_start = 5;
|
||||
uint64 byte_end = 6;
|
||||
}
|
||||
|
||||
message MissingFragmentMetadata {
|
||||
string content_hash = 1;
|
||||
FileOperationError error = 2;
|
||||
}
|
||||
enum FragmentMetadataLookupErrorCode {
|
||||
FRAGMENT_METADATA_LOOKUP_ERROR_CODE_UNSPECIFIED = 0;
|
||||
REMOTE_CODEBASE_INDEXING_NOT_ENABLED = 1;
|
||||
INVALID_REPO_PATH = 2;
|
||||
INVALID_ROOT_HASH = 3;
|
||||
INDEX_NOT_FOUND = 4;
|
||||
INDEX_NOT_SYNCED = 5;
|
||||
ROOT_HASH_MISMATCH = 6;
|
||||
}
|
||||
|
||||
message FragmentMetadataLookupError {
|
||||
FragmentMetadataLookupErrorCode code = 1;
|
||||
string message = 2;
|
||||
optional string current_root_hash = 3;
|
||||
}
|
||||
message GetFragmentMetadataFromHashSuccess {
|
||||
repeated FragmentMetadata fragments = 1;
|
||||
repeated MissingFragmentMetadata missing_hashes = 2;
|
||||
}
|
||||
|
||||
message GetFragmentMetadataFromHashResponse {
|
||||
oneof result {
|
||||
GetFragmentMetadataFromHashSuccess success = 1;
|
||||
FragmentMetadataLookupError error = 2;
|
||||
}
|
||||
}
|
||||
|
||||
enum CodebaseIndexStatusState {
|
||||
CODEBASE_INDEX_STATUS_STATE_UNSPECIFIED = 0;
|
||||
CODEBASE_INDEX_STATUS_STATE_NOT_ENABLED = 1;
|
||||
CODEBASE_INDEX_STATUS_STATE_UNAVAILABLE = 2;
|
||||
CODEBASE_INDEX_STATUS_STATE_DISABLED = 3;
|
||||
CODEBASE_INDEX_STATUS_STATE_QUEUED = 4;
|
||||
CODEBASE_INDEX_STATUS_STATE_INDEXING = 5;
|
||||
CODEBASE_INDEX_STATUS_STATE_READY = 6;
|
||||
CODEBASE_INDEX_STATUS_STATE_STALE = 7;
|
||||
CODEBASE_INDEX_STATUS_STATE_FAILED = 8;
|
||||
}
|
||||
message CodebaseIndexStatus {
|
||||
string repo_path = 1;
|
||||
CodebaseIndexStatusState state = 2;
|
||||
optional uint64 last_updated_epoch_millis = 3;
|
||||
optional uint64 progress_completed = 4;
|
||||
optional uint64 progress_total = 5;
|
||||
optional string failure_message = 6;
|
||||
optional string root_hash = 7;
|
||||
}
|
||||
|
||||
message CodebaseIndexStatusesSnapshot {
|
||||
repeated CodebaseIndexStatus statuses = 1;
|
||||
}
|
||||
|
||||
message CodebaseIndexStatusUpdated {
|
||||
CodebaseIndexStatus status = 1;
|
||||
}
|
||||
|
||||
// ── Server → client push messages ─────────────────────────────────
|
||||
|
||||
// Full or lazy-loaded repo metadata snapshot. Pushed by the server after
|
||||
@@ -302,6 +604,7 @@ message RepoMetadataSnapshot {
|
||||
string repo_path = 1;
|
||||
repeated RepoMetadataEntryUpdate entries = 2;
|
||||
bool sync_complete = 3;
|
||||
StandingQueryResultsDelta standing_results = 4;
|
||||
}
|
||||
|
||||
// Incremental repo metadata update. Mirrors RepoMetadataUpdate in Rust.
|
||||
@@ -309,4 +612,125 @@ message RepoMetadataUpdatePush {
|
||||
string repo_path = 1;
|
||||
repeated string remove_entries = 2;
|
||||
repeated RepoMetadataEntryUpdate update_entries = 3;
|
||||
StandingQueryResultsDelta standing_results_delta = 4;
|
||||
}
|
||||
|
||||
// ── Buffer syncing ────────────────────────────────────────────────
|
||||
|
||||
// Client → server: open a buffer for bidirectional syncing.
|
||||
// The server reads the file, starts watching it, and returns the content.
|
||||
message OpenBuffer {
|
||||
string path = 1;
|
||||
// When true, the server discards any in-memory buffer state and re-reads
|
||||
// the file from disk. Used by the client to resolve conflicts ("accept
|
||||
// server" / discard local edits). Other connections that have the buffer
|
||||
// open receive a BufferUpdatedPush with the fresh content.
|
||||
bool force_reload = 2;
|
||||
}
|
||||
|
||||
// Server → client: response to OpenBuffer with the initial file content.
|
||||
message OpenBufferResponse {
|
||||
oneof result {
|
||||
OpenBufferSuccess success = 1;
|
||||
FileOperationError error = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message OpenBufferSuccess {
|
||||
string content = 1;
|
||||
uint64 server_version = 2;
|
||||
}
|
||||
|
||||
// Client → server: push an incremental edit (fire-and-forget notification).
|
||||
// If the server accepts (expected_server_version matches its local version),
|
||||
// it applies the edit silently — no response needed since the client already
|
||||
// has the edit applied locally.
|
||||
// If the server rejects (version mismatch), it pushes a BufferUpdatedPush
|
||||
// with its current state.
|
||||
message BufferEdit {
|
||||
string path = 1;
|
||||
uint64 expected_server_version = 2;
|
||||
uint64 new_client_version = 3;
|
||||
repeated TextEdit edits = 4;
|
||||
}
|
||||
|
||||
// A single text edit within a buffer, using 1-indexed character offsets (matching CharOffset).
|
||||
message TextEdit {
|
||||
uint64 start_offset = 1;
|
||||
uint64 end_offset = 2;
|
||||
string text = 3;
|
||||
}
|
||||
|
||||
// Server → client push: file changed on disk.
|
||||
// The client uses expected_client_version to detect conflicts.
|
||||
// Carries only incremental edits — full content is served by OpenBufferResponse.
|
||||
message BufferUpdatedPush {
|
||||
string path = 1;
|
||||
uint64 new_server_version = 2;
|
||||
uint64 expected_client_version = 3;
|
||||
repeated TextEdit edits = 4;
|
||||
}
|
||||
|
||||
// Client → server: request the daemon gather a handoff snapshot and upload it.
|
||||
// All paths must be absolute paths on the remote host's filesystem.
|
||||
message UploadHandoffSnapshot {
|
||||
// Absolute paths the agent touched (file edits, working directories).
|
||||
// Non-absolute or empty entries are rejected by the daemon.
|
||||
repeated string paths = 1;
|
||||
}
|
||||
|
||||
// Daemon → client: result of the handoff snapshot upload.
|
||||
message UploadHandoffSnapshotResponse {
|
||||
optional string initial_snapshot_token = 1;
|
||||
bool success = 2;
|
||||
optional string error = 3;
|
||||
}
|
||||
|
||||
// Client → server: close a buffer (stop watching).
|
||||
message CloseBuffer {
|
||||
string path = 1;
|
||||
}
|
||||
|
||||
// Client → server: persist the current in-memory buffer to disk.
|
||||
message SaveBuffer {
|
||||
string path = 1;
|
||||
}
|
||||
|
||||
// Server → client: result of a SaveBuffer request.
|
||||
message SaveBufferResponse {
|
||||
oneof result {
|
||||
SaveBufferSuccess success = 1;
|
||||
FileOperationError error = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message SaveBufferSuccess {}
|
||||
|
||||
// Client → server: resolve a conflict by accepting the client's content.
|
||||
// The server replaces its in-memory buffer with client_content,
|
||||
// updates the clock to {acknowledged_server_version, current_client_version},
|
||||
// and persists to disk (updates base_content_version to avoid re-triggering).
|
||||
// For "accept server", the client simply re-sends OpenBuffer instead.
|
||||
message ResolveConflict {
|
||||
string path = 1;
|
||||
uint64 acknowledged_server_version = 2;
|
||||
string client_content = 3;
|
||||
uint64 current_client_version = 4;
|
||||
}
|
||||
|
||||
// Server → client: result of a ResolveConflict request.
|
||||
message ResolveConflictResponse {
|
||||
oneof result {
|
||||
ResolveConflictSuccess success = 1;
|
||||
FileOperationError error = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message ResolveConflictSuccess {}
|
||||
|
||||
// Server → client push: the file changed on disk while the client had
|
||||
// unsaved edits. The server does NOT apply the disk change to its buffer;
|
||||
// the client should show a conflict resolution banner.
|
||||
message BufferConflictDetected {
|
||||
string path = 1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user