// 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; }