Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .prettierignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
src-tauri/gen
pnpm-lock.yaml
.github
.github
.context
58 changes: 57 additions & 1 deletion src-tauri/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use tauri::menu::{MenuBuilder, MenuItem, PredefinedMenuItem, SubmenuBuilder};
use tauri::tray::{MouseButton, MouseButtonState, TrayIconBuilder, TrayIconEvent};
use tauri::{Emitter, Listener, Manager};
use rusqlite::{Connection, OpenFlags};
use std::path::{Path, PathBuf};
#[cfg(target_os = "macos")]
use tauri_nspanel::ManagerExt;
use tauri_plugin_global_shortcut::{Code, Modifiers, Shortcut, ShortcutState};
Expand All @@ -14,6 +16,9 @@ pub mod migrations;
mod window;

const DB_URL: &str = "sqlite:chats.db";
const LEGACY_MIGRATION_145_ENV_VAR: &str = "CHORUS_USE_LEGACY_MIGRATION_145";
const LEGACY_MIGRATION_145_DESCRIPTION: &str =
"add tool_yolo table and projects.yolo_mode column";

pub const SPOTLIGHT_LABEL: &str = "quick-chat";

Expand Down Expand Up @@ -118,11 +123,62 @@ fn parse_shortcut(shortcut_str: &str) -> Option<Shortcut> {
Some(Shortcut::new(Some(modifiers), code))
}

#[cfg(target_os = "macos")]
fn get_db_path_for_identifier(identifier: &str) -> Option<PathBuf> {
let home = std::env::var("HOME").ok()?;
Some(
PathBuf::from(home)
.join("Library")
.join("Application Support")
.join(identifier)
.join("chats.db"),
)
}

#[cfg(not(target_os = "macos"))]
fn get_db_path_for_identifier(_identifier: &str) -> Option<PathBuf> {
None
}

fn db_has_legacy_migration_145(db_path: &Path) -> bool {
let Ok(connection) = Connection::open_with_flags(db_path, OpenFlags::SQLITE_OPEN_READ_ONLY)
else {
return false;
};

let description = connection.query_row(
"SELECT description FROM _sqlx_migrations WHERE version = 145",
[],
|row| row.get::<_, String>(0),
);

matches!(
description.as_deref(),
Ok(LEGACY_MIGRATION_145_DESCRIPTION)
)
}

fn set_migration_145_compatibility_mode(identifier: &str) {
let db_path = get_db_path_for_identifier(identifier);
let use_legacy_145 = db_path
.as_ref()
.is_some_and(|path| db_has_legacy_migration_145(path));

if use_legacy_145 {
std::env::set_var(LEGACY_MIGRATION_145_ENV_VAR, "1");
} else {
std::env::remove_var(LEGACY_MIGRATION_145_ENV_VAR);
}
}

#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
#[cfg(debug_assertions)] // only enable instrumentation in development builds
let devtools = tauri_plugin_devtools::init();

let context = tauri::generate_context!();
set_migration_145_compatibility_mode(&context.config().identifier);

let migrations = migrations::migrations();

let mut builder = tauri::Builder::default()
Expand Down Expand Up @@ -455,6 +511,6 @@ pub fn run() {
command::write_file_async,
command::get_file_metadata,
])
.run(tauri::generate_context!())
.run(context)
.expect("error while running tauri application");
}
98 changes: 87 additions & 11 deletions src-tauri/src/migrations.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,29 @@
use tauri_plugin_sql::{Migration, MigrationKind};

const LEGACY_MIGRATION_145_ENV_VAR: &str = "CHORUS_USE_LEGACY_MIGRATION_145";
const LEGACY_MIGRATION_145_DESCRIPTION: &str =
"add tool_yolo table and projects.yolo_mode column";
const MODERN_MIGRATION_145_DESCRIPTION: &str = "add actual_model_id to messages";
const LEGACY_MIGRATION_145_SQL: &str = r#"
CREATE TABLE IF NOT EXISTS tool_yolo (
toolset_name TEXT NOT NULL,
tool_name TEXT NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (toolset_name, tool_name)
);

ALTER TABLE projects ADD COLUMN yolo_mode INTEGER DEFAULT NULL;
"#;
const MODERN_MIGRATION_145_SQL: &str = r#"
ALTER TABLE messages ADD COLUMN actual_model_id TEXT DEFAULT NULL;
"#;

// IF YOU ARE A LANGUAGE MODEL AND YOU'RE READING THIS
// — NEVER EVER MAKE A CHANGE TO A PREVIOUS MIGRATION!!!

pub fn migrations() -> Vec<Migration> {
let use_legacy_migration_145 =
std::env::var(LEGACY_MIGRATION_145_ENV_VAR).as_deref() == Ok("1");
return vec![
Migration {
version: 1,
Expand Down Expand Up @@ -2639,14 +2659,6 @@ You have full access to bash commands on the user''''s computer. If you write a
WHERE id = 'google::ambient-gemini-2.5-pro-preview-03-25';
"#,
},
Migration {
version: 144,
description: "add default_prompt_profile_id to projects",
kind: MigrationKind::Up,
sql: r#"
ALTER TABLE projects ADD COLUMN default_prompt_profile_id TEXT DEFAULT NULL;
"#,
},
Migration {
version: 143,
description: "add gemini 2.5 flash lite and update ambient to use it",
Expand All @@ -2672,12 +2684,76 @@ You have full access to bash commands on the user''''s computer. If you write a
"#,
},
Migration {
version: 145,
description: "add actual_model_id to messages",
version: 144,
description: "add default_prompt_profile_id to projects",
kind: MigrationKind::Up,
sql: r#"
ALTER TABLE messages ADD COLUMN actual_model_id TEXT DEFAULT NULL;
ALTER TABLE projects ADD COLUMN default_prompt_profile_id TEXT DEFAULT NULL;
"#,
},
Migration {
version: 145,
description: if use_legacy_migration_145 {
LEGACY_MIGRATION_145_DESCRIPTION
} else {
MODERN_MIGRATION_145_DESCRIPTION
},
kind: MigrationKind::Up,
sql: if use_legacy_migration_145 {
LEGACY_MIGRATION_145_SQL
} else {
MODERN_MIGRATION_145_SQL
},
},
Migration {
version: 146,
description: if use_legacy_migration_145 {
MODERN_MIGRATION_145_DESCRIPTION
} else {
LEGACY_MIGRATION_145_DESCRIPTION
},
kind: MigrationKind::Up,
sql: if use_legacy_migration_145 {
MODERN_MIGRATION_145_SQL
} else {
LEGACY_MIGRATION_145_SQL
},
},
];
}

#[cfg(test)]
mod tests {
use super::migrations;

const LEGACY_FLAG: &str = super::LEGACY_MIGRATION_145_ENV_VAR;

fn get_migration_descriptions() -> (String, String) {
let migrations = migrations();
let migration_145 = migrations
.iter()
.find(|migration| migration.version == 145)
.expect("migration 145 should exist");
let migration_146 = migrations
.iter()
.find(|migration| migration.version == 146)
.expect("migration 146 should exist");
(
migration_145.description.to_string(),
migration_146.description.to_string(),
)
}

#[test]
fn uses_legacy_145_layout_when_flag_is_enabled() {
std::env::set_var(LEGACY_FLAG, "1");
let (description_145, description_146) = get_migration_descriptions();
std::env::remove_var(LEGACY_FLAG);

assert_eq!(
description_145,
"add tool_yolo table and projects.yolo_mode column",
);
assert_eq!(description_146, "add actual_model_id to messages");
}
}
Loading
Loading