支持无GUI的Server运行模式
This commit is contained in:
@@ -3,6 +3,7 @@ use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
use tauri::State;
|
||||
|
||||
use crate::acp::binary_cache;
|
||||
@@ -17,6 +18,7 @@ use crate::acp::types::{
|
||||
use crate::db::service::agent_setting_service;
|
||||
use crate::db::AppDatabase;
|
||||
use crate::models::agent::AgentType;
|
||||
use crate::web::event_bridge::EventEmitter;
|
||||
|
||||
const ACP_AGENTS_UPDATED_EVENT: &str = "app://acp-agents-updated";
|
||||
|
||||
@@ -28,12 +30,12 @@ struct AcpAgentsUpdatedEventPayload {
|
||||
}
|
||||
|
||||
fn emit_acp_agents_updated(
|
||||
app: &tauri::AppHandle,
|
||||
emitter: &EventEmitter,
|
||||
reason: &'static str,
|
||||
agent_type: Option<AgentType>,
|
||||
) {
|
||||
crate::web::event_bridge::emit_event(
|
||||
app,
|
||||
emitter,
|
||||
ACP_AGENTS_UPDATED_EVENT,
|
||||
AcpAgentsUpdatedEventPayload { reason, agent_type },
|
||||
);
|
||||
@@ -1346,7 +1348,7 @@ pub(crate) fn build_runtime_env_from_setting(
|
||||
merged
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn acp_preflight(
|
||||
agent_type: AgentType,
|
||||
force_refresh: Option<bool>,
|
||||
@@ -1357,7 +1359,8 @@ pub async fn acp_preflight(
|
||||
Ok(preflight::run_preflight(agent_type).await)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn acp_connect(
|
||||
agent_type: AgentType,
|
||||
working_dir: Option<String>,
|
||||
@@ -1400,6 +1403,7 @@ pub async fn acp_connect(
|
||||
}
|
||||
}
|
||||
|
||||
let emitter = EventEmitter::Tauri(app_handle);
|
||||
manager
|
||||
.spawn_agent(
|
||||
agent_type,
|
||||
@@ -1407,12 +1411,13 @@ pub async fn acp_connect(
|
||||
session_id,
|
||||
runtime_env,
|
||||
window.label().to_string(),
|
||||
app_handle,
|
||||
emitter,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn acp_prompt(
|
||||
connection_id: String,
|
||||
blocks: Vec<PromptInputBlock>,
|
||||
@@ -1421,7 +1426,8 @@ pub async fn acp_prompt(
|
||||
manager.send_prompt(&connection_id, blocks).await
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn acp_set_mode(
|
||||
connection_id: String,
|
||||
mode_id: String,
|
||||
@@ -1430,7 +1436,8 @@ pub async fn acp_set_mode(
|
||||
manager.set_mode(&connection_id, mode_id).await
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn acp_set_config_option(
|
||||
connection_id: String,
|
||||
config_id: String,
|
||||
@@ -1442,7 +1449,8 @@ pub async fn acp_set_config_option(
|
||||
.await
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn acp_cancel(
|
||||
connection_id: String,
|
||||
manager: State<'_, ConnectionManager>,
|
||||
@@ -1450,7 +1458,8 @@ pub async fn acp_cancel(
|
||||
manager.cancel(&connection_id).await
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn acp_fork(
|
||||
connection_id: String,
|
||||
manager: State<'_, ConnectionManager>,
|
||||
@@ -1458,7 +1467,8 @@ pub async fn acp_fork(
|
||||
manager.fork_session(&connection_id).await
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn acp_respond_permission(
|
||||
connection_id: String,
|
||||
request_id: String,
|
||||
@@ -1470,7 +1480,8 @@ pub async fn acp_respond_permission(
|
||||
.await
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn acp_disconnect(
|
||||
connection_id: String,
|
||||
manager: State<'_, ConnectionManager>,
|
||||
@@ -1478,17 +1489,17 @@ pub async fn acp_disconnect(
|
||||
manager.disconnect(&connection_id).await
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn acp_list_connections(
|
||||
manager: State<'_, ConnectionManager>,
|
||||
) -> Result<Vec<ConnectionInfo>, AcpError> {
|
||||
Ok(manager.list_connections().await)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn acp_get_agent_status(
|
||||
pub(crate) async fn acp_get_agent_status_core(
|
||||
agent_type: AgentType,
|
||||
db: tauri::State<'_, AppDatabase>,
|
||||
db: &AppDatabase,
|
||||
) -> Result<crate::acp::types::AcpAgentStatus, AcpError> {
|
||||
let platform = registry::current_platform();
|
||||
let meta = registry::get_agent_meta(agent_type);
|
||||
@@ -1523,9 +1534,17 @@ pub async fn acp_get_agent_status(
|
||||
})
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn acp_list_agents(
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn acp_get_agent_status(
|
||||
agent_type: AgentType,
|
||||
db: tauri::State<'_, AppDatabase>,
|
||||
) -> Result<crate::acp::types::AcpAgentStatus, AcpError> {
|
||||
acp_get_agent_status_core(agent_type, &db).await
|
||||
}
|
||||
|
||||
pub(crate) async fn acp_list_agents_core(
|
||||
db: &AppDatabase,
|
||||
) -> Result<Vec<AcpAgentInfo>, AcpError> {
|
||||
let platform = registry::current_platform();
|
||||
let agent_types = registry::all_acp_agents();
|
||||
@@ -1660,7 +1679,15 @@ pub async fn acp_list_agents(
|
||||
Ok(agents)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn acp_list_agents(
|
||||
db: tauri::State<'_, AppDatabase>,
|
||||
) -> Result<Vec<AcpAgentInfo>, AcpError> {
|
||||
acp_list_agents_core(&db).await
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn acp_clear_binary_cache(agent_type: AgentType) -> Result<(), AcpError> {
|
||||
let meta = registry::get_agent_meta(agent_type);
|
||||
if matches!(
|
||||
@@ -1682,7 +1709,7 @@ pub(crate) async fn acp_update_agent_preferences_core(
|
||||
codex_auth_json: Option<String>,
|
||||
codex_config_toml: Option<String>,
|
||||
db: &AppDatabase,
|
||||
app: &tauri::AppHandle,
|
||||
emitter: &EventEmitter,
|
||||
) -> Result<(), AcpError> {
|
||||
let default = agent_setting_service::AgentDefaultInput {
|
||||
agent_type,
|
||||
@@ -1737,7 +1764,7 @@ pub(crate) async fn acp_update_agent_preferences_core(
|
||||
codex_config_toml.as_deref(),
|
||||
)?;
|
||||
}
|
||||
emit_acp_agents_updated(app, "preferences_updated", Some(agent_type));
|
||||
emit_acp_agents_updated(emitter, "preferences_updated", Some(agent_type));
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
@@ -1748,7 +1775,7 @@ pub(crate) async fn acp_update_agent_preferences_core(
|
||||
if let Some(raw) = config_json.as_deref() {
|
||||
persist_agent_local_config_json(agent_type, Some(raw))?;
|
||||
}
|
||||
emit_acp_agents_updated(app, "preferences_updated", Some(agent_type));
|
||||
emit_acp_agents_updated(emitter, "preferences_updated", Some(agent_type));
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
@@ -1756,7 +1783,7 @@ pub(crate) async fn acp_update_agent_preferences_core(
|
||||
if let Some(raw) = config_json.as_deref() {
|
||||
persist_cline_local_config(Some(raw))?;
|
||||
}
|
||||
emit_acp_agents_updated(app, "preferences_updated", Some(agent_type));
|
||||
emit_acp_agents_updated(emitter, "preferences_updated", Some(agent_type));
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
@@ -1775,11 +1802,12 @@ pub(crate) async fn acp_update_agent_preferences_core(
|
||||
let local_patch_json = serde_json::to_string(&local_patch_value)
|
||||
.map_err(|e| AcpError::protocol(format!("serialize local patch failed: {e}")))?;
|
||||
persist_agent_local_config_json(agent_type, Some(local_patch_json.as_str()))?;
|
||||
emit_acp_agents_updated(app, "preferences_updated", Some(agent_type));
|
||||
emit_acp_agents_updated(emitter, "preferences_updated", Some(agent_type));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub async fn acp_update_agent_preferences(
|
||||
agent_type: AgentType,
|
||||
@@ -1792,15 +1820,16 @@ pub async fn acp_update_agent_preferences(
|
||||
db: State<'_, AppDatabase>,
|
||||
app: tauri::AppHandle,
|
||||
) -> Result<(), AcpError> {
|
||||
let emitter = EventEmitter::Tauri(app);
|
||||
acp_update_agent_preferences_core(
|
||||
agent_type, enabled, env, config_json, opencode_auth_json,
|
||||
codex_auth_json, codex_config_toml, &db, &app,
|
||||
codex_auth_json, codex_config_toml, &db, &emitter,
|
||||
).await
|
||||
}
|
||||
|
||||
pub(crate) async fn acp_download_agent_binary_core(
|
||||
agent_type: AgentType,
|
||||
app: &tauri::AppHandle,
|
||||
emitter: &EventEmitter,
|
||||
) -> Result<(), AcpError> {
|
||||
let meta = registry::get_agent_meta(agent_type);
|
||||
match meta.distribution {
|
||||
@@ -1823,7 +1852,7 @@ pub(crate) async fn acp_download_agent_binary_core(
|
||||
|
||||
let _ = binary_cache::ensure_binary_for_agent(agent_type, version, fallback.url, cmd)
|
||||
.await?;
|
||||
emit_acp_agents_updated(app, "binary_downloaded", Some(agent_type));
|
||||
emit_acp_agents_updated(emitter, "binary_downloaded", Some(agent_type));
|
||||
Ok(())
|
||||
}
|
||||
registry::AgentDistribution::Npx { .. } => Err(
|
||||
@@ -1832,12 +1861,14 @@ pub(crate) async fn acp_download_agent_binary_core(
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn acp_download_agent_binary(
|
||||
agent_type: AgentType,
|
||||
app: tauri::AppHandle,
|
||||
) -> Result<(), AcpError> {
|
||||
acp_download_agent_binary_core(agent_type, &app).await
|
||||
let emitter = EventEmitter::Tauri(app);
|
||||
acp_download_agent_binary_core(agent_type, &emitter).await
|
||||
}
|
||||
|
||||
pub(crate) async fn acp_detect_agent_local_version_core(
|
||||
@@ -1863,7 +1894,8 @@ pub(crate) async fn acp_detect_agent_local_version_core(
|
||||
Ok(fallback)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn acp_detect_agent_local_version(
|
||||
agent_type: AgentType,
|
||||
db: State<'_, AppDatabase>,
|
||||
@@ -1875,7 +1907,7 @@ pub(crate) async fn acp_prepare_npx_agent_core(
|
||||
agent_type: AgentType,
|
||||
registry_version: Option<String>,
|
||||
db: &AppDatabase,
|
||||
app: &tauri::AppHandle,
|
||||
emitter: &EventEmitter,
|
||||
) -> Result<String, AcpError> {
|
||||
let meta = registry::get_agent_meta(agent_type);
|
||||
match meta.distribution {
|
||||
@@ -1918,7 +1950,7 @@ pub(crate) async fn acp_prepare_npx_agent_core(
|
||||
)
|
||||
.await
|
||||
.map_err(|e| AcpError::protocol(e.to_string()))?;
|
||||
emit_acp_agents_updated(app, "npx_prepared", Some(agent_type));
|
||||
emit_acp_agents_updated(emitter, "npx_prepared", Some(agent_type));
|
||||
Ok(resolved)
|
||||
}
|
||||
registry::AgentDistribution::Binary { .. } => Err(AcpError::protocol(
|
||||
@@ -1927,20 +1959,22 @@ pub(crate) async fn acp_prepare_npx_agent_core(
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn acp_prepare_npx_agent(
|
||||
agent_type: AgentType,
|
||||
registry_version: Option<String>,
|
||||
db: State<'_, AppDatabase>,
|
||||
app: tauri::AppHandle,
|
||||
) -> Result<String, AcpError> {
|
||||
acp_prepare_npx_agent_core(agent_type, registry_version, &db, &app).await
|
||||
let emitter = EventEmitter::Tauri(app);
|
||||
acp_prepare_npx_agent_core(agent_type, registry_version, &db, &emitter).await
|
||||
}
|
||||
|
||||
pub(crate) async fn acp_uninstall_agent_core(
|
||||
agent_type: AgentType,
|
||||
db: &AppDatabase,
|
||||
app: &tauri::AppHandle,
|
||||
emitter: &EventEmitter,
|
||||
) -> Result<(), AcpError> {
|
||||
let meta = registry::get_agent_meta(agent_type);
|
||||
match meta.distribution {
|
||||
@@ -1955,23 +1989,25 @@ pub(crate) async fn acp_uninstall_agent_core(
|
||||
agent_setting_service::set_installed_version(&db.conn, agent_type, None)
|
||||
.await
|
||||
.map_err(|e| AcpError::protocol(e.to_string()))?;
|
||||
emit_acp_agents_updated(app, "agent_uninstalled", Some(agent_type));
|
||||
emit_acp_agents_updated(emitter, "agent_uninstalled", Some(agent_type));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn acp_uninstall_agent(
|
||||
agent_type: AgentType,
|
||||
db: State<'_, AppDatabase>,
|
||||
app: tauri::AppHandle,
|
||||
) -> Result<(), AcpError> {
|
||||
acp_uninstall_agent_core(agent_type, &db, &app).await
|
||||
let emitter = EventEmitter::Tauri(app);
|
||||
acp_uninstall_agent_core(agent_type, &db, &emitter).await
|
||||
}
|
||||
|
||||
pub(crate) async fn acp_reorder_agents_core(
|
||||
agent_types: &[AgentType],
|
||||
db: &AppDatabase,
|
||||
app: &tauri::AppHandle,
|
||||
emitter: &EventEmitter,
|
||||
) -> Result<(), AcpError> {
|
||||
if agent_types.is_empty() {
|
||||
return Ok(());
|
||||
@@ -1986,20 +2022,22 @@ pub(crate) async fn acp_reorder_agents_core(
|
||||
AcpError::protocol(message)
|
||||
}
|
||||
})?;
|
||||
emit_acp_agents_updated(app, "agent_reordered", None);
|
||||
emit_acp_agents_updated(emitter, "agent_reordered", None);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn acp_reorder_agents(
|
||||
agent_types: Vec<AgentType>,
|
||||
db: State<'_, AppDatabase>,
|
||||
app: tauri::AppHandle,
|
||||
) -> Result<(), AcpError> {
|
||||
acp_reorder_agents_core(&agent_types, &db, &app).await
|
||||
let emitter = EventEmitter::Tauri(app);
|
||||
acp_reorder_agents_core(&agent_types, &db, &emitter).await
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn acp_list_agent_skills(
|
||||
agent_type: AgentType,
|
||||
workspace_path: Option<String>,
|
||||
@@ -2065,7 +2103,7 @@ pub async fn acp_list_agent_skills(
|
||||
})
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn acp_read_agent_skill(
|
||||
agent_type: AgentType,
|
||||
scope: AgentSkillScope,
|
||||
@@ -2088,7 +2126,7 @@ pub async fn acp_read_agent_skill(
|
||||
Ok(AgentSkillContent { skill, content })
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn acp_save_agent_skill(
|
||||
agent_type: AgentType,
|
||||
scope: AgentSkillScope,
|
||||
@@ -2148,7 +2186,7 @@ pub async fn acp_save_agent_skill(
|
||||
Ok(skill)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn acp_delete_agent_skill(
|
||||
agent_type: AgentType,
|
||||
scope: AgentSkillScope,
|
||||
|
||||
@@ -13,7 +13,8 @@ use crate::parsers::openclaw::OpenClawParser;
|
||||
use crate::parsers::opencode::OpenCodeParser;
|
||||
use crate::parsers::{path_eq_for_matching, AgentParser, ParseError};
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn list_folder_conversations(
|
||||
db: tauri::State<'_, AppDatabase>,
|
||||
folder_id: i32,
|
||||
@@ -115,7 +116,7 @@ fn list_conversations_sync(
|
||||
all_conversations
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn list_conversations(
|
||||
agent_type: Option<AgentType>,
|
||||
search: Option<String>,
|
||||
@@ -132,7 +133,7 @@ pub async fn list_conversations(
|
||||
})
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn get_conversation(
|
||||
agent_type: AgentType,
|
||||
conversation_id: String,
|
||||
@@ -158,7 +159,7 @@ pub async fn get_conversation(
|
||||
})?
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn list_folders() -> Result<Vec<FolderInfo>, AppCommandError> {
|
||||
tokio::task::spawn_blocking(move || -> Result<Vec<FolderInfo>, AppCommandError> {
|
||||
let all_conversations = list_conversations_sync(None, None, None, None);
|
||||
@@ -170,7 +171,7 @@ pub async fn list_folders() -> Result<Vec<FolderInfo>, AppCommandError> {
|
||||
})?
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn get_stats() -> Result<AgentStats, AppCommandError> {
|
||||
tokio::task::spawn_blocking(move || -> Result<AgentStats, AppCommandError> {
|
||||
let all_conversations = list_conversations_sync(None, None, None, None);
|
||||
@@ -183,7 +184,7 @@ pub async fn get_stats() -> Result<AgentStats, AppCommandError> {
|
||||
})?
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn get_sidebar_data() -> Result<SidebarData, AppCommandError> {
|
||||
tokio::task::spawn_blocking(move || -> Result<SidebarData, AppCommandError> {
|
||||
let all_conversations = list_conversations_sync(None, None, None, None);
|
||||
@@ -231,7 +232,8 @@ fn compute_folders(all_conversations: &[ConversationSummary]) -> Vec<FolderInfo>
|
||||
folders
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn import_local_conversations(
|
||||
db: tauri::State<'_, AppDatabase>,
|
||||
folder_id: i32,
|
||||
@@ -351,7 +353,8 @@ pub async fn get_folder_conversation_core(
|
||||
})
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn get_folder_conversation(
|
||||
db: tauri::State<'_, AppDatabase>,
|
||||
conversation_id: i32,
|
||||
@@ -382,7 +385,8 @@ pub async fn create_conversation_core(
|
||||
Ok(model.id)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn create_conversation(
|
||||
db: tauri::State<'_, AppDatabase>,
|
||||
folder_id: i32,
|
||||
@@ -411,7 +415,8 @@ async fn detect_git_branch(path: &str) -> Option<String> {
|
||||
Some(branch)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn update_conversation_status(
|
||||
db: tauri::State<'_, AppDatabase>,
|
||||
conversation_id: i32,
|
||||
@@ -426,7 +431,8 @@ pub async fn update_conversation_status(
|
||||
.map_err(AppCommandError::from)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn update_conversation_title(
|
||||
db: tauri::State<'_, AppDatabase>,
|
||||
conversation_id: i32,
|
||||
@@ -437,7 +443,8 @@ pub async fn update_conversation_title(
|
||||
.map_err(AppCommandError::from)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn update_conversation_external_id(
|
||||
db: tauri::State<'_, AppDatabase>,
|
||||
conversation_id: i32,
|
||||
@@ -448,7 +455,8 @@ pub async fn update_conversation_external_id(
|
||||
.map_err(AppCommandError::from)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn delete_conversation(
|
||||
db: tauri::State<'_, AppDatabase>,
|
||||
conversation_id: i32,
|
||||
|
||||
@@ -72,7 +72,8 @@ pub(crate) fn load_package_scripts_as_commands(folder_path: &str) -> Vec<(String
|
||||
commands
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn list_folder_commands(
|
||||
db: tauri::State<'_, AppDatabase>,
|
||||
folder_id: i32,
|
||||
@@ -80,7 +81,8 @@ pub async fn list_folder_commands(
|
||||
folder_command_service::list_by_folder(&db.conn, folder_id).await
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn create_folder_command(
|
||||
db: tauri::State<'_, AppDatabase>,
|
||||
folder_id: i32,
|
||||
@@ -90,7 +92,8 @@ pub async fn create_folder_command(
|
||||
folder_command_service::create(&db.conn, folder_id, &name, &command).await
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn update_folder_command(
|
||||
db: tauri::State<'_, AppDatabase>,
|
||||
id: i32,
|
||||
@@ -101,7 +104,8 @@ pub async fn update_folder_command(
|
||||
folder_command_service::update(&db.conn, id, name, command, sort_order).await
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn delete_folder_command(
|
||||
db: tauri::State<'_, AppDatabase>,
|
||||
id: i32,
|
||||
@@ -109,7 +113,8 @@ pub async fn delete_folder_command(
|
||||
folder_command_service::delete(&db.conn, id).await
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn reorder_folder_commands(
|
||||
db: tauri::State<'_, AppDatabase>,
|
||||
folder_id: i32,
|
||||
@@ -118,7 +123,8 @@ pub async fn reorder_folder_commands(
|
||||
folder_command_service::reorder(&db.conn, folder_id, ids).await
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn bootstrap_folder_commands_from_package_json(
|
||||
db: tauri::State<'_, AppDatabase>,
|
||||
folder_id: i32,
|
||||
|
||||
+163
-126
@@ -14,6 +14,7 @@ use serde::Serialize;
|
||||
use tokio::sync::Semaphore;
|
||||
use walkdir::WalkDir;
|
||||
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
use tauri::Manager;
|
||||
|
||||
use crate::app_error::AppCommandError;
|
||||
@@ -21,6 +22,7 @@ use crate::db::error::DbError;
|
||||
use crate::db::service::folder_service;
|
||||
use crate::db::AppDatabase;
|
||||
use crate::models::{FolderDetail, FolderHistoryEntry, GitCredentials, OpenedConversation};
|
||||
use crate::web::event_bridge::EventEmitter;
|
||||
|
||||
/// Configure a git command for remote operations:
|
||||
/// - Always disable interactive prompts (prevent hanging in a GUI app)
|
||||
@@ -31,9 +33,9 @@ async fn prepare_remote_git_cmd(
|
||||
repo_path: &str,
|
||||
credentials: Option<&GitCredentials>,
|
||||
db: &AppDatabase,
|
||||
app_handle: &tauri::AppHandle,
|
||||
data_dir: &std::path::Path,
|
||||
) {
|
||||
prepare_remote_git_cmd_with_remote(cmd, repo_path, None, credentials, db, app_handle).await;
|
||||
prepare_remote_git_cmd_with_remote(cmd, repo_path, None, credentials, db, data_dir).await;
|
||||
}
|
||||
|
||||
/// Same as `prepare_remote_git_cmd` but allows specifying a remote name
|
||||
@@ -44,29 +46,27 @@ async fn prepare_remote_git_cmd_with_remote(
|
||||
remote_name: Option<&str>,
|
||||
credentials: Option<&GitCredentials>,
|
||||
db: &AppDatabase,
|
||||
app_handle: &tauri::AppHandle,
|
||||
data_dir: &std::path::Path,
|
||||
) {
|
||||
cmd.env("GIT_TERMINAL_PROMPT", "0")
|
||||
.stdin(Stdio::null());
|
||||
|
||||
if let Ok(data_dir) = app_handle.path().app_data_dir() {
|
||||
if let Some(creds) = credentials {
|
||||
// Explicit credentials provided (e.g. from credential dialog)
|
||||
if let Ok(askpass) = crate::git_credential::ensure_askpass_script(&data_dir) {
|
||||
crate::git_credential::inject_credentials(
|
||||
cmd,
|
||||
&creds.username,
|
||||
&creds.password,
|
||||
&askpass,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// Fall back to stored accounts, matching against the specified remote
|
||||
crate::git_credential::try_inject_for_repo_remote(
|
||||
cmd, repo_path, remote_name, &db.conn, &data_dir,
|
||||
)
|
||||
.await;
|
||||
if let Some(creds) = credentials {
|
||||
// Explicit credentials provided (e.g. from credential dialog)
|
||||
if let Ok(askpass) = crate::git_credential::ensure_askpass_script(data_dir) {
|
||||
crate::git_credential::inject_credentials(
|
||||
cmd,
|
||||
&creds.username,
|
||||
&creds.password,
|
||||
&askpass,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// Fall back to stored accounts, matching against the specified remote
|
||||
crate::git_credential::try_inject_for_repo_remote(
|
||||
cmd, repo_path, remote_name, &db.conn, data_dir,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,24 +76,22 @@ async fn prepare_remote_git_cmd_for_url(
|
||||
clone_url: &str,
|
||||
credentials: Option<&GitCredentials>,
|
||||
db: &AppDatabase,
|
||||
app_handle: &tauri::AppHandle,
|
||||
data_dir: &std::path::Path,
|
||||
) {
|
||||
cmd.env("GIT_TERMINAL_PROMPT", "0")
|
||||
.stdin(Stdio::null());
|
||||
|
||||
if let Ok(data_dir) = app_handle.path().app_data_dir() {
|
||||
if let Some(creds) = credentials {
|
||||
if let Ok(askpass) = crate::git_credential::ensure_askpass_script(&data_dir) {
|
||||
crate::git_credential::inject_credentials(
|
||||
cmd,
|
||||
&creds.username,
|
||||
&creds.password,
|
||||
&askpass,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
crate::git_credential::try_inject_for_url(cmd, clone_url, &db.conn, &data_dir).await;
|
||||
if let Some(creds) = credentials {
|
||||
if let Ok(askpass) = crate::git_credential::ensure_askpass_script(data_dir) {
|
||||
crate::git_credential::inject_credentials(
|
||||
cmd,
|
||||
&creds.username,
|
||||
&creds.password,
|
||||
&askpass,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
crate::git_credential::try_inject_for_url(cmd, clone_url, &db.conn, data_dir).await;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -462,7 +460,8 @@ async fn estimate_push_commit_count(path: &str) -> usize {
|
||||
parse_count_from_output(&output.stdout).unwrap_or(0)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn get_folder(
|
||||
db: tauri::State<'_, AppDatabase>,
|
||||
folder_id: i32,
|
||||
@@ -472,7 +471,8 @@ pub async fn get_folder(
|
||||
.ok_or_else(|| DbError::Migration(format!("Folder {} not found", folder_id)))
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn load_folder_history(
|
||||
db: tauri::State<'_, AppDatabase>,
|
||||
) -> Result<Vec<FolderHistoryEntry>, AppCommandError> {
|
||||
@@ -481,7 +481,8 @@ pub async fn load_folder_history(
|
||||
.map_err(AppCommandError::from)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn add_folder_to_history(
|
||||
db: tauri::State<'_, AppDatabase>,
|
||||
path: String,
|
||||
@@ -513,7 +514,8 @@ pub(crate) async fn set_folder_parent_branch_core(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn set_folder_parent_branch(
|
||||
db: tauri::State<'_, AppDatabase>,
|
||||
path: String,
|
||||
@@ -522,7 +524,8 @@ pub async fn set_folder_parent_branch(
|
||||
set_folder_parent_branch_core(&db.conn, &path, parent_branch).await
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn remove_folder_from_history(
|
||||
db: tauri::State<'_, AppDatabase>,
|
||||
path: String,
|
||||
@@ -532,7 +535,8 @@ pub async fn remove_folder_from_history(
|
||||
.map_err(AppCommandError::from)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn save_folder_opened_conversations(
|
||||
db: tauri::State<'_, AppDatabase>,
|
||||
folder_id: i32,
|
||||
@@ -541,7 +545,7 @@ pub async fn save_folder_opened_conversations(
|
||||
folder_service::save_opened_conversations(&db.conn, folder_id, items).await
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn create_folder_directory(path: String) -> Result<(), AppCommandError> {
|
||||
std::fs::create_dir_all(&path).map_err(AppCommandError::io)
|
||||
}
|
||||
@@ -551,7 +555,7 @@ pub(crate) async fn clone_repository_core(
|
||||
target_dir: &str,
|
||||
credentials: Option<&GitCredentials>,
|
||||
db: &AppDatabase,
|
||||
app_handle: &tauri::AppHandle,
|
||||
data_dir: &std::path::Path,
|
||||
) -> Result<(), AppCommandError> {
|
||||
if url.trim().is_empty() || target_dir.trim().is_empty() {
|
||||
return Err(AppCommandError::invalid_input(
|
||||
@@ -561,7 +565,7 @@ pub(crate) async fn clone_repository_core(
|
||||
|
||||
let mut cmd = crate::process::tokio_command("git");
|
||||
cmd.args(["clone", url, target_dir]);
|
||||
prepare_remote_git_cmd_for_url(&mut cmd, url, credentials, db, app_handle).await;
|
||||
prepare_remote_git_cmd_for_url(&mut cmd, url, credentials, db, data_dir).await;
|
||||
|
||||
let output = cmd
|
||||
.output()
|
||||
@@ -584,7 +588,8 @@ pub(crate) async fn clone_repository_core(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn clone_repository(
|
||||
url: String,
|
||||
target_dir: String,
|
||||
@@ -592,7 +597,10 @@ pub async fn clone_repository(
|
||||
db: tauri::State<'_, AppDatabase>,
|
||||
app_handle: tauri::AppHandle,
|
||||
) -> Result<(), AppCommandError> {
|
||||
clone_repository_core(&url, &target_dir, credentials.as_ref(), &db, &app_handle).await
|
||||
let data_dir = app_handle.path().app_data_dir().map_err(|e| {
|
||||
AppCommandError::external_command("Failed to resolve app data dir", e.to_string())
|
||||
})?;
|
||||
clone_repository_core(&url, &target_dir, credentials.as_ref(), &db, &data_dir).await
|
||||
}
|
||||
|
||||
fn classify_git_clone_error(stderr: &str) -> AppCommandError {
|
||||
@@ -643,7 +651,7 @@ fn classify_git_clone_error(stderr: &str) -> AppCommandError {
|
||||
AppCommandError::external_command("Git clone failed", stderr.to_string())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn get_git_branch(path: String) -> Result<Option<String>, AppCommandError> {
|
||||
let output = crate::process::tokio_command("git")
|
||||
.args(["rev-parse", "--abbrev-ref", "HEAD"])
|
||||
@@ -679,7 +687,7 @@ pub async fn get_git_branch(path: String) -> Result<Option<String>, AppCommandEr
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn git_init(path: String) -> Result<(), AppCommandError> {
|
||||
let output = crate::process::tokio_command("git")
|
||||
.args(["init"])
|
||||
@@ -698,14 +706,14 @@ pub(crate) async fn git_pull_core(
|
||||
path: &str,
|
||||
credentials: Option<&GitCredentials>,
|
||||
db: &AppDatabase,
|
||||
app_handle: &tauri::AppHandle,
|
||||
data_dir: &std::path::Path,
|
||||
) -> Result<GitPullResult, AppCommandError> {
|
||||
let head_before = get_head_hash(path).await?;
|
||||
|
||||
// Step 1: fetch from remote
|
||||
let mut fetch_cmd = crate::process::tokio_command("git");
|
||||
fetch_cmd.args(["fetch"]).current_dir(path);
|
||||
prepare_remote_git_cmd(&mut fetch_cmd, path, credentials, db, app_handle).await;
|
||||
prepare_remote_git_cmd(&mut fetch_cmd, path, credentials, db, data_dir).await;
|
||||
|
||||
let fetch_output = fetch_cmd
|
||||
.output()
|
||||
@@ -823,20 +831,24 @@ pub(crate) async fn git_pull_core(
|
||||
})
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn git_pull(
|
||||
path: String,
|
||||
credentials: Option<GitCredentials>,
|
||||
db: tauri::State<'_, AppDatabase>,
|
||||
app_handle: tauri::AppHandle,
|
||||
) -> Result<GitPullResult, AppCommandError> {
|
||||
git_pull_core(&path, credentials.as_ref(), &db, &app_handle).await
|
||||
let data_dir = app_handle.path().app_data_dir().map_err(|e| {
|
||||
AppCommandError::external_command("Failed to resolve app data dir", e.to_string())
|
||||
})?;
|
||||
git_pull_core(&path, credentials.as_ref(), &db, &data_dir).await
|
||||
}
|
||||
|
||||
/// Start a merge with the upstream branch (used by merge workspace after pull conflict detection).
|
||||
/// This recreates the conflict state so that :1:, :2:, :3: stage entries are available.
|
||||
/// If `upstream_commit` is provided, merge against that specific commit instead of `@{u}`.
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn git_start_pull_merge(
|
||||
path: String,
|
||||
upstream_commit: Option<String>,
|
||||
@@ -862,7 +874,7 @@ pub async fn git_start_pull_merge(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn git_has_merge_head(path: String) -> Result<bool, AppCommandError> {
|
||||
let output = crate::process::tokio_command("git")
|
||||
.args(["rev-parse", "--verify", "MERGE_HEAD"])
|
||||
@@ -877,11 +889,11 @@ pub(crate) async fn git_fetch_core(
|
||||
path: &str,
|
||||
credentials: Option<&GitCredentials>,
|
||||
db: &AppDatabase,
|
||||
app_handle: &tauri::AppHandle,
|
||||
data_dir: &std::path::Path,
|
||||
) -> Result<String, AppCommandError> {
|
||||
let mut cmd = crate::process::tokio_command("git");
|
||||
cmd.args(["fetch", "--all"]).current_dir(path);
|
||||
prepare_remote_git_cmd(&mut cmd, path, credentials, db, app_handle).await;
|
||||
prepare_remote_git_cmd(&mut cmd, path, credentials, db, data_dir).await;
|
||||
|
||||
let output = cmd
|
||||
.output()
|
||||
@@ -894,17 +906,21 @@ pub(crate) async fn git_fetch_core(
|
||||
Ok(String::from_utf8_lossy(&output.stderr).trim().to_string())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn git_fetch(
|
||||
path: String,
|
||||
credentials: Option<GitCredentials>,
|
||||
db: tauri::State<'_, AppDatabase>,
|
||||
app_handle: tauri::AppHandle,
|
||||
) -> Result<String, AppCommandError> {
|
||||
git_fetch_core(&path, credentials.as_ref(), &db, &app_handle).await
|
||||
let data_dir = app_handle.path().app_data_dir().map_err(|e| {
|
||||
AppCommandError::external_command("Failed to resolve app data dir", e.to_string())
|
||||
})?;
|
||||
git_fetch_core(&path, credentials.as_ref(), &db, &data_dir).await
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn git_push_info(path: String) -> Result<GitPushInfo, AppCommandError> {
|
||||
// Get current branch name
|
||||
let branch_output = crate::process::tokio_command("git")
|
||||
@@ -941,7 +957,8 @@ pub async fn git_push_info(path: String) -> Result<GitPushInfo, AppCommandError>
|
||||
}
|
||||
|
||||
pub(crate) async fn git_push_core(
|
||||
app: &tauri::AppHandle,
|
||||
data_dir: &std::path::Path,
|
||||
emitter: &EventEmitter,
|
||||
folder_id: Option<i32>,
|
||||
path: &str,
|
||||
remote: Option<&str>,
|
||||
@@ -990,13 +1007,13 @@ pub(crate) async fn git_push_core(
|
||||
let mut cmd = crate::process::tokio_command("git");
|
||||
cmd.args(["push", "--set-upstream", target_remote, &branch])
|
||||
.current_dir(path);
|
||||
prepare_remote_git_cmd_with_remote(&mut cmd, path, Some(target_remote), credentials, db, app).await;
|
||||
prepare_remote_git_cmd_with_remote(&mut cmd, path, Some(target_remote), credentials, db, data_dir).await;
|
||||
cmd.output().await.map_err(AppCommandError::io)?
|
||||
} else {
|
||||
let mut cmd = crate::process::tokio_command("git");
|
||||
cmd.args(["push", target_remote, &branch])
|
||||
.current_dir(path);
|
||||
prepare_remote_git_cmd_with_remote(&mut cmd, path, Some(target_remote), credentials, db, app).await;
|
||||
prepare_remote_git_cmd_with_remote(&mut cmd, path, Some(target_remote), credentials, db, data_dir).await;
|
||||
cmd.output().await.map_err(AppCommandError::io)?
|
||||
};
|
||||
|
||||
@@ -1008,7 +1025,7 @@ pub(crate) async fn git_push_core(
|
||||
|
||||
if let Some(folder_id) = folder_id {
|
||||
crate::web::event_bridge::emit_event(
|
||||
app,
|
||||
emitter,
|
||||
"folder://git-push-succeeded",
|
||||
GitPushSucceededEvent {
|
||||
folder_id,
|
||||
@@ -1024,7 +1041,8 @@ pub(crate) async fn git_push_core(
|
||||
})
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn git_push(
|
||||
app: tauri::AppHandle,
|
||||
window: tauri::WebviewWindow,
|
||||
@@ -1037,10 +1055,14 @@ pub async fn git_push(
|
||||
.label()
|
||||
.strip_prefix("push-")
|
||||
.and_then(|value| value.parse::<i32>().ok());
|
||||
git_push_core(&app, folder_id, &path, remote.as_deref(), credentials.as_ref(), &db).await
|
||||
let data_dir = app.path().app_data_dir().map_err(|e| {
|
||||
AppCommandError::external_command("Failed to resolve app data dir", e.to_string())
|
||||
})?;
|
||||
let emitter = EventEmitter::Tauri(app.clone());
|
||||
git_push_core(&data_dir, &emitter, folder_id, &path, remote.as_deref(), credentials.as_ref(), &db).await
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn git_new_branch(
|
||||
path: String,
|
||||
branch_name: String,
|
||||
@@ -1067,7 +1089,7 @@ pub async fn git_new_branch(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn git_worktree_add(
|
||||
path: String,
|
||||
branch_name: String,
|
||||
@@ -1112,7 +1134,7 @@ pub async fn git_worktree_add(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn git_checkout(path: String, branch_name: String) -> Result<(), AppCommandError> {
|
||||
let output = crate::process::tokio_command("git")
|
||||
.args(["checkout", &branch_name])
|
||||
@@ -1127,7 +1149,7 @@ pub async fn git_checkout(path: String, branch_name: String) -> Result<(), AppCo
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn git_list_branches(path: String) -> Result<Vec<String>, AppCommandError> {
|
||||
let output = crate::process::tokio_command("git")
|
||||
.args(["branch", "--format=%(refname:short)"])
|
||||
@@ -1148,7 +1170,7 @@ pub async fn git_list_branches(path: String) -> Result<Vec<String>, AppCommandEr
|
||||
Ok(branches)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn git_stash_push(
|
||||
path: String,
|
||||
message: Option<String>,
|
||||
@@ -1177,7 +1199,7 @@ pub async fn git_stash_push(
|
||||
Ok(String::from_utf8_lossy(&output.stdout).trim().to_string())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn git_stash_pop(
|
||||
path: String,
|
||||
stash_ref: Option<String>,
|
||||
@@ -1201,7 +1223,7 @@ pub async fn git_stash_pop(
|
||||
Ok(String::from_utf8_lossy(&output.stdout).trim().to_string())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn git_stash_list(path: String) -> Result<Vec<GitStashEntry>, AppCommandError> {
|
||||
let output = crate::process::tokio_command("git")
|
||||
.args(["stash", "list", "--format=%gd||%gs||%ci"])
|
||||
@@ -1262,7 +1284,7 @@ pub async fn git_stash_list(path: String) -> Result<Vec<GitStashEntry>, AppComma
|
||||
Ok(entries)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn git_stash_apply(
|
||||
path: String,
|
||||
stash_ref: String,
|
||||
@@ -1280,7 +1302,7 @@ pub async fn git_stash_apply(
|
||||
Ok(String::from_utf8_lossy(&output.stdout).trim().to_string())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn git_stash_drop(
|
||||
path: String,
|
||||
stash_ref: String,
|
||||
@@ -1298,7 +1320,7 @@ pub async fn git_stash_drop(
|
||||
Ok(String::from_utf8_lossy(&output.stdout).trim().to_string())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn git_stash_clear(path: String) -> Result<String, AppCommandError> {
|
||||
let output = crate::process::tokio_command("git")
|
||||
.args(["stash", "clear"])
|
||||
@@ -1313,7 +1335,7 @@ pub async fn git_stash_clear(path: String) -> Result<String, AppCommandError> {
|
||||
Ok(String::from_utf8_lossy(&output.stdout).trim().to_string())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn git_stash_show(
|
||||
path: String,
|
||||
stash_ref: String,
|
||||
@@ -1345,7 +1367,7 @@ pub async fn git_stash_show(
|
||||
Ok(entries)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn git_status(
|
||||
path: String,
|
||||
show_all_untracked: Option<bool>,
|
||||
@@ -1379,7 +1401,7 @@ pub async fn git_status(
|
||||
Ok(entries)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn git_is_tracked(path: String, file: String) -> Result<bool, AppCommandError> {
|
||||
let literal_file = to_git_literal_pathspec(&file);
|
||||
let output = crate::process::tokio_command("git")
|
||||
@@ -1393,7 +1415,7 @@ pub async fn git_is_tracked(path: String, file: String) -> Result<bool, AppComma
|
||||
Ok(output.status.success())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn git_diff(path: String, file: Option<String>) -> Result<String, AppCommandError> {
|
||||
let literal_file = file.as_deref().map(to_git_literal_pathspec);
|
||||
let mut args = vec!["diff".to_string(), "HEAD".to_string()];
|
||||
@@ -1428,7 +1450,7 @@ pub async fn git_diff(path: String, file: Option<String>) -> Result<String, AppC
|
||||
Ok(String::from_utf8_lossy(&output.stdout).to_string())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn git_diff_with_branch(
|
||||
path: String,
|
||||
branch: String,
|
||||
@@ -1470,7 +1492,7 @@ pub async fn git_diff_with_branch(
|
||||
Ok(String::from_utf8_lossy(&output.stdout).to_string())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn git_show_diff(
|
||||
path: String,
|
||||
commit: String,
|
||||
@@ -1502,7 +1524,7 @@ pub async fn git_show_diff(
|
||||
Ok(String::from_utf8_lossy(&output.stdout).to_string())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn git_show_file(
|
||||
path: String,
|
||||
file: String,
|
||||
@@ -1534,7 +1556,7 @@ pub async fn git_show_file(
|
||||
}
|
||||
|
||||
pub(crate) async fn git_commit_core(
|
||||
app: &tauri::AppHandle,
|
||||
emitter: &EventEmitter,
|
||||
folder_id: Option<i32>,
|
||||
conn: &sea_orm::DatabaseConnection,
|
||||
path: &str,
|
||||
@@ -1587,7 +1609,7 @@ pub(crate) async fn git_commit_core(
|
||||
|
||||
if let Some(folder_id) = folder_id {
|
||||
crate::web::event_bridge::emit_event(
|
||||
app,
|
||||
emitter,
|
||||
"folder://git-commit-succeeded",
|
||||
GitCommitSucceededEvent {
|
||||
folder_id,
|
||||
@@ -1599,7 +1621,8 @@ pub(crate) async fn git_commit_core(
|
||||
Ok(GitCommitResult { committed_files })
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn git_commit(
|
||||
app: tauri::AppHandle,
|
||||
window: tauri::WebviewWindow,
|
||||
@@ -1612,10 +1635,11 @@ pub async fn git_commit(
|
||||
.label()
|
||||
.strip_prefix("commit-")
|
||||
.and_then(|value| value.parse::<i32>().ok());
|
||||
git_commit_core(&app, folder_id, &db.conn, &path, &message, &files).await
|
||||
let emitter = EventEmitter::Tauri(app.clone());
|
||||
git_commit_core(&emitter, folder_id, &db.conn, &path, &message, &files).await
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn git_rollback_file(path: String, file: String) -> Result<(), AppCommandError> {
|
||||
let target = file.trim();
|
||||
if target.is_empty() {
|
||||
@@ -1678,7 +1702,7 @@ pub async fn git_rollback_file(path: String, file: String) -> Result<(), AppComm
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn git_add_files(path: String, files: Vec<String>) -> Result<(), AppCommandError> {
|
||||
if files.is_empty() {
|
||||
return Ok(());
|
||||
@@ -1701,7 +1725,7 @@ pub async fn git_add_files(path: String, files: Vec<String>) -> Result<(), AppCo
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn git_list_all_branches(path: String) -> Result<GitBranchList, AppCommandError> {
|
||||
let local_fut = crate::process::tokio_command("git")
|
||||
.args(["branch", "--format=%(refname:short)"])
|
||||
@@ -1775,7 +1799,7 @@ pub async fn git_list_all_branches(path: String) -> Result<GitBranchList, AppCom
|
||||
})
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn git_list_remotes(path: String) -> Result<Vec<GitRemote>, AppCommandError> {
|
||||
let output = crate::process::tokio_command("git")
|
||||
.args(["remote", "-v"])
|
||||
@@ -1815,11 +1839,11 @@ pub(crate) async fn git_fetch_remote_core(
|
||||
name: &str,
|
||||
credentials: Option<&GitCredentials>,
|
||||
db: &AppDatabase,
|
||||
app_handle: &tauri::AppHandle,
|
||||
data_dir: &std::path::Path,
|
||||
) -> Result<String, AppCommandError> {
|
||||
let mut cmd = crate::process::tokio_command("git");
|
||||
cmd.args(["fetch", name]).current_dir(path);
|
||||
prepare_remote_git_cmd_with_remote(&mut cmd, path, Some(name), credentials, db, app_handle).await;
|
||||
prepare_remote_git_cmd_with_remote(&mut cmd, path, Some(name), credentials, db, data_dir).await;
|
||||
|
||||
let output = cmd
|
||||
.output()
|
||||
@@ -1832,7 +1856,8 @@ pub(crate) async fn git_fetch_remote_core(
|
||||
Ok(String::from_utf8_lossy(&output.stderr).trim().to_string())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn git_fetch_remote(
|
||||
path: String,
|
||||
name: String,
|
||||
@@ -1840,10 +1865,13 @@ pub async fn git_fetch_remote(
|
||||
db: tauri::State<'_, AppDatabase>,
|
||||
app_handle: tauri::AppHandle,
|
||||
) -> Result<String, AppCommandError> {
|
||||
git_fetch_remote_core(&path, &name, credentials.as_ref(), &db, &app_handle).await
|
||||
let data_dir = app_handle.path().app_data_dir().map_err(|e| {
|
||||
AppCommandError::external_command("Failed to resolve app data dir", e.to_string())
|
||||
})?;
|
||||
git_fetch_remote_core(&path, &name, credentials.as_ref(), &db, &data_dir).await
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn git_add_remote(
|
||||
path: String,
|
||||
name: String,
|
||||
@@ -1862,7 +1890,7 @@ pub async fn git_add_remote(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn git_remove_remote(path: String, name: String) -> Result<(), AppCommandError> {
|
||||
let output = crate::process::tokio_command("git")
|
||||
.args(["remote", "remove", &name])
|
||||
@@ -1877,7 +1905,7 @@ pub async fn git_remove_remote(path: String, name: String) -> Result<(), AppComm
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn git_set_remote_url(
|
||||
path: String,
|
||||
name: String,
|
||||
@@ -1896,7 +1924,7 @@ pub async fn git_set_remote_url(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn git_merge(
|
||||
path: String,
|
||||
branch_name: String,
|
||||
@@ -1946,7 +1974,7 @@ pub async fn git_merge(
|
||||
})
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn git_rebase(
|
||||
path: String,
|
||||
branch_name: String,
|
||||
@@ -1979,7 +2007,7 @@ pub async fn git_rebase(
|
||||
})
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn git_delete_branch(
|
||||
path: String,
|
||||
branch_name: String,
|
||||
@@ -1999,12 +2027,12 @@ pub async fn git_delete_branch(
|
||||
Ok(String::from_utf8_lossy(&output.stdout).trim().to_string())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn git_list_conflicts(path: String) -> Result<Vec<String>, AppCommandError> {
|
||||
detect_conflicts(&path).await
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn git_conflict_file_versions(
|
||||
path: String,
|
||||
file: String,
|
||||
@@ -2047,7 +2075,7 @@ pub async fn git_conflict_file_versions(
|
||||
})
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn git_resolve_conflict(
|
||||
path: String,
|
||||
file: String,
|
||||
@@ -2075,7 +2103,7 @@ pub async fn git_resolve_conflict(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn git_abort_operation(
|
||||
path: String,
|
||||
operation: String,
|
||||
@@ -2106,7 +2134,7 @@ pub async fn git_abort_operation(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn git_continue_operation(
|
||||
path: String,
|
||||
operation: String,
|
||||
@@ -2420,7 +2448,7 @@ impl WatchEventBatch {
|
||||
}
|
||||
}
|
||||
|
||||
fn emit(&self, app: &tauri::AppHandle, root_display: &str) {
|
||||
fn emit(&self, emitter: &EventEmitter, root_display: &str) {
|
||||
if self.is_empty() {
|
||||
return;
|
||||
}
|
||||
@@ -2445,13 +2473,13 @@ impl WatchEventBatch {
|
||||
full_reload: self.overflowed,
|
||||
};
|
||||
|
||||
crate::web::event_bridge::emit_event(app, "folder://file-tree-changed", payload);
|
||||
crate::web::event_bridge::emit_event(emitter, "folder://file-tree-changed", payload);
|
||||
}
|
||||
}
|
||||
|
||||
fn run_file_watch_event_loop(
|
||||
event_rx: mpsc::Receiver<notify::Event>,
|
||||
app: tauri::AppHandle,
|
||||
emitter: EventEmitter,
|
||||
root_display: String,
|
||||
root_canonical: PathBuf,
|
||||
) {
|
||||
@@ -2484,21 +2512,21 @@ fn run_file_watch_event_loop(
|
||||
};
|
||||
|
||||
if should_flush {
|
||||
batch.emit(&app, &root_display);
|
||||
batch.emit(&emitter, &root_display);
|
||||
batch.clear();
|
||||
batch_started_at = None;
|
||||
}
|
||||
}
|
||||
Err(mpsc::RecvTimeoutError::Timeout) => {
|
||||
if !batch.is_empty() {
|
||||
batch.emit(&app, &root_display);
|
||||
batch.emit(&emitter, &root_display);
|
||||
batch.clear();
|
||||
batch_started_at = None;
|
||||
}
|
||||
}
|
||||
Err(mpsc::RecvTimeoutError::Disconnected) => {
|
||||
if !batch.is_empty() {
|
||||
batch.emit(&app, &root_display);
|
||||
batch.emit(&emitter, &root_display);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -2543,9 +2571,8 @@ fn validate_new_name(new_name: &str) -> Result<&str, AppCommandError> {
|
||||
Ok(trimmed)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn start_file_tree_watch(
|
||||
app: tauri::AppHandle,
|
||||
pub(crate) async fn start_file_tree_watch_core(
|
||||
emitter: EventEmitter,
|
||||
root_path: String,
|
||||
) -> Result<(), AppCommandError> {
|
||||
let root = PathBuf::from(&root_path);
|
||||
@@ -2568,12 +2595,12 @@ pub async fn start_file_tree_watch(
|
||||
let root_display_for_worker = root_path.clone();
|
||||
let root_display_for_error = root_path.clone();
|
||||
let root_canonical_for_worker = root_canonical.clone();
|
||||
let app_for_worker = app.clone();
|
||||
let emitter_for_worker = emitter;
|
||||
let (event_tx, event_rx) = mpsc::channel::<notify::Event>();
|
||||
let mut worker = Some(std::thread::spawn(move || {
|
||||
run_file_watch_event_loop(
|
||||
event_rx,
|
||||
app_for_worker,
|
||||
emitter_for_worker,
|
||||
root_display_for_worker,
|
||||
root_canonical_for_worker,
|
||||
)
|
||||
@@ -2644,7 +2671,17 @@ pub async fn start_file_tree_watch(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn start_file_tree_watch(
|
||||
app: tauri::AppHandle,
|
||||
root_path: String,
|
||||
) -> Result<(), AppCommandError> {
|
||||
let emitter = EventEmitter::Tauri(app);
|
||||
start_file_tree_watch_core(emitter, root_path).await
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn stop_file_tree_watch(root_path: String) -> Result<(), AppCommandError> {
|
||||
let root = PathBuf::from(&root_path);
|
||||
let key = canonicalize_watch_root(&root)
|
||||
@@ -2894,7 +2931,7 @@ where
|
||||
})?
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn get_file_tree(
|
||||
path: String,
|
||||
max_depth: Option<usize>,
|
||||
@@ -3030,7 +3067,7 @@ pub async fn get_file_tree(
|
||||
Ok(dir_children.remove(&root).unwrap_or_default())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn read_file_base64(
|
||||
path: String,
|
||||
max_bytes: Option<usize>,
|
||||
@@ -3071,7 +3108,7 @@ pub async fn read_file_base64(
|
||||
.await
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn read_file_preview(
|
||||
root_path: String,
|
||||
path: String,
|
||||
@@ -3101,7 +3138,7 @@ pub async fn read_file_preview(
|
||||
.await
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn read_file_for_edit(
|
||||
root_path: String,
|
||||
path: String,
|
||||
@@ -3142,7 +3179,7 @@ pub async fn read_file_for_edit(
|
||||
.await
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn save_file_content(
|
||||
root_path: String,
|
||||
path: String,
|
||||
@@ -3242,7 +3279,7 @@ fn build_local_copy_file_name(original_name: &str, attempt: usize) -> String {
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn save_file_copy(
|
||||
root_path: String,
|
||||
path: String,
|
||||
@@ -3333,7 +3370,7 @@ pub async fn save_file_copy(
|
||||
.await
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn rename_file_tree_entry(
|
||||
root_path: String,
|
||||
path: String,
|
||||
@@ -3382,7 +3419,7 @@ pub async fn rename_file_tree_entry(
|
||||
Ok(rel)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn delete_file_tree_entry(
|
||||
root_path: String,
|
||||
path: String,
|
||||
@@ -3412,7 +3449,7 @@ pub async fn delete_file_tree_entry(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn create_file_tree_entry(
|
||||
root_path: String,
|
||||
path: String,
|
||||
@@ -3475,7 +3512,7 @@ pub async fn create_file_tree_entry(
|
||||
Ok(rel)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn git_log(
|
||||
path: String,
|
||||
limit: Option<u32>,
|
||||
@@ -3594,7 +3631,7 @@ pub async fn git_log(
|
||||
})
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn git_commit_branches(
|
||||
path: String,
|
||||
commit: String,
|
||||
|
||||
@@ -124,12 +124,12 @@ pub struct McpMarketplaceServerDetail {
|
||||
pub spec: Value,
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn mcp_scan_local() -> Result<Vec<LocalMcpServer>, AppCommandError> {
|
||||
scan_local_servers()
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn mcp_list_marketplaces() -> Result<Vec<McpMarketplaceProvider>, AppCommandError> {
|
||||
Ok(vec![
|
||||
McpMarketplaceProvider {
|
||||
@@ -146,7 +146,7 @@ pub async fn mcp_list_marketplaces() -> Result<Vec<McpMarketplaceProvider>, AppC
|
||||
])
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn mcp_search_marketplace(
|
||||
provider_id: String,
|
||||
query: Option<String>,
|
||||
@@ -164,7 +164,7 @@ pub async fn mcp_search_marketplace(
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn mcp_get_marketplace_server_detail(
|
||||
provider_id: String,
|
||||
server_id: String,
|
||||
@@ -286,7 +286,7 @@ pub async fn mcp_get_marketplace_server_detail(
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn mcp_install_from_marketplace(
|
||||
provider_id: String,
|
||||
server_id: String,
|
||||
@@ -334,7 +334,7 @@ pub async fn mcp_install_from_marketplace(
|
||||
})
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn mcp_upsert_local_server(
|
||||
server_id: String,
|
||||
spec: Value,
|
||||
@@ -368,7 +368,7 @@ pub async fn mcp_upsert_local_server(
|
||||
})
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn mcp_set_server_apps(
|
||||
server_id: String,
|
||||
apps: Vec<McpAppType>,
|
||||
@@ -391,7 +391,7 @@ pub async fn mcp_set_server_apps(
|
||||
find_local_server(&server_id)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn mcp_remove_server(
|
||||
server_id: String,
|
||||
apps: Option<Vec<McpAppType>>,
|
||||
|
||||
@@ -7,5 +7,7 @@ pub mod project_boot;
|
||||
pub mod system_settings;
|
||||
pub mod terminal;
|
||||
pub mod version_control;
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
pub mod notification;
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
pub mod windows;
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
use tauri::AppHandle;
|
||||
|
||||
use crate::app_error::AppCommandError;
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn send_notification(
|
||||
#[allow(unused_variables)] app: AppHandle,
|
||||
title: String,
|
||||
|
||||
@@ -46,7 +46,7 @@ async fn detect_one(name: &str) -> PackageManagerInfo {
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn detect_package_manager(name: String) -> PackageManagerInfo {
|
||||
detect_one(&name).await
|
||||
}
|
||||
@@ -55,7 +55,7 @@ pub async fn detect_package_manager(name: String) -> PackageManagerInfo {
|
||||
// Project creation
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn create_shadcn_project(
|
||||
project_name: String,
|
||||
template: String,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use sea_orm::DatabaseConnection;
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
use tauri::State;
|
||||
|
||||
use crate::app_error::AppCommandError;
|
||||
@@ -82,14 +83,16 @@ pub(crate) async fn load_system_language_settings(
|
||||
})
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn get_system_proxy_settings(
|
||||
db: State<'_, AppDatabase>,
|
||||
) -> Result<SystemProxySettings, AppCommandError> {
|
||||
load_system_proxy_settings(&db.conn).await
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn update_system_proxy_settings(
|
||||
settings: SystemProxySettings,
|
||||
db: State<'_, AppDatabase>,
|
||||
@@ -108,14 +111,16 @@ pub async fn update_system_proxy_settings(
|
||||
Ok(normalized)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn get_system_language_settings(
|
||||
db: State<'_, AppDatabase>,
|
||||
) -> Result<SystemLanguageSettings, AppCommandError> {
|
||||
load_system_language_settings(&db.conn).await
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn update_system_language_settings(
|
||||
settings: SystemLanguageSettings,
|
||||
db: State<'_, AppDatabase>,
|
||||
@@ -130,7 +135,8 @@ pub async fn update_system_language_settings(
|
||||
.await
|
||||
.map_err(AppCommandError::from)?;
|
||||
|
||||
crate::web::event_bridge::emit_event(&app, LANGUAGE_SETTINGS_UPDATED_EVENT, settings.clone());
|
||||
let emitter = crate::web::event_bridge::EventEmitter::Tauri(app);
|
||||
crate::web::event_bridge::emit_event(&emitter, LANGUAGE_SETTINGS_UPDATED_EVENT, settings.clone());
|
||||
|
||||
Ok(settings)
|
||||
}
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
use tauri::Manager;
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
use tauri::State;
|
||||
|
||||
use crate::git_credential;
|
||||
use crate::terminal::error::TerminalError;
|
||||
use crate::terminal::manager::{SpawnOptions, TerminalManager};
|
||||
use crate::terminal::types::TerminalInfo;
|
||||
use crate::web::event_bridge::EventEmitter;
|
||||
|
||||
/// Build extra env vars for the terminal session.
|
||||
///
|
||||
@@ -57,7 +60,8 @@ pub(crate) fn prepare_credential_env(
|
||||
Some(env)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn terminal_spawn(
|
||||
working_dir: String,
|
||||
initial_command: Option<String>,
|
||||
@@ -83,11 +87,12 @@ pub async fn terminal_spawn(
|
||||
extra_env,
|
||||
temp_files: vec![],
|
||||
},
|
||||
app_handle,
|
||||
EventEmitter::Tauri(app_handle),
|
||||
)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub fn terminal_write(
|
||||
terminal_id: String,
|
||||
data: String,
|
||||
@@ -96,7 +101,8 @@ pub fn terminal_write(
|
||||
manager.write(&terminal_id, data.as_bytes())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub fn terminal_resize(
|
||||
terminal_id: String,
|
||||
cols: u16,
|
||||
@@ -106,7 +112,8 @@ pub fn terminal_resize(
|
||||
manager.resize(&terminal_id, cols, rows)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub fn terminal_kill(
|
||||
terminal_id: String,
|
||||
manager: State<'_, TerminalManager>,
|
||||
@@ -114,10 +121,12 @@ pub fn terminal_kill(
|
||||
manager.kill(&terminal_id)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub fn terminal_list(
|
||||
manager: State<'_, TerminalManager>,
|
||||
app_handle: tauri::AppHandle,
|
||||
) -> Result<Vec<TerminalInfo>, TerminalError> {
|
||||
Ok(manager.list_with_exit_check(Some(&app_handle)))
|
||||
let emitter = EventEmitter::Tauri(app_handle);
|
||||
Ok(manager.list_with_exit_check(Some(&emitter)))
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use serde::Deserialize;
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
use tauri::State;
|
||||
|
||||
use crate::app_error::AppCommandError;
|
||||
@@ -102,14 +103,15 @@ pub(crate) async fn detect_git_core(
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn detect_git(
|
||||
db: State<'_, AppDatabase>,
|
||||
) -> Result<GitDetectResult, AppCommandError> {
|
||||
detect_git_core(&db.conn).await
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn test_git_path(path: String) -> Result<GitDetectResult, AppCommandError> {
|
||||
let trimmed = path.trim();
|
||||
if trimmed.is_empty() {
|
||||
@@ -138,14 +140,16 @@ async fn load_git_settings(
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn get_git_settings(
|
||||
db: State<'_, AppDatabase>,
|
||||
) -> Result<GitSettings, AppCommandError> {
|
||||
load_git_settings(&db.conn).await
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn update_git_settings(
|
||||
settings: GitSettings,
|
||||
db: State<'_, AppDatabase>,
|
||||
@@ -182,14 +186,16 @@ async fn load_github_accounts(
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn get_github_accounts(
|
||||
db: State<'_, AppDatabase>,
|
||||
) -> Result<GitHubAccountsSettings, AppCommandError> {
|
||||
load_github_accounts(&db.conn).await
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn update_github_accounts(
|
||||
settings: GitHubAccountsSettings,
|
||||
db: State<'_, AppDatabase>,
|
||||
@@ -210,7 +216,7 @@ pub async fn update_github_accounts(
|
||||
// Keyring token management
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn save_account_token(
|
||||
account_id: String,
|
||||
token: String,
|
||||
@@ -219,14 +225,14 @@ pub async fn save_account_token(
|
||||
.map_err(|e| AppCommandError::io_error("Failed to save token to keyring").with_detail(e))
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn get_account_token(
|
||||
account_id: String,
|
||||
) -> Result<Option<String>, AppCommandError> {
|
||||
Ok(crate::keyring_store::get_token(&account_id))
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn delete_account_token(
|
||||
account_id: String,
|
||||
) -> Result<(), AppCommandError> {
|
||||
@@ -244,7 +250,7 @@ struct GitHubUserResponse {
|
||||
avatar_url: Option<String>,
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn validate_github_token(
|
||||
server_url: String,
|
||||
token: String,
|
||||
|
||||
@@ -137,7 +137,8 @@ fn resolve_settings_target(section: Option<&str>, agent_type: Option<&str>) -> S
|
||||
route.to_string()
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn list_open_folders(
|
||||
app: AppHandle,
|
||||
db: tauri::State<'_, AppDatabase>,
|
||||
@@ -165,7 +166,8 @@ pub async fn list_open_folders(
|
||||
Ok(open_folders)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn focus_folder_window(app: AppHandle, folder_id: i32) -> Result<(), AppCommandError> {
|
||||
let windows = app.webview_windows();
|
||||
for (label, window) in &windows {
|
||||
@@ -186,7 +188,8 @@ pub async fn focus_folder_window(app: AppHandle, folder_id: i32) -> Result<(), A
|
||||
)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn open_folder_window(
|
||||
app: AppHandle,
|
||||
db: tauri::State<'_, AppDatabase>,
|
||||
@@ -233,7 +236,8 @@ pub async fn open_folder_window(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn open_commit_window(
|
||||
app: AppHandle,
|
||||
window: tauri::WebviewWindow,
|
||||
@@ -294,7 +298,8 @@ pub async fn open_commit_window(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn open_settings_window(
|
||||
app: AppHandle,
|
||||
window: tauri::WebviewWindow,
|
||||
@@ -387,7 +392,8 @@ impl MergeWindowState {
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn open_merge_window(
|
||||
app: AppHandle,
|
||||
window: tauri::WebviewWindow,
|
||||
@@ -505,8 +511,9 @@ pub async fn cleanup_dangling_merge(app: &AppHandle, merge_window_label: &str) {
|
||||
.output()
|
||||
.await;
|
||||
|
||||
let emitter = crate::web::event_bridge::EventEmitter::Tauri(app.clone());
|
||||
crate::web::event_bridge::emit_event(
|
||||
app,
|
||||
&emitter,
|
||||
"folder://merge-aborted",
|
||||
serde_json::json!({ "folder_id": folder_id }),
|
||||
);
|
||||
@@ -531,7 +538,8 @@ pub fn open_welcome_window(app: &AppHandle) -> Result<(), AppCommandError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn open_stash_window(
|
||||
app: AppHandle,
|
||||
db: tauri::State<'_, AppDatabase>,
|
||||
@@ -570,7 +578,8 @@ pub async fn open_stash_window(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn open_push_window(
|
||||
app: AppHandle,
|
||||
db: tauri::State<'_, AppDatabase>,
|
||||
@@ -609,7 +618,8 @@ pub async fn open_push_window(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(feature = "tauri-runtime")]
|
||||
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
|
||||
pub async fn open_project_boot_window(
|
||||
app: AppHandle,
|
||||
source: Option<String>,
|
||||
|
||||
Reference in New Issue
Block a user