zed.proto

  1syntax = "proto3";
  2package zed.messages;
  3
  4message Envelope {
  5    uint32 id = 1;
  6    optional uint32 responding_to = 2;
  7    optional uint32 original_sender_id = 3;
  8    oneof payload {
  9        Ack ack = 4;
 10        Error error = 5;
 11        Ping ping = 6;
 12        Test test = 7;
 13
 14        RegisterProject register_project = 8;
 15        RegisterProjectResponse register_project_response = 9;
 16        UnregisterProject unregister_project = 10;
 17        RequestJoinProject request_join_project = 11;
 18        RespondToJoinProjectRequest respond_to_join_project_request = 12;
 19        JoinProjectRequestCancelled join_project_request_cancelled = 13;
 20        JoinProject join_project = 14;
 21        JoinProjectResponse join_project_response = 15;
 22        LeaveProject leave_project = 16;
 23        AddProjectCollaborator add_project_collaborator = 17;
 24        RemoveProjectCollaborator remove_project_collaborator = 18;
 25        ProjectUnshared project_unshared = 19;
 26
 27        GetDefinition get_definition = 20;
 28        GetDefinitionResponse get_definition_response = 21;
 29        GetReferences get_references = 22;
 30        GetReferencesResponse get_references_response = 23;
 31        GetDocumentHighlights get_document_highlights = 24;
 32        GetDocumentHighlightsResponse get_document_highlights_response = 25;
 33        GetProjectSymbols get_project_symbols = 26;
 34        GetProjectSymbolsResponse get_project_symbols_response = 27;
 35        OpenBufferForSymbol open_buffer_for_symbol = 28;
 36        OpenBufferForSymbolResponse open_buffer_for_symbol_response = 29;
 37
 38        UpdateProject update_project = 30;
 39        UpdateWorktree update_worktree = 32;
 40
 41        CreateProjectEntry create_project_entry = 33;
 42        RenameProjectEntry rename_project_entry = 34;
 43        CopyProjectEntry copy_project_entry = 35;
 44        DeleteProjectEntry delete_project_entry = 36;
 45        ProjectEntryResponse project_entry_response = 37;
 46
 47        UpdateDiagnosticSummary update_diagnostic_summary = 38;
 48        StartLanguageServer start_language_server = 39;
 49        UpdateLanguageServer update_language_server = 40;
 50
 51        OpenBufferById open_buffer_by_id = 41;
 52        OpenBufferByPath open_buffer_by_path = 42;
 53        OpenBufferResponse open_buffer_response = 43;
 54        UpdateBuffer update_buffer = 44;
 55        UpdateBufferFile update_buffer_file = 45;
 56        SaveBuffer save_buffer = 46;
 57        BufferSaved buffer_saved = 47;
 58        BufferReloaded buffer_reloaded = 48;
 59        ReloadBuffers reload_buffers = 49;
 60        ReloadBuffersResponse reload_buffers_response = 50;
 61        FormatBuffers format_buffers = 51;
 62        FormatBuffersResponse format_buffers_response = 52;
 63        GetCompletions get_completions = 53;
 64        GetCompletionsResponse get_completions_response = 54;
 65        ApplyCompletionAdditionalEdits apply_completion_additional_edits = 55;
 66        ApplyCompletionAdditionalEditsResponse apply_completion_additional_edits_response = 56;
 67        GetCodeActions get_code_actions = 57;
 68        GetCodeActionsResponse get_code_actions_response = 58;
 69        GetHover get_hover = 59;
 70        GetHoverResponse get_hover_response = 60;
 71        ApplyCodeAction apply_code_action = 61;
 72        ApplyCodeActionResponse apply_code_action_response = 62;
 73        PrepareRename prepare_rename = 63;
 74        PrepareRenameResponse prepare_rename_response = 64;
 75        PerformRename perform_rename = 65;
 76        PerformRenameResponse perform_rename_response = 66;
 77        SearchProject search_project = 67;
 78        SearchProjectResponse search_project_response = 68;
 79
 80        GetChannels get_channels = 69;
 81        GetChannelsResponse get_channels_response = 70;
 82        JoinChannel join_channel = 71;
 83        JoinChannelResponse join_channel_response = 72;
 84        LeaveChannel leave_channel = 73;
 85        SendChannelMessage send_channel_message = 74;
 86        SendChannelMessageResponse send_channel_message_response = 75;
 87        ChannelMessageSent channel_message_sent = 76;
 88        GetChannelMessages get_channel_messages = 77;
 89        GetChannelMessagesResponse get_channel_messages_response = 78;
 90
 91        UpdateContacts update_contacts = 79;
 92        UpdateInviteInfo update_invite_info = 80;
 93        ShowContacts show_contacts = 81;
 94
 95        GetUsers get_users = 82;
 96        FuzzySearchUsers fuzzy_search_users = 83;
 97        UsersResponse users_response = 84;
 98        RequestContact request_contact = 85;
 99        RespondToContactRequest respond_to_contact_request = 86;
100        RemoveContact remove_contact = 87;
101
102        Follow follow = 88;
103        FollowResponse follow_response = 89;
104        UpdateFollowers update_followers = 90;
105        Unfollow unfollow = 91;
106    }
107}
108
109// Messages
110
111message Ping {}
112
113message Ack {}
114
115message Error {
116    string message = 1;
117}
118
119message Test {
120    uint64 id = 1;
121}
122
123message RegisterProject {}
124
125message RegisterProjectResponse {
126    uint64 project_id = 1;
127}
128
129message UnregisterProject {
130    uint64 project_id = 1;
131}
132
133message UpdateProject {
134    uint64 project_id = 1;
135    repeated WorktreeMetadata worktrees = 2;
136}
137
138message RequestJoinProject {
139    uint64 requester_id = 1;
140    uint64 project_id = 2;
141}
142
143message RespondToJoinProjectRequest {
144    uint64 requester_id = 1;
145    uint64 project_id = 2;
146    bool allow = 3;
147}
148
149message JoinProjectRequestCancelled {
150    uint64 requester_id = 1;
151    uint64 project_id = 2;
152}
153
154message JoinProject {
155    uint64 project_id = 1;
156}
157
158message JoinProjectResponse {
159    oneof variant {
160        Accept accept = 1;
161        Decline decline = 2;
162    }
163
164    message Accept {
165        uint32 replica_id = 1;
166        repeated Worktree worktrees = 2;
167        repeated Collaborator collaborators = 3;
168        repeated LanguageServer language_servers = 4;        
169    }
170    
171    message Decline {
172        Reason reason = 1;
173
174        enum Reason {
175            Declined = 0;
176            Closed = 1;
177            WentOffline = 2;
178        }
179    }
180}
181
182message LeaveProject {
183    uint64 project_id = 1;
184}
185
186message UpdateWorktree {
187    uint64 project_id = 1;
188    uint64 worktree_id = 2;
189    string root_name = 3;
190    repeated Entry updated_entries = 4;
191    repeated uint64 removed_entries = 5;
192    uint64 scan_id = 6;
193}
194
195message CreateProjectEntry {
196    uint64 project_id = 1;
197    uint64 worktree_id = 2;
198    bytes path = 3;
199    bool is_directory = 4;
200}
201
202message RenameProjectEntry {
203    uint64 project_id = 1;
204    uint64 entry_id = 2;
205    bytes new_path = 3;
206}
207
208message CopyProjectEntry {
209    uint64 project_id = 1;
210    uint64 entry_id = 2;
211    bytes new_path = 3;
212}
213
214message DeleteProjectEntry {
215    uint64 project_id = 1;
216    uint64 entry_id = 2;
217}
218
219message ProjectEntryResponse {
220    Entry entry = 1;
221    uint64 worktree_scan_id = 2;
222}
223
224message AddProjectCollaborator {
225    uint64 project_id = 1;
226    Collaborator collaborator = 2;
227}
228
229message RemoveProjectCollaborator {
230    uint64 project_id = 1;
231    uint32 peer_id = 2;
232}
233
234message ProjectUnshared {
235    uint64 project_id = 1;
236}
237
238message GetDefinition {
239     uint64 project_id = 1;
240     uint64 buffer_id = 2;
241     Anchor position = 3;
242     repeated VectorClockEntry version = 4;
243 }
244
245message GetDefinitionResponse {
246    repeated Location locations = 1;
247}
248
249message GetReferences {
250     uint64 project_id = 1;
251     uint64 buffer_id = 2;
252     Anchor position = 3;
253     repeated VectorClockEntry version = 4;
254 }
255
256message GetReferencesResponse {
257    repeated Location locations = 1;
258}
259
260message GetDocumentHighlights {
261     uint64 project_id = 1;
262     uint64 buffer_id = 2;
263     Anchor position = 3;
264     repeated VectorClockEntry version = 4;
265 }
266
267message GetDocumentHighlightsResponse {
268    repeated DocumentHighlight highlights = 1;
269}
270
271message Location {
272    Buffer buffer = 1;
273    Anchor start = 2;
274    Anchor end = 3;
275}
276
277message DocumentHighlight {
278    Kind kind = 1;
279    Anchor start = 2;
280    Anchor end = 3;
281
282    enum Kind {
283        Text = 0;
284        Read = 1;
285        Write = 2;
286    }
287}
288
289message GetProjectSymbols {
290    uint64 project_id = 1;
291    string query = 2;
292}
293
294message GetProjectSymbolsResponse {
295    repeated Symbol symbols = 4;
296}
297
298message Symbol {
299    uint64 source_worktree_id = 1;
300    uint64 worktree_id = 2;
301    string language_server_name = 3;
302    string name = 4;
303    int32 kind = 5;
304    string path = 6;
305    Point start = 7;
306    Point end = 8;
307    bytes signature = 9;
308}
309
310message OpenBufferForSymbol {
311    uint64 project_id = 1;
312    Symbol symbol = 2;
313}
314
315message OpenBufferForSymbolResponse {
316    Buffer buffer = 1;
317}
318
319message OpenBufferByPath {
320    uint64 project_id = 1;
321    uint64 worktree_id = 2;
322    string path = 3;
323}
324
325message OpenBufferById {
326    uint64 project_id = 1;
327    uint64 id = 2;
328}
329
330message OpenBufferResponse {
331    Buffer buffer = 1;
332}
333
334message CloseBuffer {
335    uint64 project_id = 1;
336    uint64 buffer_id = 2;
337}
338
339message UpdateBuffer {
340    uint64 project_id = 1;
341    uint64 buffer_id = 2;
342    repeated Operation operations = 3;
343}
344
345message UpdateBufferFile {
346    uint64 project_id = 1;
347    uint64 buffer_id = 2;
348    File file = 3;
349}
350
351message SaveBuffer {
352    uint64 project_id = 1;
353    uint64 buffer_id = 2;
354    repeated VectorClockEntry version = 3;
355}
356
357message BufferSaved {
358    uint64 project_id = 1;
359    uint64 buffer_id = 2;
360    repeated VectorClockEntry version = 3;
361    Timestamp mtime = 4;
362}
363
364message BufferReloaded {
365    uint64 project_id = 1;
366    uint64 buffer_id = 2;
367    repeated VectorClockEntry version = 3;
368    Timestamp mtime = 4;
369}
370
371message ReloadBuffers {
372    uint64 project_id = 1;
373    repeated uint64 buffer_ids = 2;
374}
375
376message ReloadBuffersResponse {
377    ProjectTransaction transaction = 1;
378}
379
380message FormatBuffers {
381    uint64 project_id = 1;
382    repeated uint64 buffer_ids = 2;
383}
384
385message FormatBuffersResponse {
386    ProjectTransaction transaction = 1;
387}
388
389message GetCompletions {
390    uint64 project_id = 1;
391    uint64 buffer_id = 2;
392    Anchor position = 3;
393    repeated VectorClockEntry version = 4;
394}
395
396message GetCompletionsResponse {
397    repeated Completion completions = 1;
398    repeated VectorClockEntry version = 2;
399}
400
401message ApplyCompletionAdditionalEdits {
402    uint64 project_id = 1;
403    uint64 buffer_id = 2;
404    Completion completion = 3;
405}
406
407message ApplyCompletionAdditionalEditsResponse {
408    Transaction transaction = 1;
409}
410
411message Completion {
412    Anchor old_start = 1;
413    Anchor old_end = 2;
414    string new_text = 3;
415    bytes lsp_completion = 4;
416}
417
418message GetCodeActions {
419    uint64 project_id = 1;
420    uint64 buffer_id = 2;
421    Anchor start = 3;
422    Anchor end = 4;
423    repeated VectorClockEntry version = 5;
424}
425
426message GetCodeActionsResponse {
427    repeated CodeAction actions = 1;
428    repeated VectorClockEntry version = 2;
429}
430
431message GetHover {
432    uint64 project_id = 1;
433    uint64 buffer_id = 2;
434    Anchor position = 3;
435    repeated VectorClockEntry version = 5;
436}
437
438message GetHoverResponse {
439    optional Anchor start = 1;
440    optional Anchor end = 2;
441    repeated HoverBlock contents = 3;
442}
443
444message HoverBlock {
445    string text = 1;
446    optional string language = 2;
447}
448
449message ApplyCodeAction {
450    uint64 project_id = 1;
451    uint64 buffer_id = 2;
452    CodeAction action = 3;
453}
454
455message ApplyCodeActionResponse {
456    ProjectTransaction transaction = 1;
457}
458
459message PrepareRename {
460    uint64 project_id = 1;
461    uint64 buffer_id = 2;
462    Anchor position = 3;
463    repeated VectorClockEntry version = 4;
464}
465
466message PrepareRenameResponse {
467    bool can_rename = 1;
468    Anchor start = 2;
469    Anchor end = 3;
470    repeated VectorClockEntry version = 4;
471}
472
473message PerformRename {
474    uint64 project_id = 1;
475    uint64 buffer_id = 2;
476    Anchor position = 3;
477    string new_name = 4;
478    repeated VectorClockEntry version = 5;
479}
480
481message PerformRenameResponse {
482    ProjectTransaction transaction = 2;
483}
484
485message SearchProject {
486    uint64 project_id = 1;
487    string query = 2;
488    bool regex = 3;
489    bool whole_word = 4;
490    bool case_sensitive = 5;
491}
492
493message SearchProjectResponse {
494    repeated Location locations = 1;
495}
496
497message CodeAction {
498    Anchor start = 1;
499    Anchor end = 2;
500    bytes lsp_action = 3;
501}
502
503message ProjectTransaction {
504    repeated Buffer buffers = 1;
505    repeated Transaction transactions = 2;
506}
507
508message Transaction {
509    LocalTimestamp id = 1;
510    repeated LocalTimestamp edit_ids = 2;
511    repeated VectorClockEntry start = 3;
512    repeated VectorClockEntry end = 4;
513    repeated Range ranges = 5;
514}
515
516message LocalTimestamp {
517    uint32 replica_id = 1;
518    uint32 value = 2;
519}
520
521message LanguageServer {
522    uint64 id = 1;
523    string name = 2;
524}
525
526message StartLanguageServer {
527    uint64 project_id = 1;
528    LanguageServer server = 2;
529}
530
531message UpdateDiagnosticSummary {
532    uint64 project_id = 1;
533    uint64 worktree_id = 2;
534    DiagnosticSummary summary = 3;
535}
536
537message DiagnosticSummary {
538    string path = 1;
539    uint64 language_server_id = 2;
540    uint32 error_count = 3;
541    uint32 warning_count = 4;
542}
543
544message UpdateLanguageServer {
545    uint64 project_id = 1;
546    uint64 language_server_id = 2;
547    oneof variant {
548        LspWorkStart work_start = 3;
549        LspWorkProgress work_progress = 4;
550        LspWorkEnd work_end = 5;
551        LspDiskBasedDiagnosticsUpdating disk_based_diagnostics_updating = 6;
552        LspDiskBasedDiagnosticsUpdated disk_based_diagnostics_updated = 7;
553    }
554}
555
556message LspWorkStart {
557    string token = 1;
558    optional string message = 2;
559    optional uint32 percentage = 3;
560}
561
562message LspWorkProgress {
563    string token = 1;
564    optional string message = 2;
565    optional uint32 percentage = 3;
566}
567
568message LspWorkEnd {
569    string token = 1;
570}
571
572message LspDiskBasedDiagnosticsUpdating {}
573
574message LspDiskBasedDiagnosticsUpdated {}
575
576message GetChannels {}
577
578message GetChannelsResponse {
579    repeated Channel channels = 1;
580}
581
582message JoinChannel {
583    uint64 channel_id = 1;
584}
585
586message JoinChannelResponse {
587    repeated ChannelMessage messages = 1;
588    bool done = 2;
589}
590
591message LeaveChannel {
592    uint64 channel_id = 1;
593}
594
595message GetUsers {
596    repeated uint64 user_ids = 1;
597}
598
599message FuzzySearchUsers {
600    string query = 1;
601}
602
603message UsersResponse {
604    repeated User users = 1;
605}
606
607message RequestContact {
608    uint64 responder_id = 1;
609}
610
611message RemoveContact {
612    uint64 user_id = 1;
613}
614
615message RespondToContactRequest {
616    uint64 requester_id = 1;
617    ContactRequestResponse response = 2;
618}
619
620enum ContactRequestResponse {
621    Accept = 0;
622    Decline = 1;
623    Block = 2;
624    Dismiss = 3;
625}
626
627message SendChannelMessage {
628    uint64 channel_id = 1;
629    string body = 2;
630    Nonce nonce = 3;
631}
632
633message SendChannelMessageResponse {
634    ChannelMessage message = 1;
635}
636
637message ChannelMessageSent {
638    uint64 channel_id = 1;
639    ChannelMessage message = 2;
640}
641
642message GetChannelMessages {
643    uint64 channel_id = 1;
644    uint64 before_message_id = 2;
645}
646
647message GetChannelMessagesResponse {
648    repeated ChannelMessage messages = 1;
649    bool done = 2;
650}
651
652message UpdateContacts {
653    repeated Contact contacts = 1;
654    repeated uint64 remove_contacts = 2;
655    repeated IncomingContactRequest incoming_requests = 3;
656    repeated uint64 remove_incoming_requests = 4;
657    repeated uint64 outgoing_requests = 5;
658    repeated uint64 remove_outgoing_requests = 6;
659}
660
661message UpdateInviteInfo {
662    string url = 1;
663    uint32 count = 2;
664}
665
666message ShowContacts {}
667
668message IncomingContactRequest {
669    uint64 requester_id = 1;
670    bool should_notify = 2;
671}
672
673message UpdateDiagnostics {
674    uint32 replica_id = 1;
675    uint32 lamport_timestamp = 2;
676    repeated Diagnostic diagnostics = 3;
677}
678
679message Follow {
680    uint64 project_id = 1;
681    uint32 leader_id = 2;
682}
683
684message FollowResponse {
685    optional uint64 active_view_id = 1;
686    repeated View views = 2;
687}
688
689message UpdateFollowers {
690    uint64 project_id = 1;
691    repeated uint32 follower_ids = 2;
692    oneof variant {
693        UpdateActiveView update_active_view = 3;
694        View create_view = 4;
695        UpdateView update_view = 5;
696    }
697}
698
699message Unfollow {
700    uint64 project_id = 1;
701    uint32 leader_id = 2;
702}
703
704// Entities
705
706message UpdateActiveView {
707    optional uint64 id = 1;
708    optional uint32 leader_id = 2;
709}
710
711message UpdateView {
712    uint64 id = 1;
713    optional uint32 leader_id = 2;
714
715    oneof variant {
716        Editor editor = 3;
717    }
718
719    message Editor {
720        repeated Selection selections = 1;
721        Anchor scroll_top_anchor = 2;
722        float scroll_x = 3;
723        float scroll_y = 4;
724    }
725}
726
727message View {
728    uint64 id = 1;
729    optional uint32 leader_id = 2;
730
731    oneof variant {
732        Editor editor = 3;
733    }
734
735    message Editor {
736        uint64 buffer_id = 1;
737        repeated Selection selections = 2;
738        Anchor scroll_top_anchor = 3;
739        float scroll_x = 4;
740        float scroll_y = 5;
741    }
742}
743
744message Collaborator {
745    uint32 peer_id = 1;
746    uint32 replica_id = 2;
747    uint64 user_id = 3;
748}
749
750message User {
751    uint64 id = 1;
752    string github_login = 2;
753    string avatar_url = 3;
754}
755
756message Worktree {
757    uint64 id = 1;
758    string root_name = 2;
759    repeated Entry entries = 3;
760    repeated DiagnosticSummary diagnostic_summaries = 4;
761    bool visible = 5;
762    uint64 scan_id = 6;
763}
764
765message File {
766    uint64 worktree_id = 1;
767    optional uint64 entry_id = 2;
768    string path = 3;
769    Timestamp mtime = 4;
770}
771
772message Entry {
773    uint64 id = 1;
774    bool is_dir = 2;
775    bytes path = 3;
776    uint64 inode = 4;
777    Timestamp mtime = 5;
778    bool is_symlink = 6;
779    bool is_ignored = 7;
780}
781
782message Buffer {
783    oneof variant {
784        uint64 id = 1;
785        BufferState state = 2;
786    }
787}
788
789message BufferState {
790    uint64 id = 1;
791    optional File file = 2;
792    string base_text = 3;
793    repeated Operation operations = 4;
794    repeated SelectionSet selections = 5;
795    repeated Diagnostic diagnostics = 6;
796    uint32 diagnostics_timestamp = 7;
797    repeated string completion_triggers = 8;
798}
799
800message SelectionSet {
801    uint32 replica_id = 1;
802    repeated Selection selections = 2;
803    uint32 lamport_timestamp = 3;
804    bool line_mode = 4;
805}
806
807message Selection {
808    uint64 id = 1;
809    Anchor start = 2;
810    Anchor end = 3;
811    bool reversed = 4;
812}
813
814message Anchor {
815    uint32 replica_id = 1;
816    uint32 local_timestamp = 2;
817    uint64 offset = 3;
818    Bias bias = 4;
819    optional uint64 buffer_id = 5;
820}
821
822enum Bias {
823    Left = 0;
824    Right = 1;
825}
826
827message Diagnostic {
828    Anchor start = 1;
829    Anchor end = 2;
830    Severity severity = 3;
831    string message = 4;
832    optional string code = 5;
833    uint64 group_id = 6;
834    bool is_primary = 7;
835    bool is_valid = 8;
836    bool is_disk_based = 9;
837    bool is_unnecessary = 10;
838
839    enum Severity {
840        None = 0;
841        Error = 1;
842        Warning = 2;
843        Information = 3;
844        Hint = 4;
845    }
846}
847
848message Operation {
849    oneof variant {
850        Edit edit = 1;
851        Undo undo = 2;
852        UpdateSelections update_selections = 3;
853        UpdateDiagnostics update_diagnostics = 4;
854        UpdateCompletionTriggers update_completion_triggers = 5;
855    }
856
857    message Edit {
858        uint32 replica_id = 1;
859        uint32 local_timestamp = 2;
860        uint32 lamport_timestamp = 3;
861        repeated VectorClockEntry version = 4;
862        repeated Range ranges = 5;
863        repeated string new_text = 6;
864    }
865
866    message Undo {
867        uint32 replica_id = 1;
868        uint32 local_timestamp = 2;
869        uint32 lamport_timestamp = 3;
870        repeated VectorClockEntry version = 4;
871        repeated Range transaction_ranges = 5;
872        repeated VectorClockEntry transaction_version = 6;
873        repeated UndoCount counts = 7;
874    }
875
876    message UpdateSelections {
877        uint32 replica_id = 1;
878        uint32 lamport_timestamp = 2;
879        repeated Selection selections = 3;
880        bool line_mode = 4;
881    }
882
883    message UpdateCompletionTriggers {
884        uint32 replica_id = 1;
885        uint32 lamport_timestamp = 2;
886        repeated string triggers = 3;
887    }
888}
889
890message UndoMapEntry {
891    uint32 replica_id = 1;
892    uint32 local_timestamp = 2;
893    repeated UndoCount counts = 3;
894}
895
896message UndoCount {
897    uint32 replica_id = 1;
898    uint32 local_timestamp = 2;
899    uint32 count = 3;
900}
901
902message VectorClockEntry {
903    uint32 replica_id = 1;
904    uint32 timestamp = 2;
905}
906
907message Timestamp {
908    uint64 seconds = 1;
909    uint32 nanos = 2;
910}
911
912message Range {
913    uint64 start = 1;
914    uint64 end = 2;
915}
916
917message Point {
918    uint32 row = 1;
919    uint32 column = 2;
920}
921
922message Nonce {
923    uint64 upper_half = 1;
924    uint64 lower_half = 2;
925}
926
927message Channel {
928    uint64 id = 1;
929    string name = 2;
930}
931
932message ChannelMessage {
933    uint64 id = 1;
934    string body = 2;
935    uint64 timestamp = 3;
936    uint64 sender_id = 4;
937    Nonce nonce = 5;
938}
939
940message Contact {
941    uint64 user_id = 1;
942    repeated ProjectMetadata projects = 2;
943    bool online = 3;
944    bool should_notify = 4;
945}
946
947message ProjectMetadata {
948    uint64 id = 1;
949    repeated string worktree_root_names = 3;
950    repeated uint64 guests = 4;
951}
952
953message WorktreeMetadata {
954    uint64 id = 1;
955    string root_name = 2;
956    bool visible = 3;
957}