← back to derio-net__vscode-launchpad

Function bodies 82 total

All specs Real LLM only Function bodies
validatePath function · javascript · L90-L121 (32 LOC)
server/workspaceScanner.js
async function validatePath(workspacePath) {
  if (!workspacePath || typeof workspacePath !== 'string') {
    return false;
  }
  
  // Skip validation for remote URLs
  if (workspacePath.startsWith('http://') || 
      workspacePath.startsWith('https://') ||
      workspacePath.startsWith('vscode://') ||
      workspacePath.startsWith('vscode-remote://')) {
    return true; // Consider remote paths as valid
  }
  
  // Handle file:// prefix
  let cleanPath = workspacePath;
  if (cleanPath.startsWith('file://')) {
    cleanPath = cleanPath.substring(7);
  }
  
  // Decode URL-encoded characters
  try {
    cleanPath = decodeURIComponent(cleanPath);
  } catch (e) {
    // If decoding fails, use original path
  }
  
  try {
    return await pathExists(cleanPath);
  } catch {
    return false;
  }
}
validatePaths function · javascript · L128-L139 (12 LOC)
server/workspaceScanner.js
async function validatePaths(workspaces) {
  const results = {};
  
  for (const workspace of workspaces) {
    if (!workspace || !workspace.id || !workspace.path) {
      continue;
    }
    results[workspace.id] = await validatePath(workspace.path);
  }
  
  return results;
}
parseWorkspaceType function · javascript · L147-L160 (14 LOC)
server/workspaceScanner.js
function parseWorkspaceType(uri) {
  if (uri.startsWith('file://')) {
    return 'local';
  } else if (uri.includes('vscode-remote://dev-container')) {
    return 'dev-container';
  } else if (uri.includes('vscode-remote://attached-container')) {
    return 'attached-container';
  } else if (uri.includes('vscode-remote://ssh-remote')) {
    return 'ssh-remote';
  } else if (uri.startsWith('vscode-remote://')) {
    return 'remote';
  }
  return 'unknown';
}
extractWorkspaceName function · javascript · L165-L180 (16 LOC)
server/workspaceScanner.js
function extractWorkspaceName(uri) {
  try {
    // Decode URI components
    const decoded = decodeURIComponent(uri);
    
    // Extract the last part of the path
    const parts = decoded.split('/');
    const lastPart = parts[parts.length - 1];
    
    // Remove file extension if present
    return lastPart.replace(/\.(code-workspace|json)$/, '');
  } catch (error) {
    console.error('Error extracting workspace name:', error);
    return 'Unknown';
  }
}
parseWorkspaceData function · javascript · L185-L215 (31 LOC)
server/workspaceScanner.js
function parseWorkspaceData(workspaceJson, workspaceDir, stats) {
  try {
    const data = JSON.parse(workspaceJson);
    let uri = null;
    let type = 'unknown';
    let name = 'Unknown';
    
    // Check for workspace or folder property
    if (data.workspace) {
      uri = data.workspace;
      type = parseWorkspaceType(uri);
      name = extractWorkspaceName(uri);
    } else if (data.folder) {
      uri = data.folder;
      type = parseWorkspaceType(uri);
      name = extractWorkspaceName(uri);
    }
    
    return {
      id: path.basename(workspaceDir),
      name,
      path: uri || 'Unknown',
      type,
      lastAccessed: stats.mtime.toISOString(),
      storageDir: workspaceDir
    };
  } catch (error) {
    console.error(`Error parsing workspace data:`, error);
    return null;
  }
}
scanWorkspaceDirectory function · javascript · L220-L241 (22 LOC)
server/workspaceScanner.js
async function scanWorkspaceDirectory(workspaceDir) {
  try {
    const workspaceJsonPath = path.join(workspaceDir, 'workspace.json');
    
    // Check if workspace.json exists
    try {
      await fs.access(workspaceJsonPath);
    } catch {
      // workspace.json doesn't exist, skip this directory
      return null;
    }
    
    // Read workspace.json
    const workspaceJson = await fs.readFile(workspaceJsonPath, 'utf8');
    const stats = await fs.stat(workspaceDir);

    return parseWorkspaceData(workspaceJson, workspaceDir, stats);
  } catch (error) {
    console.error(`Error scanning workspace directory ${workspaceDir}:`, error.message);
    return null;
  }
}
scanWorkspaces function · javascript · L246-L283 (38 LOC)
server/workspaceScanner.js
async function scanWorkspaces() {
  try {
    const WORKSPACE_STORAGE_PATH = getWorkspaceStoragePath();
    
    // Check if workspace storage directory exists
    try {
      await fs.access(WORKSPACE_STORAGE_PATH);
    } catch {
      console.error(`Workspace storage directory not found: ${WORKSPACE_STORAGE_PATH}`);
      return [];
    }
    
    // Read all subdirectories
    const entries = await fs.readdir(WORKSPACE_STORAGE_PATH, { withFileTypes: true });
    const workspaceDirs = entries
      .filter(entry => entry.isDirectory())
      .map(entry => path.join(WORKSPACE_STORAGE_PATH, entry.name));
    
    // Scan each workspace directory
    const workspacePromises = workspaceDirs.map(scanWorkspaceDirectory);
    const workspaces = await Promise.all(workspacePromises);
    
    // Filter out null results (failed scans)
    const validWorkspaces = workspaces.filter(ws => ws !== null);
    
    // Log if some workspaces failed to parse
    const failedCount = workspaces.length - 
Want fix-PRs on findings? Install Repobility's GitHub App · github.com/apps/repobility-bot
refreshWorkspaces function · javascript · L288-L292 (5 LOC)
server/workspaceScanner.js
async function refreshWorkspaces() {
  console.log('Refreshing workspaces...');
  workspacesCache = await scanWorkspaces();
  console.log(`Found ${workspacesCache.length} workspaces`);
}
initialize function · javascript · L297-L318 (22 LOC)
server/workspaceScanner.js
async function initialize() {
  console.log('Initializing workspace scanner...');
  console.log(`Detected platform: ${process.platform}`);
  
  const WORKSPACE_STORAGE_PATH = getWorkspaceStoragePath();
  console.log(`Workspace storage path: ${WORKSPACE_STORAGE_PATH}`);
  
  // Validate the workspace path exists
  const pathExists = await validateWorkspacePath(WORKSPACE_STORAGE_PATH);
  if (!pathExists) {
    console.warn(`Workspace storage directory not found: ${WORKSPACE_STORAGE_PATH}`);
    console.warn('This is normal if VS Code has not been used yet or workspaces have not been created.');
  }
  
  // Initial scan
  await refreshWorkspaces();
  
  // Set up periodic refresh
  setInterval(refreshWorkspaces, REFRESH_INTERVAL);
  
  console.log(`Workspace scanner initialized. Refresh interval: ${REFRESH_INTERVAL}ms`);
}
getWorkspaces function · javascript · L323-L325 (3 LOC)
server/workspaceScanner.js
function getWorkspaces() {
  return workspacesCache;
}
removeWorkspacesFromPath function · javascript · L332-L404 (73 LOC)
server/workspaceScanner.js
async function removeWorkspacesFromPath(workspaceIds) {
  console.log('[WorkspaceScanner] removeWorkspacesFromPath called with IDs:', workspaceIds);
  
  if (!Array.isArray(workspaceIds) || workspaceIds.length === 0) {
    console.log('[WorkspaceScanner] No workspace IDs provided');
    return { success: false, removed: 0, errors: ['No workspace IDs provided'] };
  }

  const errors = [];
  let removed = 0;

  // Get current workspaces
  const currentWorkspaces = getWorkspaces();
  console.log('[WorkspaceScanner] Current workspaces count:', currentWorkspaces.length);
  console.log('[WorkspaceScanner] Current workspace IDs:', currentWorkspaces.map(ws => ws.id));
  
  // Validate that all workspaces exist in the current list
  const validIds = workspaceIds.filter(id => {
    const exists = currentWorkspaces.some(ws => ws.id === id);
    if (!exists) {
      console.log(`[WorkspaceScanner] Workspace ${id} not found in current list`);
      errors.push(`Workspace ${id} not found`);
    }
 
apiRequest function · javascript · L33-L105 (73 LOC)
src/api/client.js
export async function apiRequest(endpoint, options = {}) {
  const url = `${API_BASE_URL}${endpoint}`;
  const retries = options.retries || MAX_RETRIES;
  
  let lastError;
  
  for (let attempt = 0; attempt < retries; attempt++) {
    try {
      let response;
      
      if (isTauri()) {
        // Use Tauri HTTP plugin in desktop mode
        // Note: The Tauri HTTP plugin is loaded via the plugin system
        response = await fetch(url, {
          method: options.method || 'GET',
          headers: {
            'Content-Type': 'application/json',
            ...options.headers
          },
          body: options.body ? JSON.stringify(options.body) : undefined
        });
      } else {
        // Use native fetch in browser/development mode
        response = await fetch(url, {
          method: options.method || 'GET',
          headers: {
            'Content-Type': 'application/json',
            ...options.headers
          },
          body: options.body ? JSON.stringify
getWorkspaces function · javascript · L111-L113 (3 LOC)
src/api/client.js
export async function getWorkspaces() {
  return apiRequest('/api/workspaces');
}
validatePath function · javascript · L120-L125 (6 LOC)
src/api/client.js
export async function validatePath(path) {
  return apiRequest('/api/validate-path', {
    method: 'POST',
    body: { path }
  });
}
validatePaths function · javascript · L132-L137 (6 LOC)
src/api/client.js
export async function validatePaths(workspaces) {
  return apiRequest('/api/validate-paths', {
    method: 'POST',
    body: { workspaces }
  });
}
Citation: Repobility (2026). State of AI-Generated Code. https://repobility.com/research/
deleteWorkspaces function · javascript · L144-L157 (14 LOC)
src/api/client.js
export async function deleteWorkspaces(ids) {
  console.log('[API Client] deleteWorkspaces called with IDs:', ids);
  try {
    const result = await apiRequest('/api/workspaces/delete', {
      method: 'POST',
      body: { ids }
    });
    console.log('[API Client] deleteWorkspaces result:', result);
    return result;
  } catch (error) {
    console.error('[API Client] deleteWorkspaces error:', error);
    throw error;
  }
}
checkHealth function · javascript · L163-L174 (12 LOC)
src/api/client.js
export async function checkHealth() {
  try {
    const response = await fetch(`${API_BASE_URL}/health`, {
      method: 'GET',
      // Short timeout for health check
      signal: AbortSignal.timeout(5000)
    });
    return response.ok;
  } catch {
    return false;
  }
}
waitForApi function · javascript · L182-L193 (12 LOC)
src/api/client.js
export async function waitForApi(timeout = 30000, interval = 1000) {
  const startTime = Date.now();
  
  while (Date.now() - startTime < timeout) {
    if (await checkHealth()) {
      return true;
    }
    await new Promise(resolve => setTimeout(resolve, interval));
  }
  
  return false;
}
getEnvironment function · javascript · L199-L201 (3 LOC)
src/api/client.js
export function getEnvironment() {
  return isTauri() ? 'tauri' : 'browser';
}
getDiagnostics function · javascript · L209-L232 (24 LOC)
src/api/client.js
export async function getDiagnostics() {
  const diag = {
    environment: getEnvironment(),
    api_url: API_BASE_URL,
    api_port: validatedPort || 3010,
    timestamp: new Date().toISOString(),
  };

  // Check API health
  diag.health_check = await checkHealth();

  // In Tauri mode, call the Rust get_diagnostics command
  if (isTauri()) {
    try {
      const { invoke } = await import('@tauri-apps/api/core');
      const tauriDiag = await invoke('get_diagnostics');
      return { ...diag, ...tauriDiag };
    } catch (e) {
      diag.tauri_error = e.toString();
    }
  }

  return diag;
}
DiagnosticsPanel function · javascript · L6-L63 (58 LOC)
src/App.js
function DiagnosticsPanel() {
  const [diagnostics, setDiagnostics] = useState(null);
  const [expanded, setExpanded] = useState(false);
  const [loading, setLoading] = useState(false);

  const runDiagnostics = async () => {
    setLoading(true);
    try {
      const data = await getDiagnostics();
      setDiagnostics(data);
      setExpanded(true);
    } catch (e) {
      setDiagnostics({ error: e.toString() });
      setExpanded(true);
    } finally {
      setLoading(false);
    }
  };

  if (!expanded) {
    return (
      <button
        className="diagnostics-toggle"
        onClick={runDiagnostics}
        disabled={loading}
      >
        {loading ? 'Running diagnostics...' : 'Show Diagnostics'}
      </button>
    );
  }

  return (
    <div className="diagnostics-panel">
      <div className="diagnostics-header">
        <span>Diagnostics</span>
        <button className="diagnostics-close" onClick={() => setExpanded(false)}>
          Hide
        </button>
      </div>
 
App function · javascript · L65-L157 (93 LOC)
src/App.js
function App() {
  const [workspaces, setWorkspaces] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);
  const [isFetching, setIsFetching] = useState(false);
  const [retryCount, setRetryCount] = useState(0);

  // Fetch workspaces from API
  const fetchWorkspaces = async () => {
    if (isFetching) {
      console.log('Already fetching workspaces, skipping...');
      return;
    }

    console.log('Starting fetchWorkspaces...');
    try {
      setIsFetching(true);
      const data = await getWorkspaces();
      console.log('Workspaces fetched:', data.length);
      setWorkspaces(data);
      setError(null);
    } catch (err) {
      console.error('Error fetching workspaces:', err);
      setError(`Failed to load workspaces: ${err.message || 'Unknown error'}. Please try again.`);
    } finally {
      setLoading(false);
      setIsFetching(false);
      console.log('fetchWorkspaces complete');
    }
  };

  // Memoize fetchWor
Dashboard function · javascript · L21-L308 (288 LOC)
src/components/Dashboard.js
function Dashboard({ workspaces, onRefresh }) {
  const [searchTerm, setSearchTerm] = useState('');
  const [typeFilter, setTypeFilter] = useState('all');
  const [sortConfig, setSortConfig] = useState({ key: 'lastAccessed', direction: 'desc' });
  const [validationStatus, setValidationStatus] = useState({}); // Map of workspace id to isValid
  const [selectedWorkspaces, setSelectedWorkspaces] = useState(new Set());
  const [isDeleting, setIsDeleting] = useState(false);
  const [notification, setNotification] = useState(null);

  // Filter and sort workspaces
  const filteredAndSortedWorkspaces = useMemo(() => {
    let filtered = workspaces;

    // Apply search filter
    if (searchTerm) {
      const lowerSearch = searchTerm.toLowerCase();
      filtered = filtered.filter(ws =>
        ws.name.toLowerCase().includes(lowerSearch) ||
        ws.path.toLowerCase().includes(lowerSearch)
      );
    }

    // Apply type filter
    if (typeFilter !== 'all') {
      filtered = filtered.fi
Methodology: Repobility · https://repobility.com/research/state-of-ai-code-2026/
SearchFilter function · javascript · L4-L44 (41 LOC)
src/components/SearchFilter.js
function SearchFilter({ searchTerm, onSearchChange, typeFilter, onTypeFilterChange, workspaceTypes, onClear }) {
  const hasActiveFilters = searchTerm || typeFilter !== 'all';

  return (
    <div className="search-filter">
      <div className="filter-group">
        <label htmlFor="search">Search:</label>
        <input
          id="search"
          type="text"
          placeholder="Search by name or path..."
          value={searchTerm}
          onChange={(e) => onSearchChange(e.target.value)}
          className="search-input"
        />
      </div>

      <div className="filter-group">
        <label htmlFor="type-filter">Type:</label>
        <select
          id="type-filter"
          value={typeFilter}
          onChange={(e) => onTypeFilterChange(e.target.value)}
          className="type-filter"
        >
          {workspaceTypes.map(type => (
            <option key={type} value={type}>
              {type === 'all' ? 'All Types' : type.replace('-', ' ').replace(/\b\w
main function · rust · L1-L3 (3 LOC)
src-tauri/build.rs
fn main() {
  tauri_build::build()
}
open_vscode function · rust · L14-L19 (6 LOC)
src-tauri/src/lib.rs
async fn open_vscode(app: AppHandle, uri: String) -> Result<(), String> {
    app.opener()
        .open_url(&uri, None::<&str>)
        .map_err(|e| format!("Failed to open VS Code: {}", e))?;
    Ok(())
}
get_diagnostics function · rust · L23-L69 (47 LOC)
src-tauri/src/lib.rs
async fn get_diagnostics(app: AppHandle) -> Result<serde_json::Value, String> {
    let state: State<SidecarState> = app.state();
    let port = state.sidecar_port;
    let sidecar_path = resolve_sidecar_path(&app).unwrap_or_default();
    let sidecar_exists = sidecar_path.exists();
    let health_ok = check_sidecar_health(port).await;

    Ok(serde_json::json!({
        "sidecar_path": sidecar_path.to_string_lossy(),
        "sidecar_exists": sidecar_exists,
        "sidecar_port": port,
        "health_check": health_ok,
        "api_url": format!("http://127.0.0.1:{}", port),
        "platform": std::env::consts::OS,
        "arch": std::env::consts::ARCH,
        "dev_mode": cfg!(dev),
    })
    )
}

// Sidecar state management
pub struct SidecarState {
    pub sidecar_port: u16,
    pub restart_attempts: Arc<Mutex<u32>>,
    pub last_restart: Arc<Mutex<std::time::Instant>>,
}

impl SidecarState {
    pub fn new() -> Self {
        Self {
            sidecar_port: std::env::var("D
new function · rust · L51-L60 (10 LOC)
src-tauri/src/lib.rs
    pub fn new() -> Self {
        Self {
            sidecar_port: std::env::var("DASHBOARD_PORT")
                .ok()
                .and_then(|p| p.parse().ok())
                .unwrap_or(3010),
            restart_attempts: Arc::new(Mutex::new(0)),
            last_restart: Arc::new(Mutex::new(std::time::Instant::now())),
        }
    }
resolve_sidecar_path function · rust · L72-L102 (31 LOC)
src-tauri/src/lib.rs
fn resolve_sidecar_path(_app: &AppHandle) -> Result<std::path::PathBuf, String> {
    if cfg!(dev) {
        // In dev mode, look for the binary relative to the project root
        // current_dir() is the workspace root, binaries are in src-tauri/binaries/
        std::env::current_dir()
            .map_err(|e| format!("Failed to get current dir: {}", e))
            .map(|dir| {
                dir.join("binaries").join(if cfg!(target_os = "macos") {
                    if cfg!(target_arch = "aarch64") {
                        "sidecar-vscode-dashboard-aarch64-apple-darwin"
                    } else {
                        "sidecar-vscode-dashboard-macos-x64"
                    }
                } else if cfg!(target_os = "windows") {
                    "sidecar-vscode-dashboard-win-x64.exe"
                } else {
                    "sidecar-vscode-dashboard-linux-x64"
                })
            })
    } else {
        // In production, Tauri places externalBin sidecars
spawn_sidecar function · rust · L105-L125 (21 LOC)
src-tauri/src/lib.rs
fn spawn_sidecar(app: &AppHandle, port: u16) -> Result<std::process::Child, String> {
    let sidecar_path = resolve_sidecar_path(app)?;

    log::info!("Attempting to spawn sidecar from: {:?}", sidecar_path);

    let mut command = std::process::Command::new(&sidecar_path);
    command.env("DASHBOARD_PORT", port.to_string());
    command.env("PORT", port.to_string()); // Backward compatibility
    command.env("HOST", "127.0.0.1");

    #[cfg(target_os = "windows")]
    {
        use std::os::windows::process::CommandExt;
        const CREATE_NO_WINDOW: u32 = 0x08000000;
        command.creation_flags(CREATE_NO_WINDOW);
    }

    command
        .spawn()
        .map_err(|e| format!("Failed to spawn sidecar: {}", e))
}
start_health_monitor function · rust · L128-L175 (48 LOC)
src-tauri/src/lib.rs
async fn start_health_monitor(app: AppHandle, port: u16) {
    let mut interval = interval(Duration::from_secs(5));
    let state: State<SidecarState> = app.state();

    loop {
        interval.tick().await;

        if !check_sidecar_health(port).await {
            log::warn!("Sidecar health check failed, attempting restart...");

            let mut attempts = state.restart_attempts.lock().await;
            let mut last_restart = state.last_restart.lock().await;

            // Reset attempts if more than 60 seconds have passed
            if last_restart.elapsed().as_secs() > 60 {
                *attempts = 0;
            }

            if *attempts >= 3 {
                log::error!("Sidecar restart limit exceeded");
                let _ = app.emit(
                    "sidecar-error",
                    serde_json::json!({
                        "message": "Failed to start backend service after multiple attempts"
                    }),
                );
                br
Want this analysis on your repo? https://repobility.com/scan/
run function · rust · L178-L285 (108 LOC)
src-tauri/src/lib.rs
pub fn run() {
    tauri::Builder::default()
        .manage(SidecarState::new())
        .manage(tray::TrayState::new())
        .plugin(tauri_plugin_log::Builder::default().build())
        .plugin(tauri_plugin_shell::init())
        .plugin(tauri_plugin_opener::init())
        .plugin(tauri_plugin_http::init())
        .plugin(tauri_plugin_fs::init())
        .plugin(tauri_plugin_dialog::init())
        .plugin(tauri_plugin_process::init())
        .setup(|app| {
            // Get sidecar port from state
            let state: State<SidecarState> = app.state();
            let port = state.sidecar_port;

            // Spawn sidecar on startup
            match spawn_sidecar(app.app_handle(), port) {
                Ok(child) => {
                    log::info!("Sidecar spawned successfully on port {}", port);

                    // Store child process for cleanup
                    app.manage(Arc::new(Mutex::new(child)));

                    // Start health monitoring
         
main function · rust · L3-L6 (4 LOC)
src-tauri/src/main.rs
fn main() {
  app_lib::run();
}
create_menu function · rust · L4-L146 (143 LOC)
src-tauri/src/menu.rs
pub fn create_menu(app: &tauri::AppHandle) -> Menu<tauri::Wry> {
    let app_name = "VS Code Launchpad";

    // macOS specific menu
    #[cfg(target_os = "macos")]
    {
        let app_menu = Submenu::with_items(
            app,
            app_name,
            true,
            &[
                &MenuItem::with_id(app, "app_about", "About", true, None::<&str>).unwrap(),
                &PredefinedMenuItem::separator(app).unwrap(),
                &MenuItem::with_id(app, "app_preferences", "Preferences...", true, Some("Cmd+,")).unwrap(),
                &PredefinedMenuItem::separator(app).unwrap(),
                &MenuItem::with_id(app, "app_hide", "Hide", true, Some("Cmd+H")).unwrap(),
                &MenuItem::with_id(app, "app_hide_others", "Hide Others", true, Some("Cmd+Option+H")).unwrap(),
                &MenuItem::with_id(app, "app_show_all", "Show All", true, None::<&str>).unwrap(),
                &PredefinedMenuItem::separator(app).unwrap(),
                &MenuItem
handle_menu_event function · rust · L147-L184 (38 LOC)
src-tauri/src/menu.rs
pub fn handle_menu_event(app: &tauri::AppHandle, event: tauri::menu::MenuEvent) {
    match event.id().as_ref() {
        "app_quit" => {
            app.exit(0);
        }
        "app_hide" => {
            if let Some(window) = app.get_webview_window("main") {
                let _: Result<(), _> = window.minimize();
            }
        }
        "window_minimize" => {
            if let Some(window) = app.get_webview_window("main") {
                let _: Result<(), _> = window.minimize();
            }
        }
        "window_close" => {
            if let Some(window) = app.get_webview_window("main") {
                let _: Result<(), _> = window.close();
            }
        }
        "view_reload" => {
            if let Some(window) = app.get_webview_window("main") {
                let _: Result<(), _> = window.eval("window.location.reload()");
            }
        }
        "view_toggle_devtools" => {
            if let Some(window) = app.get_webview_window("main") 
convert_to_vscode_uri function · rust · L25-L35 (11 LOC)
src-tauri/src/tray.rs
pub fn convert_to_vscode_uri(path: &str, workspace_type: &str) -> String {
    // Remote workspaces: transform vscode-remote:// to vscode://vscode-remote/
    match workspace_type {
        "remote" | "dev-container" | "attached-container" | "ssh-remote" => {
            if path.starts_with("vscode-remote://") {
                return path.replacen("vscode-remote://", "vscode://vscode-remote/", 1);
            }
            return path.to_string();
        }
        _ => {}
    }
new function · rust · L64-L68 (5 LOC)
src-tauri/src/tray.rs
    pub fn new() -> Self {
        Self {
            tray_icon: Arc::new(Mutex::new(None)),
        }
    }
resolve_icon_path function · rust · L72-L90 (19 LOC)
src-tauri/src/tray.rs
fn resolve_icon_path(app: &tauri::AppHandle) -> Option<std::path::PathBuf> {
    if cfg!(dev) {
        // In dev mode, icons are in src-tauri/icons/ relative to the working dir
        let path = std::env::current_dir().ok()?.join("icons").join("32x32.png");
        if path.exists() { Some(path) } else { None }
    } else {
        // In production, use the resource directory
        let resource_dir = app.path().resource_dir().ok()?;
        let path = resource_dir.join("icons").join("32x32.png");
        if path.exists() {
            Some(path)
        } else {
            // Fallback: icon may be bundled alongside the executable
            let exe_dir = std::env::current_exe().ok()?.parent()?.to_path_buf();
            let path = exe_dir.join("icons").join("32x32.png");
            if path.exists() { Some(path) } else { None }
        }
    }
}
create_tray function · rust · L93-L138 (46 LOC)
src-tauri/src/tray.rs
pub fn create_tray(app: &tauri::AppHandle) -> tauri::Result<TrayIcon> {
    let tray_menu = build_menu(app, &[], false, &HashMap::new());

    let mut builder = TrayIconBuilder::with_id("main-tray")
        .menu(&tray_menu)
        .show_menu_on_left_click(cfg!(target_os = "macos"))
        .on_menu_event(handle_tray_menu_event)
        .on_tray_icon_event(|tray, event| {
            // On Windows/Linux, left-click shows the main window
            #[cfg(not(target_os = "macos"))]
            {
                use tauri::tray::{TrayIconEvent, MouseButton};
                if let TrayIconEvent::Click { button, .. } = event {
                    if button == MouseButton::Left {
                        let app = tray.app_handle();
                        if let Some(window) = app.get_webview_window("main") {
                            let _: Result<(), _> = window.show();
                            let _: Result<(), _> = window.set_focus();
                        }
                   
Want fix-PRs on findings? Install Repobility's GitHub App · github.com/apps/repobility-bot
handle_tray_menu_event function · rust · L141-L168 (28 LOC)
src-tauri/src/tray.rs
fn handle_tray_menu_event(app: &tauri::AppHandle, event: tauri::menu::MenuEvent) {
    let id = event.id();
    let id_str = id.as_ref();

    if id_str.starts_with("ws_open:") {
        // Workspace quick-open: extract the URI after the prefix
        let uri = &id_str["ws_open:".len()..];
        if let Err(e) = app.opener().open_url(uri, None::<&str>) {
            log::error!("Failed to open workspace from tray: {}", e);
        }
    } else {
        match id_str {
            "show_dashboard" => {
                if let Some(window) = app.get_webview_window("main") {
                    let _: Result<(), _> = window.show();
                    let _: Result<(), _> = window.set_focus();
                }
            }
            "check_updates" => {
                let _ = app.emit("check-for-updates", ());
            }
            "quit" => {
                app.exit(0);
            }
            _ => {}
        }
    }
}
type_emoji function · rust · L171-L180 (10 LOC)
src-tauri/src/tray.rs
fn type_emoji(workspace_type: &str) -> &'static str {
    match workspace_type {
        "local" => "🔵",
        "ssh-remote" => "🟣",
        "dev-container" => "🟢",
        "attached-container" => "🟡",
        "remote" => "🩷",
        _ => "⚪",
    }
}
is_remote_type function · rust · L183-L185 (3 LOC)
src-tauri/src/tray.rs
fn is_remote_type(workspace_type: &str) -> bool {
    matches!(workspace_type, "remote" | "dev-container" | "attached-container" | "ssh-remote")
}
build_menu function · rust · L188-L242 (55 LOC)
src-tauri/src/tray.rs
fn build_menu(app: &tauri::AppHandle, workspaces: &[TrayWorkspace], backend_healthy: bool, validity: &HashMap<String, bool>) -> Menu<tauri::Wry> {
    let status_label = if backend_healthy { "Backend: Running" } else { "Backend: Offline" };

    if workspaces.is_empty() {
        let no_ws = MenuItem::with_id(app, "no_workspaces", "No workspaces found", false, None::<&str>).unwrap();
        let sep1 = PredefinedMenuItem::separator(app).unwrap();
        let show = MenuItem::with_id(app, "show_dashboard", "Show Dashboard", true, None::<&str>).unwrap();
        let updates = MenuItem::with_id(app, "check_updates", "Check for Updates", true, None::<&str>).unwrap();
        let sep2 = PredefinedMenuItem::separator(app).unwrap();
        let quit = MenuItem::with_id(app, "quit", "Quit", true, None::<&str>).unwrap();
        let sep3 = PredefinedMenuItem::separator(app).unwrap();
        let status = MenuItem::with_id(app, "backend_status", status_label, false, None::<&str>).unwrap();

    
update_tray_menu function · rust · L245-L259 (15 LOC)
src-tauri/src/tray.rs
pub async fn update_tray_menu(app: &tauri::AppHandle, workspaces: &[TrayWorkspace], backend_healthy: bool, validity: &HashMap<String, bool>) {
    let tray_state: tauri::State<'_, TrayState> = app.state();
    let tray_icon = tray_state.tray_icon.lock().await;

    if let Some(tray) = tray_icon.as_ref() {
        let new_menu = build_menu(app, workspaces, backend_healthy, validity);
        if let Err(e) = tray.set_menu(Some(new_menu)) {
            log::error!("Failed to update tray menu: {}", e);
        } else {
            log::info!("Tray menu updated: {} workspaces, backend {}", workspaces.len(), if backend_healthy { "online" } else { "offline" });
        }
    } else {
        log::warn!("Tray icon not stored in state, cannot update menu");
    }
}
fetch_workspaces function · rust · L262-L336 (75 LOC)
src-tauri/src/tray.rs
pub async fn fetch_workspaces(port: u16) -> Vec<TrayWorkspace> {
    let url = format!("http://127.0.0.1:{}/api/workspaces", port);
    match reqwest::get(&url).await {
        Ok(response) => {
            if response.status().is_success() {
                match response.json::<Vec<TrayWorkspace>>().await {
                    Ok(mut workspaces) => {
                        // Sort by last_accessed descending
                        workspaces.sort_by(|a, b| b.last_accessed.cmp(&a.last_accessed));
                        workspaces
                    }
                    Err(e) => {
                        log::warn!("Failed to parse workspace response: {}", e);
                        Vec::new()
                    }
                }
            } else {
                Vec::new()
            }
        }
        Err(e) => {
            log::warn!("Failed to fetch workspaces for tray: {}", e);
            Vec::new()
        }
    }
}

/// Validate workspace paths via the sidecar A
validate_workspace_paths function · rust · L292-L586 (295 LOC)
src-tauri/src/tray.rs
pub async fn validate_workspace_paths(port: u16, workspaces: &[TrayWorkspace]) -> HashMap<String, bool> {
    let url = format!("http://127.0.0.1:{}/api/validate-paths", port);

    // Build the request body: { workspaces: [{id, path}, ...] }
    let payload: Vec<serde_json::Value> = workspaces.iter().map(|ws| {
        serde_json::json!({ "id": ws.id, "path": ws.path })
    }).collect();
    let body = serde_json::json!({ "workspaces": payload });

    let client = reqwest::Client::new();
    match client.post(&url).json(&body).send().await {
        Ok(response) => {
            if response.status().is_success() {
                // Response: { results: { "ws-id": true/false, ... } }
                #[derive(Deserialize)]
                struct ValidateResponse {
                    results: HashMap<String, bool>,
                }
                match response.json::<ValidateResponse>().await {
                    Ok(parsed) => {
                        // Convert id-keyed results 
refresh_tray function · rust · L339-L346 (8 LOC)
src-tauri/src/tray.rs
pub async fn refresh_tray(app: &tauri::AppHandle, port: u16) {
    log::debug!("Tray refresh: fetching workspaces from port {}", port);
    let workspaces = fetch_workspaces(port).await;
    let healthy = super::check_sidecar_health(port).await;
    let validity = validate_workspace_paths(port, &workspaces).await;
    log::debug!("Tray refresh: got {} workspaces, healthy={}, validated {} paths", workspaces.len(), healthy, validity.len());
    update_tray_menu(app, &workspaces, healthy, &validity).await;
}
Citation: Repobility (2026). State of AI-Generated Code. https://repobility.com/research/
tray_state_starts_empty function · rust · L353-L358 (6 LOC)
src-tauri/src/tray.rs
    fn tray_state_starts_empty() {
        let state = TrayState::new();
        // TrayIcon should be None initially
        let guard = state.tray_icon.blocking_lock();
        assert!(guard.is_none(), "TrayState should start with no icon");
    }
blocking_lock_provides_immediate_access function · rust · L361-L379 (19 LOC)
src-tauri/src/tray.rs
    fn blocking_lock_provides_immediate_access() {
        // This test verifies the fix: blocking_lock() in synchronous context
        // makes the value immediately available, unlike the old async spawn pattern
        // which could leave the value as None when accessed shortly after.
        let state = TrayState::new();

        // Simulate synchronous storage (the fix)
        {
            let guard = state.tray_icon.blocking_lock();
            // We can't create a real TrayIcon in tests, but we verify the lock works
            assert!(guard.is_none());
            // In production: *guard = Some(tray_icon);
        }

        // Immediately accessible after the lock is released
        let guard = state.tray_icon.blocking_lock();
        // Lock is acquired without blocking — no race condition
        assert!(guard.is_none()); // Still None since we didn't set a real icon
    }
async_spawn_storage_can_race_with_reader function · rust · L382-L403 (22 LOC)
src-tauri/src/tray.rs
    async fn async_spawn_storage_can_race_with_reader() {
        // This test demonstrates the BUG: storing a value via async spawn
        // means the value may not be available when a reader checks immediately.
        let shared = Arc::new(Mutex::new(false));

        // Simulate the old pattern: store value via async spawn
        let writer = shared.clone();
        tokio::spawn(async move {
            // This task is queued but may not run immediately
            let mut guard = writer.lock().await;
            *guard = true;
        });

        // Read immediately WITHOUT awaiting the spawn — simulates the refresh
        // task reading TrayState before the icon storage spawn executes.
        // NOTE: This succeeds on a multi-threaded runtime but demonstrates
        // the pattern issue — the value might still be false (unset).
        let guard = shared.lock().await;
        // On a busy runtime, the spawn may not have executed yet.
        // The fix avoids this race en
page 1 / 2next ›