@@ -33,6 +33,7 @@ pub(crate) fn complete<P: WorkspaceProvider>(
3333 match subcommand {
3434 "auth" => complete_auth ( current, & args_before, & mut workspace_ctx) ,
3535 "create" => complete_create ( current, & args_before) ,
36+ "rsync" => complete_rsync ( current, & args_before, & mut workspace_ctx) ,
3637 "ls" => complete_ls ( current, & args_before) ,
3738 "rm" => complete_rm ( & args_before, & mut workspace_ctx) ,
3839 "exec" => complete_exec ( current, & args_before, & mut workspace_ctx) ,
@@ -57,6 +58,7 @@ fn complete_top_level(_current: &str) -> Vec<Candidate> {
5758 & [
5859 ( "auth" , "Update auth material in workspace" ) ,
5960 ( "create" , "Create a new workspace" ) ,
61+ ( "rsync" , "Sync files between host and container" ) ,
6062 ( "ls" , "List workspaces" ) ,
6163 ( "rm" , "Remove workspace(s)" ) ,
6264 ( "exec" , "Run command in workspace" ) ,
@@ -68,6 +70,89 @@ fn complete_top_level(_current: &str) -> Vec<Candidate> {
6870 out
6971}
7072
73+ fn complete_rsync < P : WorkspaceProvider > (
74+ current : & str ,
75+ args_before : & [ String ] ,
76+ workspace_ctx : & mut WorkspaceContext < ' _ , P > ,
77+ ) -> Vec < Candidate > {
78+ if let Some ( ( option, inline) ) = value_option ( args_before, current, & [ "--user" ] ) {
79+ return value_suggestions_described (
80+ & option,
81+ inline,
82+ & [
83+ ( "0" , "UID 0 (root)" ) ,
84+ ( "root" , "Root user" ) ,
85+ ( "agent" , "Default agent user" ) ,
86+ ( "codex" , "Alternate codex user" ) ,
87+ ] ,
88+ ) ;
89+ }
90+
91+ let mut direction: Option < & str > = None ;
92+ let mut idx = 0usize ;
93+ while idx < args_before. len ( ) {
94+ let token = args_before[ idx] . as_str ( ) ;
95+ if token. starts_with ( '-' ) {
96+ idx += 1 ;
97+ continue ;
98+ }
99+ direction = Some ( token) ;
100+ idx += 1 ;
101+ break ;
102+ }
103+
104+ let mut out: Vec < Candidate > = Vec :: new ( ) ;
105+ if direction. is_none ( ) {
106+ push_described_values (
107+ & mut out,
108+ & [
109+ ( "push" , "Sync host files into workspace" ) ,
110+ ( "pull" , "Sync workspace files to host" ) ,
111+ ( "--help" , "Show help for rsync" ) ,
112+ ( "-h" , "Show help for rsync" ) ,
113+ ] ,
114+ ) ;
115+ push_global_options ( & mut out) ;
116+ return out;
117+ }
118+
119+ let mut positional_seen = 0usize ;
120+ let mut j = idx;
121+ while j < args_before. len ( ) {
122+ let token = args_before[ j] . as_str ( ) ;
123+ match token {
124+ "--user" | "-u" => j += 2 ,
125+ _ if token. starts_with ( "--user=" ) => j += 1 ,
126+ "--root" | "--delete" | "--dry-run" | "-n" | "--help" | "-h" => j += 1 ,
127+ _ if token. starts_with ( '-' ) => j += 1 ,
128+ _ => {
129+ positional_seen += 1 ;
130+ j += 1 ;
131+ }
132+ }
133+ }
134+
135+ push_described_values (
136+ & mut out,
137+ & [
138+ ( "--user" , "Run rsync inside container as user" ) ,
139+ ( "--root" , "Run rsync inside container as root" ) ,
140+ ( "--delete" , "Delete files not present at source" ) ,
141+ ( "--dry-run" , "Preview changes without writing" ) ,
142+ ( "-n" , "Alias of --dry-run" ) ,
143+ ( "--help" , "Show help for rsync" ) ,
144+ ( "-h" , "Show help for rsync" ) ,
145+ ] ,
146+ ) ;
147+ push_global_options ( & mut out) ;
148+
149+ if positional_seen == 0 {
150+ out. extend ( workspace_ctx. workspace_candidates ( None ) ) ;
151+ }
152+
153+ out
154+ }
155+
71156fn complete_create ( current : & str , args_before : & [ String ] ) -> Vec < Candidate > {
72157 if let Some ( ( option, inline) ) = value_option (
73158 args_before,
0 commit comments