feat(v2): add SSH management, ctx integration, themes, detached mode, auto-updater
SSH session management: - SshSession struct + ssh_sessions SQLite table in session.rs - CRUD Tauri commands (ssh_session_list/save/delete) in lib.rs - SshDialog.svelte (create/edit modal), SshSessionList.svelte (sidebar) - SSH pane routes to TerminalPane with shell=/usr/bin/ssh + args ctx context database integration: - ctx.rs: read-only CtxDb (SQLITE_OPEN_READ_ONLY for ~/.claude-context/context.db) - 5 Tauri commands (ctx_list_projects/get_context/get_shared/get_summaries/search) - ContextPane.svelte with project selector, tabs, search - ctx-bridge.ts adapter Catppuccin theme flavors (Latte/Frappe/Macchiato/Mocha): - themes.ts: all 4 palette definitions + buildXtermTheme/applyCssVariables - theme.svelte.ts: reactive store with SQLite persistence - SettingsDialog flavor dropdown, TerminalPane theme-aware Detached pane mode (pop-out windows): - detach.ts: isDetachedMode/getDetachedConfig from URL params - App.svelte: conditional rendering of single pane without chrome Other additions: - Shiki syntax highlighting (highlight.ts, lazy singleton, 13 languages) - Tauri auto-updater plugin (tauri-plugin-updater + updater.ts) - AgentPane markdown rendering with Shiki code highlighting - New deps: shiki, @tauri-apps/plugin-updater, tauri-plugin-updater
This commit is contained in:
parent
4f2614186d
commit
4db7ccff60
28 changed files with 2992 additions and 51 deletions
|
|
@ -6,6 +6,20 @@ use serde::{Deserialize, Serialize};
|
|||
use std::path::PathBuf;
|
||||
use std::sync::Mutex;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct SshSession {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
pub host: String,
|
||||
pub port: i32,
|
||||
pub username: String,
|
||||
pub key_file: String,
|
||||
pub folder: String,
|
||||
pub color: String,
|
||||
pub created_at: i64,
|
||||
pub last_used_at: i64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Session {
|
||||
pub id: String,
|
||||
|
|
@ -73,6 +87,19 @@ impl SessionDb {
|
|||
key TEXT PRIMARY KEY,
|
||||
value TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS ssh_sessions (
|
||||
id TEXT PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
host TEXT NOT NULL,
|
||||
port INTEGER NOT NULL DEFAULT 22,
|
||||
username TEXT NOT NULL,
|
||||
key_file TEXT DEFAULT '',
|
||||
folder TEXT DEFAULT '',
|
||||
color TEXT DEFAULT '#89b4fa',
|
||||
created_at INTEGER NOT NULL,
|
||||
last_used_at INTEGER NOT NULL
|
||||
);
|
||||
"
|
||||
).map_err(|e| format!("Migration failed: {e}"))?;
|
||||
Ok(())
|
||||
|
|
@ -212,4 +239,80 @@ impl SessionDb {
|
|||
Ok(LayoutState { preset, pane_ids })
|
||||
}).map_err(|e| format!("Layout read failed: {e}"))
|
||||
}
|
||||
|
||||
// --- SSH session methods ---
|
||||
|
||||
pub fn list_ssh_sessions(&self) -> Result<Vec<SshSession>, String> {
|
||||
let conn = self.conn.lock().unwrap();
|
||||
let mut stmt = conn
|
||||
.prepare("SELECT id, name, host, port, username, key_file, folder, color, created_at, last_used_at FROM ssh_sessions ORDER BY last_used_at DESC")
|
||||
.map_err(|e| format!("SSH query prepare failed: {e}"))?;
|
||||
|
||||
let sessions = stmt
|
||||
.query_map([], |row| {
|
||||
Ok(SshSession {
|
||||
id: row.get(0)?,
|
||||
name: row.get(1)?,
|
||||
host: row.get(2)?,
|
||||
port: row.get(3)?,
|
||||
username: row.get(4)?,
|
||||
key_file: row.get(5)?,
|
||||
folder: row.get(6)?,
|
||||
color: row.get(7)?,
|
||||
created_at: row.get(8)?,
|
||||
last_used_at: row.get(9)?,
|
||||
})
|
||||
})
|
||||
.map_err(|e| format!("SSH query failed: {e}"))?
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.map_err(|e| format!("SSH row read failed: {e}"))?;
|
||||
|
||||
Ok(sessions)
|
||||
}
|
||||
|
||||
pub fn save_ssh_session(&self, session: &SshSession) -> Result<(), String> {
|
||||
let conn = self.conn.lock().unwrap();
|
||||
conn.execute(
|
||||
"INSERT OR REPLACE INTO ssh_sessions (id, name, host, port, username, key_file, folder, color, created_at, last_used_at) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10)",
|
||||
params![
|
||||
session.id,
|
||||
session.name,
|
||||
session.host,
|
||||
session.port,
|
||||
session.username,
|
||||
session.key_file,
|
||||
session.folder,
|
||||
session.color,
|
||||
session.created_at,
|
||||
session.last_used_at,
|
||||
],
|
||||
).map_err(|e| format!("SSH insert failed: {e}"))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn delete_ssh_session(&self, id: &str) -> Result<(), String> {
|
||||
let conn = self.conn.lock().unwrap();
|
||||
conn.execute("DELETE FROM ssh_sessions WHERE id = ?1", params![id])
|
||||
.map_err(|e| format!("SSH delete failed: {e}"))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn update_ssh_session(&self, session: &SshSession) -> Result<(), String> {
|
||||
let conn = self.conn.lock().unwrap();
|
||||
conn.execute(
|
||||
"UPDATE ssh_sessions SET name = ?1, host = ?2, port = ?3, username = ?4, key_file = ?5, folder = ?6, color = ?7, last_used_at = ?8 WHERE id = ?9",
|
||||
params![
|
||||
session.name,
|
||||
session.host,
|
||||
session.port,
|
||||
session.username,
|
||||
session.key_file,
|
||||
session.folder,
|
||||
session.color,
|
||||
session.last_used_at,
|
||||
session.id,
|
||||
],
|
||||
).map_err(|e| format!("SSH update failed: {e}"))?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue