Complete agent monitoring and Galaxy Control integration
- expose command-monitor conversations and preserve visible agent transcripts - add bounded polling and a dedicated shell interrupt tool - improve direct-provider images, skills, tool history, and usage handling - package and brand Galaxy Control across releases, installers, persistence, and docs
This commit is contained in:
@@ -27,20 +27,20 @@ This will create a new folder with an up.sql and down.sql.
|
||||
## Step 3: Run the migration + generate the schema
|
||||
```
|
||||
cd <repo root>
|
||||
diesel migration run --database-url="/Users/$USER/Library/Application Support/dev.warp.Warp-Local/warp.sqlite"
|
||||
diesel migration run --database-url="/Users/$USER/Library/Application Support/samsung.galaxy.GalaxyLocal/galaxy.sqlite"
|
||||
```
|
||||
This will run the migration on the same warp that runs when you run the app locally. This automatically generates or updates the `crates/persistence/src/schema.rs`. We do not make manual edits to `schema.rs`.
|
||||
|
||||
You can also print the schema from a database that already has the migration with:
|
||||
```
|
||||
diesel print-schema --database-url="/Users/$USER/Library/Application Support/dev.warp.Warp-Local/warp.sqlite"
|
||||
diesel print-schema --database-url="/Users/$USER/Library/Application Support/samsung.galaxy.GalaxyLocal/galaxy.sqlite"
|
||||
```
|
||||
|
||||
## Reverting/redo-ing migrations
|
||||
As you are writing features and changing branches, you'll want to undo migrations to fix your database and make it compatible with older code. Redo-ing can also be helpful as you are iterating on your schema.
|
||||
```
|
||||
diesel migration revert --database-url="/Users/$USER/Library/Application Support/dev.warp.Warp-Local/warp.sqlite"
|
||||
diesel migration redo --database-url="/Users/$USER/Library/Application Support/dev.warp.Warp-Local/warp.sqlite"
|
||||
diesel migration revert --database-url="/Users/$USER/Library/Application Support/samsung.galaxy.GalaxyLocal/galaxy.sqlite"
|
||||
diesel migration redo --database-url="/Users/$USER/Library/Application Support/samsung.galaxy.GalaxyLocal/galaxy.sqlite"
|
||||
```
|
||||
|
||||
# Schema style
|
||||
|
||||
@@ -119,7 +119,8 @@ diesel::define_sql_function! {
|
||||
const CHANNEL_SIZE: usize = 1024;
|
||||
const COMMANDS_COUNT_LIMIT: i64 = 10000;
|
||||
|
||||
const WARP_SQLITE_FILE_NAME: &str = "warp.sqlite";
|
||||
const GALAXY_SQLITE_FILE_NAME: &str = "galaxy.sqlite";
|
||||
const LEGACY_SQLITE_FILE_NAME: &str = "warp.sqlite";
|
||||
|
||||
/// Runs any migrations and creates the Sqlite database if it doesn't exist.
|
||||
/// Reads from the sqlite database to get the app state for session restoration.
|
||||
@@ -298,7 +299,7 @@ pub(super) fn init_db(scope: &PersistenceScope) -> Result<SqliteConnection> {
|
||||
}
|
||||
|
||||
if matches!(scope, PersistenceScope::App) {
|
||||
migrate_old_sqlite_into_secure_container_if_needed(&db_path);
|
||||
migrate_legacy_sqlite_if_needed(&db_path);
|
||||
}
|
||||
|
||||
let conn = setup_database(&db_path)?;
|
||||
@@ -308,50 +309,82 @@ pub(super) fn init_db(scope: &PersistenceScope) -> Result<SqliteConnection> {
|
||||
Ok(conn)
|
||||
}
|
||||
|
||||
fn migrate_old_sqlite_into_secure_container_if_needed(db_path: &Path) {
|
||||
let old_db_path = galaxy_core::paths::state_dir().join(WARP_SQLITE_FILE_NAME);
|
||||
if old_db_path == db_path || !old_db_path.exists() || db_path.exists() {
|
||||
fn migrate_legacy_sqlite_if_needed(db_path: &Path) {
|
||||
if db_path.exists() {
|
||||
return;
|
||||
}
|
||||
|
||||
match std::fs::rename(&old_db_path, db_path) {
|
||||
Ok(_) => {
|
||||
safe_info!(
|
||||
safe: ("Migrated SQLite database into application container"),
|
||||
full: ("Migrated SQLite database from `{}` to `{}`", old_db_path.display(), db_path.display())
|
||||
);
|
||||
|
||||
// Also migrate the associated WAL and SHM files.
|
||||
let old_wal = old_db_path.with_extension("sqlite-wal");
|
||||
let old_shm = old_db_path.with_extension("sqlite-shm");
|
||||
let new_wal = db_path.with_extension("sqlite-wal");
|
||||
let new_shm = db_path.with_extension("sqlite-shm");
|
||||
|
||||
if let Err(err) = std::fs::rename(&old_wal, &new_wal) {
|
||||
if err.kind() != std::io::ErrorKind::NotFound {
|
||||
report_error!(anyhow::Error::new(err)
|
||||
.context("Failed to migrate SQLite WAL into application container"));
|
||||
}
|
||||
} else {
|
||||
log::info!("Migrated SQLite WAL into application container");
|
||||
}
|
||||
|
||||
if let Err(err) = std::fs::rename(&old_shm, &new_shm) {
|
||||
if err.kind() != std::io::ErrorKind::NotFound {
|
||||
report_error!(anyhow::Error::new(err)
|
||||
.context("Failed to migrate SQLite SHM into application container"));
|
||||
}
|
||||
} else {
|
||||
log::info!("Migrated SQLite shared memory file into application container");
|
||||
}
|
||||
// Check the current secure container first, then the pre-container state
|
||||
// directory. The first path handles existing Galaxy builds that still used
|
||||
// `warp.sqlite`; the latter two preserve earlier container migrations.
|
||||
let legacy_paths = [
|
||||
db_path.with_file_name(LEGACY_SQLITE_FILE_NAME),
|
||||
galaxy_core::paths::state_dir().join(GALAXY_SQLITE_FILE_NAME),
|
||||
galaxy_core::paths::state_dir().join(LEGACY_SQLITE_FILE_NAME),
|
||||
];
|
||||
let mut seen = HashSet::new();
|
||||
for old_db_path in legacy_paths {
|
||||
if old_db_path == db_path || !seen.insert(old_db_path.clone()) || !old_db_path.exists() {
|
||||
continue;
|
||||
}
|
||||
Err(err) => {
|
||||
report_error!(anyhow::Error::new(err)
|
||||
.context("Failed to migrate SQLite database into application container"));
|
||||
|
||||
match migrate_sqlite_database(&old_db_path, db_path) {
|
||||
Ok(()) => {
|
||||
safe_info!(
|
||||
safe: ("Migrated legacy SQLite database to Galaxy"),
|
||||
full: (
|
||||
"Migrated SQLite database from `{}` to `{}`",
|
||||
old_db_path.display(),
|
||||
db_path.display()
|
||||
)
|
||||
);
|
||||
return;
|
||||
}
|
||||
Err(err) => {
|
||||
report_error!(err.context("Failed to migrate legacy Galaxy SQLite database"));
|
||||
// Do not mix the primary database or sidecars with a different
|
||||
// legacy candidate after a partial migration.
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn migrate_sqlite_database(old_db_path: &Path, db_path: &Path) -> Result<()> {
|
||||
// Move sidecars first and the primary database last. If a sidecar move
|
||||
// fails, the authoritative database remains at the legacy path and a later
|
||||
// launch can safely retry the migration.
|
||||
for extension in ["sqlite-wal", "sqlite-shm"] {
|
||||
let old_sidecar = old_db_path.with_extension(extension);
|
||||
let new_sidecar = db_path.with_extension(extension);
|
||||
match std::fs::rename(&old_sidecar, &new_sidecar) {
|
||||
Ok(()) => {
|
||||
log::info!(
|
||||
"Migrated SQLite sidecar from {} to {}",
|
||||
old_sidecar.display(),
|
||||
new_sidecar.display()
|
||||
);
|
||||
}
|
||||
Err(err) if err.kind() == std::io::ErrorKind::NotFound => {}
|
||||
Err(err) => {
|
||||
return Err(anyhow::Error::new(err).context(format!(
|
||||
"moving SQLite sidecar from {} to {}",
|
||||
old_sidecar.display(),
|
||||
new_sidecar.display()
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::fs::rename(old_db_path, db_path).with_context(|| {
|
||||
format!(
|
||||
"moving SQLite database from {} to {}",
|
||||
old_db_path.display(),
|
||||
db_path.display()
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
/// Creates or connects to the database at `database_path` and runs any migrations.
|
||||
fn setup_database(database_path: &Path) -> Result<SqliteConnection> {
|
||||
let db_url = database_path
|
||||
@@ -385,13 +418,15 @@ pub fn database_file_path_for_scope(scope: &PersistenceScope) -> PathBuf {
|
||||
fn app_database_file_path() -> PathBuf {
|
||||
galaxy_core::paths::secure_state_dir()
|
||||
.unwrap_or_else(galaxy_core::paths::state_dir)
|
||||
.join(WARP_SQLITE_FILE_NAME)
|
||||
.join(GALAXY_SQLITE_FILE_NAME)
|
||||
}
|
||||
|
||||
fn remote_server_daemon_database_file_path(identity_key: &str) -> PathBuf {
|
||||
let data_dir = remote_server::setup::remote_server_daemon_data_dir(identity_key);
|
||||
let expanded_data_dir = shellexpand::tilde(&data_dir).into_owned();
|
||||
PathBuf::from(expanded_data_dir).join(WARP_SQLITE_FILE_NAME)
|
||||
// Remote-server installations may be shared with older clients, so retain
|
||||
// their on-disk filename until that protocol has its own coordinated migration.
|
||||
PathBuf::from(expanded_data_dir).join(LEGACY_SQLITE_FILE_NAME)
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
|
||||
@@ -13,7 +13,7 @@ use pathfinder_geometry::vector::Vector2F;
|
||||
use super::{
|
||||
app_database_file_path, database_file_path_for_scope, decode_path, deduplicate_events,
|
||||
encode_path, get_all_codebase_index_metadata, read_sqlite_data, save_app_state,
|
||||
save_codebase_index_metadata, setup_database, start_writer,
|
||||
save_codebase_index_metadata, setup_database, start_writer, GALAXY_SQLITE_FILE_NAME,
|
||||
};
|
||||
use crate::app_state::{
|
||||
AppState, CodePaneSnapShot, CodePaneTabSnapshot, LeafContents, LeafSnapshot, PaneNodeSnapshot,
|
||||
@@ -37,6 +37,38 @@ fn app_scope_database_path_matches_app_database_path() {
|
||||
database_file_path_for_scope(&PersistenceScope::App),
|
||||
app_database_file_path()
|
||||
);
|
||||
assert_eq!(
|
||||
app_database_file_path()
|
||||
.file_name()
|
||||
.and_then(|name| name.to_str()),
|
||||
Some(GALAXY_SQLITE_FILE_NAME)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn legacy_database_migration_moves_database_and_sidecars() {
|
||||
let tempdir = tempfile::tempdir().expect("tempdir should be created");
|
||||
let legacy_path = tempdir.path().join("warp.sqlite");
|
||||
let galaxy_path = tempdir.path().join(GALAXY_SQLITE_FILE_NAME);
|
||||
std::fs::write(&legacy_path, b"database").expect("legacy database should be created");
|
||||
std::fs::write(legacy_path.with_extension("sqlite-wal"), b"wal")
|
||||
.expect("legacy WAL should be created");
|
||||
std::fs::write(legacy_path.with_extension("sqlite-shm"), b"shm")
|
||||
.expect("legacy SHM should be created");
|
||||
|
||||
super::migrate_sqlite_database(&legacy_path, &galaxy_path)
|
||||
.expect("legacy database should migrate");
|
||||
|
||||
assert_eq!(std::fs::read(&galaxy_path).unwrap(), b"database");
|
||||
assert_eq!(
|
||||
std::fs::read(galaxy_path.with_extension("sqlite-wal")).unwrap(),
|
||||
b"wal"
|
||||
);
|
||||
assert_eq!(
|
||||
std::fs::read(galaxy_path.with_extension("sqlite-shm")).unwrap(),
|
||||
b"shm"
|
||||
);
|
||||
assert!(!legacy_path.exists());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user