Skip to content

Commit 1d4d4a2

Browse files
Equivalent Rust support
1 parent a2baee6 commit 1d4d4a2

2 files changed

Lines changed: 81 additions & 1 deletion

File tree

‎docs/features/remote-sessions.md‎

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,30 @@ session.On((SessionEvent e) =>
9393
});
9494
```
9595

96+
#### **Rust**
97+
98+
<!-- docs-validate: skip -->
99+
```rust
100+
use copilot_sdk::{Client, ClientOptions};
101+
102+
let client = Client::start(
103+
ClientOptions::new().with_remote(true)
104+
).await?;
105+
let session = client.create_session(
106+
SessionConfig::new("/path/to/github-repo")
107+
.with_permission_handler(|_req, _inv| async {
108+
Ok(PermissionRequestResult::approved())
109+
}),
110+
).await?;
111+
112+
let mut events = session.subscribe();
113+
while let Ok(event) = events.recv().await {
114+
if event.event_type == "session.info" {
115+
// Check info_type and extract URL
116+
}
117+
}
118+
```
119+
96120
<!-- tabs:end -->
97121

98122
### On-demand (per-session toggle)
@@ -147,6 +171,19 @@ Console.WriteLine($"Remote URL: {result.Url}");
147171
await session.Rpc.Remote.DisableAsync();
148172
```
149173

174+
#### **Rust**
175+
176+
<!-- docs-validate: skip -->
177+
```rust
178+
let result = session.rpc().remote().enable().await?;
179+
if let Some(url) = &result.url {
180+
println!("Remote URL: {url}");
181+
}
182+
183+
// Later: stop sharing
184+
session.rpc().remote().disable().await?;
185+
```
186+
150187
<!-- tabs:end -->
151188

152189
## QR Code Generation
@@ -157,6 +194,7 @@ The remote URL can be rendered as a QR code for easy mobile access. The SDK prov
157194
- **Python**: [qrcode](https://pypi.org/project/qrcode/)
158195
- **Go**: [go-qrcode](https://github.com/skip2/go-qrcode)
159196
- **C#**: [QRCoder](https://www.nuget.org/packages/QRCoder)
197+
- **Rust**: [qrcode](https://crates.io/crates/qrcode)
160198

161199
## Notes
162200

‎rust/src/lib.rs‎

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,12 @@ pub struct ClientOptions {
393393
/// is safe by default. Combining with [`Transport::Stdio`] is invalid
394394
/// and surfaces as an error from [`Client::start`].
395395
pub tcp_connection_token: Option<String>,
396+
/// Enable remote session support (Mission Control integration).
397+
/// When `true`, the SDK passes `--remote` to the spawned CLI process so
398+
/// sessions in a GitHub repository working directory are accessible from
399+
/// GitHub web and mobile. Ignored when connecting to an external server
400+
/// via [`Transport::External`].
401+
pub remote: bool,
396402
}
397403

398404
impl std::fmt::Debug for ClientOptions {
@@ -430,6 +436,7 @@ impl std::fmt::Debug for ClientOptions {
430436
"tcp_connection_token",
431437
&self.tcp_connection_token.as_ref().map(|_| "<redacted>"),
432438
)
439+
.field("remote", &self.remote)
433440
.finish()
434441
}
435442
}
@@ -636,6 +643,7 @@ impl Default for ClientOptions {
636643
telemetry: None,
637644
copilot_home: None,
638645
tcp_connection_token: None,
646+
remote: false,
639647
}
640648
}
641649
}
@@ -793,6 +801,13 @@ impl ClientOptions {
793801
self.tcp_connection_token = Some(token.into());
794802
self
795803
}
804+
805+
/// Enable remote session support (Mission Control). Passes `--remote`
806+
/// to the spawned CLI process.
807+
pub fn with_remote(mut self, enabled: bool) -> Self {
808+
self.remote = enabled;
809+
self
810+
}
796811
}
797812

798813
/// Validate a [`SessionFsConfig`] before sending `sessionFs.setProvider`.
@@ -1233,6 +1248,14 @@ impl Client {
12331248
}
12341249
}
12351250

1251+
fn remote_args(options: &ClientOptions) -> Vec<String> {
1252+
if options.remote {
1253+
vec!["--remote".to_string()]
1254+
} else {
1255+
Vec::new()
1256+
}
1257+
}
1258+
12361259
fn spawn_stdio(program: &Path, options: &ClientOptions) -> Result<Child, Error> {
12371260
info!(cwd = ?options.cwd, program = %program.display(), "spawning copilot CLI (stdio)");
12381261
let mut command = Self::build_command(program, options);
@@ -1247,6 +1270,7 @@ impl Client {
12471270
])
12481271
.args(Self::auth_args(options))
12491272
.args(Self::session_idle_timeout_args(options))
1273+
.args(Self::remote_args(options))
12501274
.args(&options.extra_args)
12511275
.stdin(Stdio::piped());
12521276
Ok(command.spawn()?)
@@ -1271,6 +1295,7 @@ impl Client {
12711295
])
12721296
.args(Self::auth_args(options))
12731297
.args(Self::session_idle_timeout_args(options))
1298+
.args(Self::remote_args(options))
12741299
.args(&options.extra_args)
12751300
.stdin(Stdio::null());
12761301
let mut child = command.spawn()?;
@@ -1901,7 +1926,8 @@ mod tests {
19011926
.with_github_token("ghp_test")
19021927
.with_use_logged_in_user(false)
19031928
.with_log_level(LogLevel::Debug)
1904-
.with_session_idle_timeout_seconds(120);
1929+
.with_session_idle_timeout_seconds(120)
1930+
.with_remote(true);
19051931
assert!(matches!(opts.program, CliProgram::Path(_)));
19061932
assert_eq!(opts.prefix_args, vec![std::ffi::OsString::from("node")]);
19071933
assert_eq!(opts.cwd, PathBuf::from("/tmp"));
@@ -1918,6 +1944,7 @@ mod tests {
19181944
assert_eq!(opts.use_logged_in_user, Some(false));
19191945
assert!(matches!(opts.log_level, Some(LogLevel::Debug)));
19201946
assert_eq!(opts.session_idle_timeout_seconds, Some(120));
1947+
assert!(opts.remote);
19211948
}
19221949

19231950
#[test]
@@ -2233,6 +2260,21 @@ mod tests {
22332260
);
22342261
}
22352262

2263+
#[test]
2264+
fn remote_args_omitted_by_default() {
2265+
let opts = ClientOptions::default();
2266+
assert!(Client::remote_args(&opts).is_empty());
2267+
}
2268+
2269+
#[test]
2270+
fn remote_args_emit_flag_when_enabled() {
2271+
let opts = ClientOptions {
2272+
remote: true,
2273+
..Default::default()
2274+
};
2275+
assert_eq!(Client::remote_args(&opts), vec!["--remote".to_string()]);
2276+
}
2277+
22362278
#[test]
22372279
fn log_level_str_round_trips() {
22382280
for level in [

0 commit comments

Comments
 (0)