Skip to content

Commit 00cff6f

Browse files
committed
fix: surface codex readiness errors
1 parent 4fa6317 commit 00cff6f

2 files changed

Lines changed: 69 additions & 2 deletions

File tree

src-tauri/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ tauri = { version = "2", features = ["macos-private-api"] }
2222
tauri-plugin-opener = "2"
2323
serde = { version = "1", features = ["derive"] }
2424
serde_json = "1"
25-
tokio = { version = "1", features = ["io-util", "process", "rt", "sync"] }
25+
tokio = { version = "1", features = ["io-util", "process", "rt", "sync", "time"] }
2626
uuid = { version = "1", features = ["v4"] }
2727
tauri-plugin-dialog = "2"
2828
git2 = "0.20.3"

src-tauri/src/lib.rs

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ use serde::{Deserialize, Serialize};
22
use serde_json::{json, Map, Value};
33
use std::collections::HashMap;
44
use std::env;
5+
use std::io::ErrorKind;
56
use std::path::PathBuf;
7+
use std::time::Duration;
68
use std::sync::atomic::{AtomicU64, Ordering};
79
use std::sync::Arc;
810
use git2::{DiffOptions, Repository, Sort, Status, StatusOptions, Tree};
@@ -12,6 +14,7 @@ use tauri::{WebviewUrl, WebviewWindowBuilder};
1214
use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};
1315
use tokio::process::{Child, ChildStdin, Command};
1416
use tokio::sync::{Mutex, oneshot};
17+
use tokio::time::timeout;
1518
use uuid::Uuid;
1619

1720
#[derive(Debug, Serialize, Deserialize, Clone)]
@@ -250,10 +253,58 @@ fn build_codex_command(entry: &WorkspaceEntry) -> Command {
250253
command
251254
}
252255

256+
async fn check_codex_installation(entry: &WorkspaceEntry) -> Result<Option<String>, String> {
257+
let mut command = build_codex_command(entry);
258+
command.arg("--version");
259+
command.stdout(std::process::Stdio::piped());
260+
command.stderr(std::process::Stdio::piped());
261+
262+
let output = match timeout(Duration::from_secs(5), command.output()).await {
263+
Ok(result) => result.map_err(|e| {
264+
if e.kind() == ErrorKind::NotFound {
265+
"Codex CLI not found. Install Codex and ensure `codex` is on your PATH."
266+
.to_string()
267+
} else {
268+
e.to_string()
269+
}
270+
})?,
271+
Err(_) => {
272+
return Err(
273+
"Timed out while checking Codex CLI. Make sure `codex --version` runs in Terminal."
274+
.to_string(),
275+
);
276+
}
277+
};
278+
279+
if !output.status.success() {
280+
let stderr = String::from_utf8_lossy(&output.stderr);
281+
let stdout = String::from_utf8_lossy(&output.stdout);
282+
let detail = if stderr.trim().is_empty() {
283+
stdout.trim()
284+
} else {
285+
stderr.trim()
286+
};
287+
if detail.is_empty() {
288+
return Err(
289+
"Codex CLI failed to start. Try running `codex --version` in Terminal."
290+
.to_string(),
291+
);
292+
}
293+
return Err(format!(
294+
"Codex CLI failed to start: {detail}. Try running `codex --version` in Terminal."
295+
));
296+
}
297+
298+
let version = String::from_utf8_lossy(&output.stdout).trim().to_string();
299+
Ok(if version.is_empty() { None } else { Some(version) })
300+
}
301+
253302
async fn spawn_workspace_session(
254303
entry: WorkspaceEntry,
255304
app_handle: AppHandle,
256305
) -> Result<Arc<WorkspaceSession>, String> {
306+
let _ = check_codex_installation(&entry).await?;
307+
257308
let mut command = build_codex_command(&entry);
258309
command.arg("app-server");
259310
command.stdin(std::process::Stdio::piped());
@@ -351,7 +402,23 @@ async fn spawn_workspace_session(
351402
"version": "0.1.0"
352403
}
353404
});
354-
session.send_request("initialize", init_params).await?;
405+
let init_result = timeout(
406+
Duration::from_secs(15),
407+
session.send_request("initialize", init_params),
408+
)
409+
.await;
410+
let init_response = match init_result {
411+
Ok(response) => response,
412+
Err(_) => {
413+
let mut child = session.child.lock().await;
414+
let _ = child.kill().await;
415+
return Err(
416+
"Codex app-server did not respond to initialize. Check that `codex app-server` works in Terminal."
417+
.to_string(),
418+
);
419+
}
420+
};
421+
init_response?;
355422
session.send_notification("initialized", None).await?;
356423

357424
let payload = AppServerEvent {

0 commit comments

Comments
 (0)