Skip to content

Commit 70c16d8

Browse files
eisbawclaude
authored andcommitted
fix(web): use wss:// for HTTPS connections and apply cargo fmt
- Fix WebSocket protocol to use wss:// for HTTPS (ngrok) and ws:// for HTTP (localhost) - This resolves the issue where Send button doesn't work when accessed via ngrok - Apply cargo fmt to fix Rust code formatting issues 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent 92825e5 commit 70c16d8

File tree

12 files changed

+857
-608
lines changed

12 files changed

+857
-608
lines changed

src-tauri/src/claude_binary.rs

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ pub fn find_claude_binary(app_handle: &tauri::AppHandle) -> Result<String, Strin
4747
|row| row.get::<_, String>(0),
4848
) {
4949
info!("Found stored claude path in database: {}", stored_path);
50-
50+
5151
// Check if the path still exists
5252
let path_buf = PathBuf::from(&stored_path);
5353
if path_buf.exists() && path_buf.is_file() {
@@ -56,14 +56,14 @@ pub fn find_claude_binary(app_handle: &tauri::AppHandle) -> Result<String, Strin
5656
warn!("Stored claude path no longer exists: {}", stored_path);
5757
}
5858
}
59-
59+
6060
// Check user preference
6161
let preference = conn.query_row(
6262
"SELECT value FROM app_settings WHERE key = 'claude_installation_preference'",
6363
[],
6464
|row| row.get::<_, String>(0),
6565
).unwrap_or_else(|_| "system".to_string());
66-
66+
6767
info!("User preference for Claude installation: {}", preference);
6868
}
6969
}
@@ -261,7 +261,9 @@ fn find_nvm_installations() -> Vec<ClaudeInstallation> {
261261
let claude_path = PathBuf::from(&nvm_bin).join("claude");
262262
if claude_path.exists() && claude_path.is_file() {
263263
debug!("Found Claude via NVM_BIN: {:?}", claude_path);
264-
let version = get_claude_version(&claude_path.to_string_lossy()).ok().flatten();
264+
let version = get_claude_version(&claude_path.to_string_lossy())
265+
.ok()
266+
.flatten();
265267
installations.push(ClaudeInstallation {
266268
path: claude_path.to_string_lossy().to_string(),
267269
version,
@@ -496,7 +498,6 @@ fn find_standard_installations() -> Vec<ClaudeInstallation> {
496498
installations
497499
}
498500

499-
500501
/// Get Claude version by running --version command
501502
fn get_claude_version(path: &str) -> Result<Option<String>, String> {
502503
match Command::new(path).arg("--version").output() {
@@ -517,10 +518,10 @@ fn get_claude_version(path: &str) -> Result<Option<String>, String> {
517518
/// Extract version string from command output
518519
fn extract_version_from_output(stdout: &[u8]) -> Option<String> {
519520
let output_str = String::from_utf8_lossy(stdout);
520-
521+
521522
// Debug log the raw output
522523
debug!("Raw version output: {:?}", output_str);
523-
524+
524525
// Use regex to directly extract version pattern (e.g., "1.0.41")
525526
// This pattern matches:
526527
// - One or more digits, followed by
@@ -529,16 +530,17 @@ fn extract_version_from_output(stdout: &[u8]) -> Option<String> {
529530
// - A dot, followed by
530531
// - One or more digits
531532
// - Optionally followed by pre-release/build metadata
532-
let version_regex = regex::Regex::new(r"(\d+\.\d+\.\d+(?:-[a-zA-Z0-9.-]+)?(?:\+[a-zA-Z0-9.-]+)?)").ok()?;
533-
533+
let version_regex =
534+
regex::Regex::new(r"(\d+\.\d+\.\d+(?:-[a-zA-Z0-9.-]+)?(?:\+[a-zA-Z0-9.-]+)?)").ok()?;
535+
534536
if let Some(captures) = version_regex.captures(&output_str) {
535537
if let Some(version_match) = captures.get(1) {
536538
let version = version_match.as_str().to_string();
537539
debug!("Extracted version: {:?}", version);
538540
return Some(version);
539541
}
540542
}
541-
543+
542544
debug!("No version found in output");
543545
None
544546
}
@@ -618,7 +620,7 @@ fn compare_versions(a: &str, b: &str) -> Ordering {
618620
/// This ensures commands like Claude can find Node.js and other dependencies
619621
pub fn create_command_with_env(program: &str) -> Command {
620622
let mut cmd = Command::new(program);
621-
623+
622624
info!("Creating command for: {}", program);
623625

624626
// Inherit essential environment variables from parent process
@@ -646,7 +648,7 @@ pub fn create_command_with_env(program: &str) -> Command {
646648
cmd.env(&key, &value);
647649
}
648650
}
649-
651+
650652
// Log proxy-related environment variables for debugging
651653
info!("Command will use proxy settings:");
652654
if let Ok(http_proxy) = std::env::var("HTTP_PROXY") {
@@ -669,7 +671,7 @@ pub fn create_command_with_env(program: &str) -> Command {
669671
}
670672
}
671673
}
672-
674+
673675
// Add Homebrew support if the program is in a Homebrew directory
674676
if program.contains("/homebrew/") || program.contains("/opt/homebrew/") {
675677
if let Some(program_dir) = std::path::Path::new(program).parent() {
@@ -678,7 +680,10 @@ pub fn create_command_with_env(program: &str) -> Command {
678680
let homebrew_bin_str = program_dir.to_string_lossy();
679681
if !current_path.contains(&homebrew_bin_str.as_ref()) {
680682
let new_path = format!("{}:{}", homebrew_bin_str, current_path);
681-
debug!("Adding Homebrew bin directory to PATH: {}", homebrew_bin_str);
683+
debug!(
684+
"Adding Homebrew bin directory to PATH: {}",
685+
homebrew_bin_str
686+
);
682687
cmd.env("PATH", new_path);
683688
}
684689
}

src-tauri/src/commands/agents.rs

Lines changed: 61 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,10 @@ pub async fn read_session_jsonl(session_id: &str, project_path: &str) -> Result<
179179
let session_file = project_dir.join(format!("{}.jsonl", session_id));
180180

181181
if !session_file.exists() {
182-
return Err(format!("Session file not found: {}", session_file.display()));
182+
return Err(format!(
183+
"Session file not found: {}",
184+
session_file.display()
185+
));
183186
}
184187

185188
match tokio::fs::read_to_string(&session_file).await {
@@ -317,7 +320,6 @@ pub fn init_database(app: &AppHandle) -> SqliteResult<Connection> {
317320
[],
318321
)?;
319322

320-
321323
// Create settings table for app-wide settings
322324
conn.execute(
323325
"CREATE TABLE IF NOT EXISTS app_settings (
@@ -690,38 +692,41 @@ pub async fn execute_agent(
690692
// Get the agent from database
691693
let agent = get_agent(db.clone(), agent_id).await?;
692694
let execution_model = model.unwrap_or(agent.model.clone());
693-
695+
694696
// Create .claude/settings.json with agent hooks if it doesn't exist
695697
if let Some(hooks_json) = &agent.hooks {
696698
let claude_dir = std::path::Path::new(&project_path).join(".claude");
697699
let settings_path = claude_dir.join("settings.json");
698-
700+
699701
// Create .claude directory if it doesn't exist
700702
if !claude_dir.exists() {
701703
std::fs::create_dir_all(&claude_dir)
702704
.map_err(|e| format!("Failed to create .claude directory: {}", e))?;
703705
info!("Created .claude directory at: {:?}", claude_dir);
704706
}
705-
707+
706708
// Check if settings.json already exists
707709
if !settings_path.exists() {
708710
// Parse the hooks JSON
709711
let hooks: serde_json::Value = serde_json::from_str(hooks_json)
710712
.map_err(|e| format!("Failed to parse agent hooks: {}", e))?;
711-
713+
712714
// Create a settings object with just the hooks
713715
let settings = serde_json::json!({
714716
"hooks": hooks
715717
});
716-
718+
717719
// Write the settings file
718720
let settings_content = serde_json::to_string_pretty(&settings)
719721
.map_err(|e| format!("Failed to serialize settings: {}", e))?;
720-
722+
721723
std::fs::write(&settings_path, settings_content)
722724
.map_err(|e| format!("Failed to write settings.json: {}", e))?;
723-
724-
info!("Created settings.json with agent hooks at: {:?}", settings_path);
725+
726+
info!(
727+
"Created settings.json with agent hooks at: {:?}",
728+
settings_path
729+
);
725730
} else {
726731
info!("settings.json already exists at: {:?}", settings_path);
727732
}
@@ -775,7 +780,8 @@ pub async fn execute_agent(
775780
execution_model,
776781
db,
777782
registry,
778-
).await
783+
)
784+
.await
779785
}
780786

781787
/// Creates a system binary command for agent execution
@@ -785,17 +791,17 @@ fn create_agent_system_command(
785791
project_path: &str,
786792
) -> Command {
787793
let mut cmd = create_command_with_env(claude_path);
788-
794+
789795
// Add all arguments
790796
for arg in args {
791797
cmd.arg(arg);
792798
}
793-
799+
794800
cmd.current_dir(project_path)
795801
.stdin(Stdio::null())
796802
.stdout(Stdio::piped())
797803
.stderr(Stdio::piped());
798-
804+
799805
cmd
800806
}
801807

@@ -905,14 +911,15 @@ async fn spawn_agent_system(
905911
// Extract session ID from JSONL output
906912
if let Ok(json) = serde_json::from_str::<JsonValue>(&line) {
907913
// Claude Code uses "session_id" (underscore), not "sessionId"
908-
if json.get("type").and_then(|t| t.as_str()) == Some("system") &&
909-
json.get("subtype").and_then(|s| s.as_str()) == Some("init") {
914+
if json.get("type").and_then(|t| t.as_str()) == Some("system")
915+
&& json.get("subtype").and_then(|s| s.as_str()) == Some("init")
916+
{
910917
if let Some(sid) = json.get("session_id").and_then(|s| s.as_str()) {
911918
if let Ok(mut current_session_id) = session_id_clone.lock() {
912919
if current_session_id.is_empty() {
913920
*current_session_id = sid.to_string();
914921
info!("🔑 Extracted session ID: {}", sid);
915-
922+
916923
// Update database immediately with session ID
917924
if let Ok(conn) = Connection::open(&db_path_for_stdout) {
918925
match conn.execute(
@@ -925,7 +932,10 @@ async fn spawn_agent_system(
925932
}
926933
}
927934
Err(e) => {
928-
error!("❌ Failed to update session ID immediately: {}", e);
935+
error!(
936+
"❌ Failed to update session ID immediately: {}",
937+
e
938+
);
929939
}
930940
}
931941
}
@@ -1085,7 +1095,10 @@ async fn spawn_agent_system(
10851095

10861096
// Update the run record with session ID and mark as completed - open a new connection
10871097
if let Ok(conn) = Connection::open(&db_path_for_monitor) {
1088-
info!("🔄 Updating database with extracted session ID: {}", extracted_session_id);
1098+
info!(
1099+
"🔄 Updating database with extracted session ID: {}",
1100+
extracted_session_id
1101+
);
10891102
match conn.execute(
10901103
"UPDATE agent_runs SET session_id = ?1, status = 'completed', completed_at = CURRENT_TIMESTAMP WHERE id = ?2",
10911104
params![extracted_session_id, run_id],
@@ -1102,7 +1115,10 @@ async fn spawn_agent_system(
11021115
}
11031116
}
11041117
} else {
1105-
error!("❌ Failed to open database to update session ID for run {}", run_id);
1118+
error!(
1119+
"❌ Failed to open database to update session ID for run {}",
1120+
run_id
1121+
);
11061122
}
11071123

11081124
// Cleanup will be handled by the cleanup_finished_processes function
@@ -1162,10 +1178,8 @@ pub async fn list_running_sessions(
11621178
// Cross-check with the process registry to ensure accuracy
11631179
// Get actually running processes from the registry
11641180
let registry_processes = registry.0.get_running_agent_processes()?;
1165-
let registry_run_ids: std::collections::HashSet<i64> = registry_processes
1166-
.iter()
1167-
.map(|p| p.run_id)
1168-
.collect();
1181+
let registry_run_ids: std::collections::HashSet<i64> =
1182+
registry_processes.iter().map(|p| p.run_id).collect();
11691183

11701184
// Filter out any database entries that aren't actually running in the registry
11711185
// This handles cases where processes crashed without updating the database
@@ -1358,7 +1372,7 @@ pub async fn get_session_output(
13581372

13591373
// Find the correct project directory by searching for the session file
13601374
let projects_dir = claude_dir.join("projects");
1361-
1375+
13621376
// Check if projects directory exists
13631377
if !projects_dir.exists() {
13641378
log::error!("Projects directory not found at: {:?}", projects_dir);
@@ -1367,15 +1381,18 @@ pub async fn get_session_output(
13671381

13681382
// Search for the session file in all project directories
13691383
let mut session_file_path = None;
1370-
log::info!("Searching for session file {} in all project directories", run.session_id);
1371-
1384+
log::info!(
1385+
"Searching for session file {} in all project directories",
1386+
run.session_id
1387+
);
1388+
13721389
if let Ok(entries) = std::fs::read_dir(&projects_dir) {
13731390
for entry in entries.filter_map(Result::ok) {
13741391
let path = entry.path();
13751392
if path.is_dir() {
13761393
let dir_name = path.file_name().unwrap_or_default().to_string_lossy();
13771394
log::debug!("Checking project directory: {}", dir_name);
1378-
1395+
13791396
let potential_session_file = path.join(format!("{}.jsonl", run.session_id));
13801397
if potential_session_file.exists() {
13811398
log::info!("Found session file at: {:?}", potential_session_file);
@@ -1395,15 +1412,22 @@ pub async fn get_session_output(
13951412
match tokio::fs::read_to_string(&session_path).await {
13961413
Ok(content) => Ok(content),
13971414
Err(e) => {
1398-
log::error!("Failed to read session file {}: {}", session_path.display(), e);
1415+
log::error!(
1416+
"Failed to read session file {}: {}",
1417+
session_path.display(),
1418+
e
1419+
);
13991420
// Fallback to live output if file read fails
14001421
let live_output = registry.0.get_live_output(run_id)?;
14011422
Ok(live_output)
14021423
}
14031424
}
14041425
} else {
14051426
// If session file not found, try the old method as fallback
1406-
log::warn!("Session file not found for {}, trying legacy method", run.session_id);
1427+
log::warn!(
1428+
"Session file not found for {}, trying legacy method",
1429+
run.session_id
1430+
);
14071431
match read_session_jsonl(&run.session_id, &run.project_path).await {
14081432
Ok(content) => Ok(content),
14091433
Err(_) => {
@@ -1916,23 +1940,26 @@ pub async fn load_agent_session_history(
19161940
.join(".claude");
19171941

19181942
let projects_dir = claude_dir.join("projects");
1919-
1943+
19201944
if !projects_dir.exists() {
19211945
log::error!("Projects directory not found at: {:?}", projects_dir);
19221946
return Err("Projects directory not found".to_string());
19231947
}
19241948

19251949
// Search for the session file in all project directories
19261950
let mut session_file_path = None;
1927-
log::info!("Searching for session file {} in all project directories", session_id);
1928-
1951+
log::info!(
1952+
"Searching for session file {} in all project directories",
1953+
session_id
1954+
);
1955+
19291956
if let Ok(entries) = std::fs::read_dir(&projects_dir) {
19301957
for entry in entries.filter_map(Result::ok) {
19311958
let path = entry.path();
19321959
if path.is_dir() {
19331960
let dir_name = path.file_name().unwrap_or_default().to_string_lossy();
19341961
log::debug!("Checking project directory: {}", dir_name);
1935-
1962+
19361963
let potential_session_file = path.join(format!("{}.jsonl", session_id));
19371964
if potential_session_file.exists() {
19381965
log::info!("Found session file at: {:?}", potential_session_file);

0 commit comments

Comments
 (0)