diff --git a/crates/goose-cli/src/cli.rs b/crates/goose-cli/src/cli.rs index c642e48dbf7..34d4ec2b3bf 100644 --- a/crates/goose-cli/src/cli.rs +++ b/crates/goose-cli/src/cli.rs @@ -9,7 +9,7 @@ use crate::commands::configure::handle_configure; use crate::commands::info::handle_info; use crate::commands::project::{handle_project_default, handle_projects_interactive}; use crate::commands::recipe::{handle_deeplink, handle_list, handle_open, handle_validate}; -// Import the new handlers from commands::schedule + use crate::commands::schedule::{ handle_schedule_add, handle_schedule_cron_help, handle_schedule_list, handle_schedule_remove, handle_schedule_run_now, handle_schedule_services_status, handle_schedule_services_stop, diff --git a/crates/goose-cli/src/commands/info.rs b/crates/goose-cli/src/commands/info.rs index de3b8383146..56c9d295b08 100644 --- a/crates/goose-cli/src/commands/info.rs +++ b/crates/goose-cli/src/commands/info.rs @@ -2,43 +2,73 @@ use anyhow::Result; use console::style; use goose::config::paths::Paths; use goose::config::Config; +use goose::session::session_manager::{DB_NAME, SESSIONS_FOLDER}; use serde_yaml; fn print_aligned(label: &str, value: &str, width: usize) { println!(" {: String { + if path.exists() { + "".to_string() + } else { + let mut current = path.parent(); + while let Some(parent) = current { + if parent.exists() { + return match fs::metadata(parent).map(|m| !m.permissions().readonly()) { + Ok(true) => style("missing (can create)").dim().to_string(), + Ok(false) => style("missing (read-only parent)").red().to_string(), + Err(_) => style("missing (cannot check)").red().to_string(), + }; + } + current = parent.parent(); + } + style("missing (no writable parent)").red().to_string() + } +} + pub fn handle_info(verbose: bool) -> Result<()> { let logs_dir = Paths::in_state_dir("logs"); - let sessions_dir = Paths::in_data_dir("sessions"); - let sessions_db = sessions_dir.join("sessions.db"); - - // Get paths using a stored reference to the global config + let sessions_dir = Paths::in_data_dir(SESSIONS_FOLDER); + let sessions_db = sessions_dir.join(DB_NAME); let config = Config::global(); - let config_dir = Paths::config_dir().display().to_string(); + let config_dir = Paths::config_dir(); + let config_yaml_file = config_dir.join(CONFIG_YAML_NAME); - // Define the labels and their corresponding path values once. let paths = [ - ("Config dir:", config_dir), - ("Sessions DB (sqlite):", sessions_db.display().to_string()), - ("Logs dir:", logs_dir.display().to_string()), + ("Config dir:", &config_dir), + ("Config yaml:", &config_yaml_file), + ("Sessions DB (sqlite):", &sessions_db), + ("Logs dir:", &logs_dir), ]; - // Calculate padding: use the max length of the label plus extra space. - let basic_padding = paths.iter().map(|(l, _)| l.len()).max().unwrap_or(0) + 4; + let label_padding = paths.iter().map(|(l, _)| l.len()).max().unwrap_or(0) + 4; + let path_padding = paths + .iter() + .map(|(_, p)| p.display().to_string().len()) + .max() + .unwrap_or(0) + + 4; - // Print version information println!("{}", style("goose Version:").cyan().bold()); - print_aligned("Version:", env!("CARGO_PKG_VERSION"), basic_padding); + print_aligned("Version:", env!("CARGO_PKG_VERSION"), label_padding); println!(); - // Print location information - println!("{}", style("goose Locations:").cyan().bold()); + println!("{}", style("Paths:").cyan().bold()); for (label, path) in &paths { - print_aligned(label, path, basic_padding); + println!( + "{: Result<()> { if let Err(e) = goose_cli::logging::setup_logging(None, None) { - eprintln!("Warning: Failed to initialize telemetry: {}", e); + eprintln!("Warning: Failed to initialize logging: {}", e); } let result = cli().await; diff --git a/crates/goose-server/src/commands/agent.rs b/crates/goose-server/src/commands/agent.rs index a1eb422d970..901667855a4 100644 --- a/crates/goose-server/src/commands/agent.rs +++ b/crates/goose-server/src/commands/agent.rs @@ -28,13 +28,10 @@ async fn shutdown_signal() { } pub async fn run() -> Result<()> { - // Initialize logging and telemetry crate::logging::setup_logging(Some("goosed"))?; let settings = configuration::Settings::new()?; - // Initialize pricing cache on startup - tracing::info!("Initializing pricing cache..."); if let Err(e) = initialize_pricing_cache().await { tracing::warn!( "Failed to initialize pricing cache: {}. Pricing data may not be available.", @@ -61,7 +58,7 @@ pub async fn run() -> Result<()> { let listener = tokio::net::TcpListener::bind(settings.socket_addr()).await?; info!("listening on {}", listener.local_addr()?); - // Ensure the listener/socket is properly closed on cancellation by using graceful shutdown + axum::serve(listener, app) .with_graceful_shutdown(shutdown_signal()) .await?; diff --git a/crates/goose-server/src/logging.rs b/crates/goose-server/src/logging.rs index 0a5eadc20cf..72c2b50d84b 100644 --- a/crates/goose-server/src/logging.rs +++ b/crates/goose-server/src/logging.rs @@ -1,4 +1,4 @@ -use anyhow::{Context, Result}; +use anyhow::Result; use tracing_appender::rolling::Rotation; use tracing_subscriber::{ filter::LevelFilter, fmt, layer::SubscriberExt, util::SubscriberInitExt, EnvFilter, Layer, @@ -20,11 +20,8 @@ pub fn setup_logging(name: Option<&str>) -> Result<()> { } else { format!("{}.log", timestamp) }; - let file_appender = tracing_appender::rolling::RollingFileAppender::new( - Rotation::NEVER, // we do manual rotation via file naming and cleanup_old_logs - log_dir, - log_filename, - ); + let file_appender = + tracing_appender::rolling::RollingFileAppender::new(Rotation::NEVER, log_dir, log_filename); // Create JSON file logging layer let file_layer = fmt::layer() @@ -34,35 +31,27 @@ pub fn setup_logging(name: Option<&str>) -> Result<()> { .with_ansi(false) .with_file(true); - // Create console logging layer for development - INFO and above only + let base_env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| { + EnvFilter::new("") + .add_directive("mcp_client=info".parse().unwrap()) + .add_directive("goose=debug".parse().unwrap()) + .add_directive("goose_server=info".parse().unwrap()) + .add_directive("tower_http=info".parse().unwrap()) + .add_directive(LevelFilter::WARN.into()) + }); + let console_layer = fmt::layer() .with_writer(std::io::stderr) .with_target(true) .with_level(true) - .with_ansi(true) .with_file(true) + .with_ansi(false) .with_line_number(true) .pretty(); - // Base filter for all logging - let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| { - // Set default levels for different modules - EnvFilter::new("") - // Set mcp-client to DEBUG - .add_directive("mcp_client=debug".parse().unwrap()) - // Set goose module to DEBUG - .add_directive("goose=debug".parse().unwrap()) - // Set goose-server to INFO - .add_directive("goose_server=info".parse().unwrap()) - // Set tower-http to INFO for request logging - .add_directive("tower_http=info".parse().unwrap()) - // Set everything else to WARN - .add_directive(LevelFilter::WARN.into()) - }); - let mut layers = vec![ - file_layer.with_filter(env_filter).boxed(), - console_layer.with_filter(LevelFilter::INFO).boxed(), + file_layer.with_filter(base_env_filter.clone()).boxed(), + console_layer.with_filter(base_env_filter).boxed(), ]; if let Ok((otlp_tracing_layer, otlp_metrics_layer, otlp_logs_layer)) = otlp_layer::init_otlp() { @@ -89,9 +78,7 @@ pub fn setup_logging(name: Option<&str>) -> Result<()> { let subscriber = Registry::default().with(layers); - subscriber - .try_init() - .context("Failed to set global subscriber")?; + subscriber.try_init()?; Ok(()) } diff --git a/crates/goose/src/config/base.rs b/crates/goose/src/config/base.rs index a7938900f01..0f6c14d0758 100644 --- a/crates/goose/src/config/base.rs +++ b/crates/goose/src/config/base.rs @@ -17,6 +17,7 @@ use thiserror::Error; const KEYRING_SERVICE: &str = "goose"; const KEYRING_USERNAME: &str = "secrets"; +pub const CONFIG_YAML_NAME: &str = "config.yaml"; #[cfg(test)] const TEST_KEYRING_SERVICE: &str = "goose-test"; @@ -119,9 +120,7 @@ impl Default for Config { fn default() -> Self { let config_dir = Paths::config_dir(); - std::fs::create_dir_all(&config_dir).expect("Failed to create config directory"); - - let config_path = config_dir.join("config.yaml"); + let config_path = config_dir.join(CONFIG_YAML_NAME); let secrets = match env::var("GOOSE_DISABLE_KEYRING") { Ok(_) => SecretStorage::File { @@ -433,7 +432,6 @@ impl Config { // Convert to YAML for storage let yaml_value = serde_yaml::to_string(&values)?; - // Ensure the directory exists if let Some(parent) = self.config_path.parent() { std::fs::create_dir_all(parent) .map_err(|e| ConfigError::DirectoryError(e.to_string()))?; diff --git a/crates/goose/src/logging.rs b/crates/goose/src/logging.rs index 80b96a935d8..380c5dd3952 100644 --- a/crates/goose/src/logging.rs +++ b/crates/goose/src/logging.rs @@ -24,7 +24,8 @@ pub fn prepare_log_directory(component: &str, use_date_subdir: bool) -> Result

Result<()> { // Try loading from disk first if let Ok(Some(cached)) = self.load_from_disk().await { - // Log how many models we have cached - let total_models: usize = cached.pricing.values().map(|models| models.len()).sum(); - tracing::debug!( - "Loaded {} providers with {} total models from disk cache", - cached.pricing.len(), - total_models - ); - - // Update memory cache { let mut cache = self.memory_cache.write().await; *cache = Some(cached); @@ -196,8 +186,6 @@ impl PricingCache { return Ok(()); } - // If no disk cache, fetch from OpenRouter - tracing::info!("Fetching pricing data from OpenRouter API"); self.refresh().await } } @@ -213,14 +201,13 @@ lazy_static::lazy_static! { static ref PRICING_CACHE: PricingCache = PricingCache::new(); } -/// Create a properly configured HTTP client for the current runtime -fn create_http_client() -> Client { +fn create_http_client() -> Result { Client::builder() .timeout(Duration::from_secs(30)) .pool_idle_timeout(Duration::from_secs(90)) .pool_max_idle_per_host(10) .build() - .expect("Failed to create HTTP client") + .map_err(|e| anyhow!(e)) } /// OpenRouter model pricing information @@ -254,7 +241,7 @@ pub struct OpenRouterModelsResponse { /// Internal function to fetch pricing data async fn fetch_openrouter_pricing_internal() -> Result> { - let client = create_http_client(); + let client = create_http_client()?; let response = client .get("https://openrouter.ai/api/v1/models") .send() diff --git a/crates/goose/src/scheduler.rs b/crates/goose/src/scheduler.rs index f3cc9a77504..045922074a8 100644 --- a/crates/goose/src/scheduler.rs +++ b/crates/goose/src/scheduler.rs @@ -190,13 +190,6 @@ impl Scheduler { let local_tz = Local::now().timezone(); - tracing::info!( - "Creating cron task for job '{}' cron: '{}' in timezone: {:?}", - job.id, - cron, - local_tz - ); - Job::new_async_tz(&cron, local_tz, move |_uuid, _l| { tracing::info!("Cron task triggered for job '{}'", job_for_task.id); let task_job_id = job_for_task.id.clone(); @@ -215,7 +208,6 @@ impl Scheduler { }; if !should_execute { - tracing::info!("Skipping paused job '{}'", task_job_id); return; } @@ -731,15 +723,11 @@ async fn execute_job( } } - if let Err(e) = SessionManager::update_session(&session.id) + SessionManager::update_session(&session.id) .schedule_id(Some(job.id.clone())) .recipe(Some(recipe)) .apply() - .await - { - tracing::error!("Failed to update session: {}", e); - } - + .await?; Ok(session.id) } diff --git a/crates/goose/src/session/session_manager.rs b/crates/goose/src/session/session_manager.rs index 2f960cd8497..8dfc81e232c 100644 --- a/crates/goose/src/session/session_manager.rs +++ b/crates/goose/src/session/session_manager.rs @@ -19,6 +19,8 @@ use tracing::{info, warn}; use utoipa::ToSchema; const CURRENT_SCHEMA_VERSION: i32 = 5; +pub const SESSIONS_FOLDER: &str = "sessions"; +pub const DB_NAME: &str = "sessions.db"; #[derive(Debug, Clone, Copy, Serialize, Deserialize, ToSchema, PartialEq, Eq)] #[serde(rename_all = "snake_case")] @@ -335,7 +337,7 @@ pub struct SessionStorage { } pub fn ensure_session_dir() -> Result { - let session_dir = Paths::data_dir().join("sessions"); + let session_dir = Paths::data_dir().join(SESSIONS_FOLDER); if !session_dir.exists() { fs::create_dir_all(&session_dir)?; @@ -439,7 +441,7 @@ impl sqlx::FromRow<'_, sqlx::sqlite::SqliteRow> for Session { impl SessionStorage { async fn new() -> Result { let session_dir = ensure_session_dir()?; - let db_path = session_dir.join("sessions.db"); + let db_path = session_dir.join(DB_NAME); let storage = if db_path.exists() { Self::open(&db_path).await? diff --git a/crates/goose/src/tracing/otlp_layer.rs b/crates/goose/src/tracing/otlp_layer.rs index b8edd745e12..5a357634d7f 100644 --- a/crates/goose/src/tracing/otlp_layer.rs +++ b/crates/goose/src/tracing/otlp_layer.rs @@ -34,7 +34,6 @@ impl Default for OtlpConfig { impl OtlpConfig { pub fn from_config() -> Option { - // Try to get from goose config system (which checks env vars first, then config file) let config = crate::config::Config::global(); // Try to get the endpoint from config (checks OTEL_EXPORTER_OTLP_ENDPOINT env var first) diff --git a/ui/desktop/src/components/settings/chat/ChatSettingsSection.tsx b/ui/desktop/src/components/settings/chat/ChatSettingsSection.tsx index 68ead2dc269..fbdc4e5edc3 100644 --- a/ui/desktop/src/components/settings/chat/ChatSettingsSection.tsx +++ b/ui/desktop/src/components/settings/chat/ChatSettingsSection.tsx @@ -1,6 +1,5 @@ import { ModeSection } from '../mode/ModeSection'; import { ToolSelectionStrategySection } from '../tool_selection_strategy/ToolSelectionStrategySection'; -import SchedulerSection from '../scheduler/SchedulerSection'; import DictationSection from '../dictation/DictationSection'; import { SecurityToggle } from '../security/SecurityToggle'; import { ResponseStylesSection } from '../response_styles/ResponseStylesSection'; @@ -48,9 +47,6 @@ export default function ChatSettingsSection() { Choose which scheduling backend to use for scheduled recipes and tasks - - - diff --git a/ui/desktop/src/components/settings/scheduler/SchedulerSection.tsx b/ui/desktop/src/components/settings/scheduler/SchedulerSection.tsx deleted file mode 100644 index 64995da6d8b..00000000000 --- a/ui/desktop/src/components/settings/scheduler/SchedulerSection.tsx +++ /dev/null @@ -1,113 +0,0 @@ -import { useState, useEffect } from 'react'; -import { SchedulingEngine, Settings } from '../../../utils/settings'; - -interface SchedulingEngineOption { - key: SchedulingEngine; - label: string; - description: string; -} - -const schedulingEngineOptions: SchedulingEngineOption[] = [ - { - key: 'builtin-cron', - label: 'Built-in Cron (Default)', - description: - "Uses Goose's built-in cron scheduler. Simple and reliable for basic scheduling needs.", - }, - { - key: 'temporal', - label: 'Temporal', - description: - 'Uses Temporal workflow engine for advanced scheduling features. Requires Temporal CLI to be installed.', - }, -]; - -interface SchedulerSectionProps { - onSchedulingEngineChange?: (engine: SchedulingEngine) => void; -} - -export default function SchedulerSection({ onSchedulingEngineChange }: SchedulerSectionProps) { - const [schedulingEngine, setSchedulingEngine] = useState('builtin-cron'); - - useEffect(() => { - const loadSchedulingEngine = async () => { - try { - const settings = (await window.electron.getSettings()) as Settings | null; - if (settings?.schedulingEngine) { - setSchedulingEngine(settings.schedulingEngine); - } - } catch (error) { - console.error('Failed to load scheduling engine setting:', error); - } - }; - - loadSchedulingEngine(); - }, []); - - const handleEngineChange = async (engine: SchedulingEngine) => { - try { - setSchedulingEngine(engine); - - await window.electron.setSchedulingEngine(engine); - - if (onSchedulingEngineChange) { - onSchedulingEngineChange(engine); - } - } catch (error) { - console.error('Failed to save scheduling engine setting:', error); - } - }; - - return ( -

- {schedulingEngineOptions.map((option) => { - const isChecked = schedulingEngine === option.key; - - return ( -
-
handleEngineChange(option.key)} - > -
-
-

{option.label}

-

{option.description}

-
-
- -
- handleEngineChange(option.key)} - className="peer sr-only" - /> -
-
-
-
- ); - })} - -
-

- Note: Changing the scheduling engine will apply to new Goose sessions. - You will need to restart Goose for the change to take full effect.
- The scheduling engines do not share the list of schedules. -

-
-
- ); -} diff --git a/ui/desktop/src/goosed.ts b/ui/desktop/src/goosed.ts index e8887ac55fc..e6459cc68aa 100644 --- a/ui/desktop/src/goosed.ts +++ b/ui/desktop/src/goosed.ts @@ -2,7 +2,6 @@ import { spawn, ChildProcess } from 'child_process'; import { createServer } from 'net'; import os from 'node:os'; import path from 'node:path'; -import fs from 'node:fs'; import { getBinaryPath } from './utils/pathUtils'; import log from './utils/logger'; import { App } from 'electron'; @@ -11,7 +10,6 @@ import { Buffer } from 'node:buffer'; import { status } from './api'; import { Client } from './api/client'; -// Find an available port to start goosed on export const findAvailablePort = (): Promise => { return new Promise((resolve, _reject) => { const server = createServer(); @@ -27,11 +25,20 @@ export const findAvailablePort = (): Promise => { }; // Check if goosed server is ready by polling the status endpoint -export const checkServerStatus = async (client: Client): Promise => { +export const checkServerStatus = async (client: Client, errorLog: string[]): Promise => { const interval = 100; // ms - const maxAttempts = 1200; // 120s + const maxAttempts = 30; // 3s + + const fatal = (line: string) => { + const trimmed = line.trim().toLowerCase(); + return trimmed.startsWith("thread 'main' panicked at") || trimmed.startsWith('error:'); + }; for (let attempt = 1; attempt <= maxAttempts; attempt++) { + if (errorLog.some(fatal)) { + log.error('Detected fatal error in server logs'); + return false; + } try { await status({ client, throwOnError: true }); return true; @@ -48,7 +55,7 @@ export const checkServerStatus = async (client: Client): Promise => { const connectToExternalBackend = async ( workingDir: string, port: number = 3000 -): Promise<[number, string, ChildProcess]> => { +): Promise<[number, string, ChildProcess, string[]]> => { log.info(`Using external goosed backend on port ${port}`); const mockProcess = { @@ -58,7 +65,7 @@ const connectToExternalBackend = async ( }, } as ChildProcess; - return [port, workingDir, mockProcess]; + return [port, workingDir, mockProcess, []]; }; interface GooseProcessEnv { @@ -76,39 +83,23 @@ interface GooseProcessEnv { export const startGoosed = async ( app: App, serverSecret: string, - dir: string | null = null, + dir: string, env: Partial = {} -): Promise<[number, string, ChildProcess]> => { - const homeDir = os.homedir(); +): Promise<[number, string, ChildProcess, string[]]> => { const isWindows = process.platform === 'win32'; - - if (!dir) { - dir = homeDir; - } - + const homeDir = os.homedir(); dir = path.resolve(path.normalize(dir)); if (process.env.GOOSE_EXTERNAL_BACKEND) { return connectToExternalBackend(dir, 3000); } - try { - const stats = fs.lstatSync(dir); - - if (!stats.isDirectory()) { - log.warn(`Provided path is not a directory, falling back to home directory`); - dir = homeDir; - } - } catch { - log.warn(`Directory does not exist, falling back to home directory`); - dir = homeDir; - } - let goosedPath = getBinaryPath(app, 'goosed'); const resolvedGoosedPath = path.resolve(goosedPath); const port = await findAvailablePort(); + const stderrLines: string[] = []; log.info(`Starting goosed from: ${resolvedGoosedPath} on port ${port} in dir ${dir}`); @@ -183,7 +174,14 @@ export const startGoosed = async ( }); goosedProcess.stderr?.on('data', (data: Buffer) => { - log.error(`goosed stderr for port ${port} and dir ${dir}: ${data.toString()}`); + const lines = data + .toString() + .split('\n') + .filter((l) => l.trim()); + lines.forEach((line) => { + log.error(`goosed stderr for port ${port} and dir ${dir}: ${line}`); + stderrLines.push(line); + }); }); goosedProcess.on('close', (code: number | null) => { @@ -215,5 +213,5 @@ export const startGoosed = async ( }); log.info(`Goosed server successfully started on port ${port}`); - return [port, dir, goosedProcess]; + return [port, dir, goosedProcess, stderrLines]; }; diff --git a/ui/desktop/src/main.ts b/ui/desktop/src/main.ts index 9431af3fde5..bf9456bede8 100644 --- a/ui/desktop/src/main.ts +++ b/ui/desktop/src/main.ts @@ -33,9 +33,7 @@ import { EnvToggles, loadSettings, saveSettings, - SchedulingEngine, updateEnvironmentVariables, - updateSchedulingEngineEnvironment, } from './utils/settings'; import * as crypto from 'crypto'; // import electron from "electron"; @@ -502,38 +500,20 @@ const createChat = async ( scheduledJobId?: string, // Scheduled job ID if applicable recipeId?: string ) => { - // Initialize variables for process and configuration - let port = 0; - let workingDir = ''; - let goosedProcess: import('child_process').ChildProcess | null = null; + updateEnvironmentVariables(envToggles); - { - // Apply current environment settings before creating chat - updateEnvironmentVariables(envToggles); - - // Apply scheduling engine setting - const settings = loadSettings(); - updateSchedulingEngineEnvironment(settings.schedulingEngine); - - const envVars = { - GOOSE_SCHEDULER_TYPE: process.env.GOOSE_SCHEDULER_TYPE, - GOOSE_PATH_ROOT: process.env.GOOSE_PATH_ROOT, - }; - const [newPort, newWorkingDir, newGoosedProcess] = await startGoosed( - app, - SERVER_SECRET, - dir, - envVars - ); - port = newPort; - workingDir = newWorkingDir; - goosedProcess = newGoosedProcess; - } + const envVars = { + GOOSE_PATH_ROOT: process.env.GOOSE_PATH_ROOT, + }; + const [port, workingDir, goosedProcess, errorLog] = await startGoosed( + app, + SERVER_SECRET, + dir || os.homedir(), + envVars + ); - // Create window config with loading state for recipe deeplinks - // Load and manage window state const mainWindowState = windowStateKeeper({ - defaultWidth: 940, // large enough to show the sidebar on launch + defaultWidth: 940, defaultHeight: 800, }); @@ -594,23 +574,21 @@ const createChat = async ( ); goosedClients.set(mainWindow.id, goosedClient); - console.log('[Main] Waiting for backend server to be ready...'); - const serverReady = await checkServerStatus(goosedClient); + const serverReady = await checkServerStatus(goosedClient, errorLog); if (!serverReady) { - throw new Error('Backend server failed to start in time'); + dialog.showMessageBoxSync({ + type: 'error', + title: 'Goose Failed to Start', + message: 'The backend server failed to start.', + detail: errorLog.join('\n'), + buttons: ['OK'], + }); + app.quit(); } // Let windowStateKeeper manage the window mainWindowState.manage(mainWindow); - // Enable spellcheck / right and ctrl + click on mispelled word - // - // NOTE: We could use webContents.session.availableSpellCheckerLanguages to include - // all languages in the list of spell checked words, but it diminishes the times you - // get red squigglies back for mispelled english words. Given the rest of Goose only - // renders in english right now, this feels like the correct set of language codes - // for the moment. - // mainWindow.webContents.session.setSpellCheckerLanguages(['en-US', 'en-GB']); mainWindow.webContents.on('context-menu', (_event, params) => { const menu = new Menu(); @@ -1167,22 +1145,6 @@ ipcMain.handle('get-goosed-host-port', async (event) => { return client.getConfig().baseUrl || null; }); -ipcMain.handle('set-scheduling-engine', async (_event, engine: string) => { - try { - const settings = loadSettings(); - settings.schedulingEngine = engine as SchedulingEngine; - saveSettings(settings); - - // Update the environment variable immediately - updateSchedulingEngineEnvironment(settings.schedulingEngine); - - return true; - } catch (error) { - console.error('Error setting scheduling engine:', error); - return false; - } -}); - // Handle menu bar icon visibility ipcMain.handle('set-menu-bar-icon', async (_event, show: boolean) => { try { diff --git a/ui/desktop/src/preload.ts b/ui/desktop/src/preload.ts index 654c558412f..070e8a0afeb 100644 --- a/ui/desktop/src/preload.ts +++ b/ui/desktop/src/preload.ts @@ -80,7 +80,6 @@ type ElectronAPI = { getSettings: () => Promise; getSecretKey: () => Promise; getGoosedHostPort: () => Promise; - setSchedulingEngine: (engine: string) => Promise; setWakelock: (enable: boolean) => Promise; getWakelockState: () => Promise; openNotificationsSettings: () => Promise; @@ -186,7 +185,6 @@ const electronAPI: ElectronAPI = { getSettings: () => ipcRenderer.invoke('get-settings'), getSecretKey: () => ipcRenderer.invoke('get-secret-key'), getGoosedHostPort: () => ipcRenderer.invoke('get-goosed-host-port'), - setSchedulingEngine: (engine: string) => ipcRenderer.invoke('set-scheduling-engine', engine), setWakelock: (enable: boolean) => ipcRenderer.invoke('set-wakelock', enable), getWakelockState: () => ipcRenderer.invoke('get-wakelock-state'), openNotificationsSettings: () => ipcRenderer.invoke('open-notifications-settings'), diff --git a/ui/desktop/src/utils/settings.ts b/ui/desktop/src/utils/settings.ts index 84e0a127cd9..d85267ff681 100644 --- a/ui/desktop/src/utils/settings.ts +++ b/ui/desktop/src/utils/settings.ts @@ -2,23 +2,18 @@ import { app } from 'electron'; import fs from 'fs'; import path from 'path'; -// Types export interface EnvToggles { GOOSE_SERVER__MEMORY: boolean; GOOSE_SERVER__COMPUTER_CONTROLLER: boolean; } -export type SchedulingEngine = 'builtin-cron' | 'temporal'; - export interface Settings { envToggles: EnvToggles; showMenuBarIcon: boolean; showDockIcon: boolean; - schedulingEngine: SchedulingEngine; enableWakelock: boolean; } -// Constants const SETTINGS_FILE = path.join(app.getPath('userData'), 'settings.json'); const defaultSettings: Settings = { @@ -28,7 +23,6 @@ const defaultSettings: Settings = { }, showMenuBarIcon: true, showDockIcon: true, - schedulingEngine: 'builtin-cron', enableWakelock: false, }; @@ -53,7 +47,6 @@ export function saveSettings(settings: Settings): void { } } -// Environment management export function updateEnvironmentVariables(envToggles: EnvToggles): void { if (envToggles.GOOSE_SERVER__MEMORY) { process.env.GOOSE_SERVER__MEMORY = 'true'; @@ -67,12 +60,3 @@ export function updateEnvironmentVariables(envToggles: EnvToggles): void { delete process.env.GOOSE_SERVER__COMPUTER_CONTROLLER; } } - -export function updateSchedulingEngineEnvironment(schedulingEngine: SchedulingEngine): void { - // Set GOOSE_SCHEDULER_TYPE based on the scheduling engine setting - if (schedulingEngine === 'temporal') { - process.env.GOOSE_SCHEDULER_TYPE = 'temporal'; - } else { - process.env.GOOSE_SCHEDULER_TYPE = 'legacy'; - } -}