feat: batch of fixes and features (#56)
Security Scan and Upload / Security & DefectDojo Upload (push) Successful in 57s
CI / Lint & Test (push) Successful in 14m14s
CI / Build Linux (push) Successful in 16m45s
CI / Build Windows (cross-compile) (push) Successful in 26m50s

## Summary

This PR includes a batch of bug fixes and new features:

### Bug Fixes
- **Links in chat history now open in default browser** instead of navigating within the app
  - Closes #54
- **Allow spaces in tab names** - space key no longer acts like enter when renaming tabs
  - Closes #52

### New Features
- **`/cd` command** - Change the working directory of an active tab with context preservation
  - Closes #55
- **`/search` command** - Search and highlight matches within the conversation
  - Closes #32

## Test Plan
- [ ] Click a link in chat history and verify it opens in the default browser
- [ ] Rename a tab and verify spaces can be typed
- [ ] Use `/cd <path>` and verify the directory changes while preserving conversation context
- [ ] Use `/search <query>` and verify matches are highlighted in yellow
- [ ] Use `/search` with no args to clear the search highlighting

 This PR was created with help from Hikari~ 🌸

Co-authored-by: Naomi Carrigan <commits@nhcarrigan.com>
Reviewed-on: #56
Co-authored-by: Hikari <hikari@nhcarrigan.com>
Co-committed-by: Hikari <hikari@nhcarrigan.com>
This commit was merged in pull request #56.
This commit is contained in:
2026-01-23 11:59:21 -08:00
committed by Naomi Carrigan
parent 947e56ef41
commit 94991796be
10 changed files with 369 additions and 5 deletions
+45
View File
@@ -105,6 +105,51 @@ pub async fn get_usage_stats(
manager.get_usage_stats(&conversation_id)
}
#[tauri::command]
pub async fn validate_directory(path: String, current_dir: Option<String>) -> Result<String, String> {
use std::path::Path;
let path = Path::new(&path);
// Expand ~ to home directory
let expanded_path = if path.starts_with("~") {
if let Some(home) = std::env::var_os("HOME") {
let home_path = Path::new(&home);
if path == Path::new("~") {
home_path.to_path_buf()
} else {
home_path.join(path.strip_prefix("~").unwrap())
}
} else {
return Err("Could not determine home directory".to_string());
}
} else if path.is_relative() {
// Handle relative paths (., .., or any relative path) by resolving against current_dir
if let Some(ref cwd) = current_dir {
Path::new(cwd).join(path)
} else {
path.to_path_buf()
}
} else {
path.to_path_buf()
};
// Check if the path exists and is a directory
if !expanded_path.exists() {
return Err(format!("Directory does not exist: {}", expanded_path.display()));
}
if !expanded_path.is_dir() {
return Err(format!("Path is not a directory: {}", expanded_path.display()));
}
// Return the canonicalized (absolute) path
expanded_path
.canonicalize()
.map(|p| p.to_string_lossy().to_string())
.map_err(|e| format!("Failed to resolve path: {}", e))
}
#[tauri::command]
pub async fn load_saved_achievements(app: AppHandle) -> Result<Vec<AchievementUnlockedEvent>, String> {
use chrono::Utc;
+3
View File
@@ -22,6 +22,9 @@ pub struct ClaudeStartOptions {
#[serde(default)]
pub skip_greeting: bool,
#[serde(default)]
pub resume_session_id: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
+1
View File
@@ -53,6 +53,7 @@ pub fn run() {
send_notify_send,
send_wsl_notification,
send_vbs_notification,
validate_directory,
])
.run(tauri::generate_context!())
.expect("error while running tauri application");
+14
View File
@@ -195,6 +195,13 @@ impl WslBridge {
cmd.args(["--mcp-config", mcp_path]);
}
// Add resume flag if session ID provided
if let Some(ref session_id) = options.resume_session_id {
if !session_id.is_empty() {
cmd.args(["--resume", session_id]);
}
}
cmd.current_dir(working_dir);
// Set API key as environment variable if specified
@@ -251,6 +258,13 @@ impl WslBridge {
claude_cmd.push_str(&format!(" --mcp-config '{}'", mcp_path));
}
// Add resume flag if session ID provided
if let Some(ref session_id) = options.resume_session_id {
if !session_id.is_empty() {
claude_cmd.push_str(&format!(" --resume '{}'", session_id));
}
}
// Use bash -lc to load login profile (ensures PATH includes claude)
cmd.args(["-e", "bash", "-lc", &claude_cmd]);