Skip to content

Comments

Major Rewrite#20

Merged
iamEvanYT merged 78 commits intomainfrom
evan/reorganization
Apr 17, 2025
Merged

Major Rewrite#20
iamEvanYT merged 78 commits intomainfrom
evan/reorganization

Conversation

@iamEvanYT
Copy link
Member

@iamEvanYT iamEvanYT commented Apr 8, 2025

Info

Major rewrite of the core to support profiles & spaces!

Tasks

  • Flow Games
  • Simple Onboarding
  • Spaces
  • Profiles
  • Better Flow APIs
  • Better Security
  • Vibrancy on Background
  • Always Allow Opening External Applications
  • Tabs & Tab Group System

Issues

Linked to #7

Summary by CodeRabbit

  • New Features

    • Added context menu for browser tabs with rich navigation, link, image, and text actions.
    • Introduced prevention of Ctrl+W closing entire window on Windows, closing only current tab instead.
    • Added onboarding React component for creating user spaces during onboarding flow.
    • Added typed event emitter for strongly typed event handling.
    • Added animated tab bounds transitions for smooth resizing and repositioning.
    • Added modular menu system with dynamic spaces menu and sidebar toggle.
    • Added new IPC modules for tab management, onboarding, new tab modes, icons, and open-external preferences.
    • Added onboarding window with custom title bar and dark mode support.
    • Added custom Electron protocols with secure asset and favicon serving.
    • Added new browser window and tab management classes with modular architecture.
    • Added comprehensive preload API with modular IPC communication and permission checks.
    • Added new tab group modes ("glance", "split") with lifecycle and layout management.
    • Added favicon fetching improvements with session support and URL normalization.
    • Added new CSS and HTML for multiple Olympic-themed Chrome Dino offline games and Edge Surf game.
    • Added profile and space management with event-driven updates and ordering.
    • Added hot reload support with concurrency control for development environment.
    • Added view and z-index management for Electron views.
    • Added onboarding completion state management and reset functionality.
    • Added modular menu items for app, file, edit, view, archive, window, and spaces menus.
    • Added tab lifecycle and management with event-driven state synchronization.
    • Added browser event typing and structured event emission.
    • Added Electron IPC handlers for window buttons, navigation, tabs, and settings.
  • Improvements

    • Refined settings management with sidebar collapse mode and onboarding state persistence.
    • Improved error handling, debug logging, and user feedback across icon, window, and profile management.
    • Enhanced preload script with better UI context detection and modular API exposure.
    • Improved protocol handling with CORS bypass and domain validation.
    • Expanded and reorganized developer documentation for APIs, tabs, omnibox, and contributing.
    • Added detailed menu utilities and icon management with platform support.
    • Improved favicon caching to ignore unsupported protocols gracefully.
    • Improved onboarding flow integration with window lifecycle and profile creation.
    • Updated Electron window creation for async readiness and event handling.
    • Added debug logging and error handling in icon management lifecycle.
    • Improved tab group synchronization and lifecycle event handling.
    • Enhanced session management with permission prompts for external URLs.
    • Improved window and tab destruction safety and event emission.
    • Added caching and normalization enhancements for favicon URLs.
  • Bug Fixes

    • Fixed ignored files in version control for macOS and legacy directories.
    • Addressed menu item reliability and window focus handling.
    • Fixed favicon caching to ignore unsupported protocols gracefully.
  • Chores

    • Updated dependencies and scripts for Electron, Vite, and related tooling.
    • Removed legacy WebUI extension files and outdated IPC/menu code.
    • Cleaned up project structure and improved TypeScript path aliases.
    • Removed deprecated IPC handlers and replaced with modular IPC modules.
    • Added extensive debug logging for icon management.
    • Added new CSS files for offline games and interstitial styling.
    • Removed unused imports and streamlined window creation promises.
    • Refactored preload script for modular API exposure and permission checks.
    • Consolidated IPC handlers into categorized modules.
    • Removed obsolete menu and IPC files, replaced with modular utilities.
  • Documentation

    • Updated README with new version, features, screenshots, and roadmap.
    • Added extensive API and reference documentation files.
    • Added new contributing guides including hot reloading instructions.
    • Added detailed omnibox, tab group, and session management documentation.
  • Style

    • Added and updated CSS for offline games, interstitials, and browser UI.
  • Tests

    • No explicit test changes noted.
  • Revert

    • Removed legacy WebUI extension files and outdated documentation.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Apr 8, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

This update is a comprehensive refactor and feature expansion across the Flow Browser codebase. It introduces a modular architecture by splitting monolithic classes into dedicated managers for profiles, windows, tabs, and tab groups, each with event-driven designs and strong typing. The Electron main process now uses a centralized IPC structure, with new handlers for browser, session, app, and window operations. Extensive new documentation is added for APIs and architecture. The UI gains new features such as spaces, onboarding, and hot reloading support, with corresponding backend and IPC logic. The public directory is enriched with themed offline games. The build system, settings, and dependency management are also updated for improved development and user experience.

Changes

Files/Areas Change Summary
electron/browser/browser.ts, electron/browser/profile-manager.ts, electron/browser/window-manager.ts, electron/browser/tabs/tab-manager.ts, electron/browser/tabs/tab-groups/*, electron/browser/tabs/tab-bounds.ts, electron/browser/tabs/tab.ts, electron/browser/window.ts, electron/browser/view-manager.ts, electron/browser/components/*, electron/browser/utility/* Refactored browser core into modular, event-driven managers for profiles, windows, tabs, tab groups, and views; introduced new classes for GlanceModal, Omnibox, and utility helpers.
electron/browser/ipc.ts, electron/browser/menu.ts, electron/browser/protocols.ts, electron/browser/tabbed-browser-window.ts, electron/browser/tabs.ts Removed legacy IPC, menu, protocol, and tab/window management implementations, replaced by new modular managers and utility modules.
electron/ipc/*, electron/saving/*, electron/sessions/*, electron/modules/* Added or refactored IPC handlers for browser, session, app, window, and onboarding; improved settings, onboarding, and open-external state management; enhanced session and favicon handling; added typed event emitter class.
electron/preload.ts Refactored preload script for modular, permission-checked API exposure; standardized IPC channel naming; expanded API coverage.
electron/settings/main.ts Updated settings window logic for async creation and internal URL changes; removed direct IPC handlers from this module.
electron/package.json, package.json, vite/package.json, electron/tsconfig.json Updated versions, dependencies, scripts, and TypeScript path aliases.
README.md, CONTRIBUTING.md, docs/* Major documentation updates and additions for features, APIs, and new developer guides.
vite/public/chrome-dino-game/*, vite/public/edge-surf-game-v1/* Added multiple themed offline games and supporting scripts, CSS, and manifests.
vite/.gitignore, .gitignore, vite/README.md, vite/manifest.json, vite/background.js Updated ignore rules; removed obsolete or extension-related files.
electron/modules/icons.ts, electron/modules/output.ts, electron/modules/flags.ts Enhanced icon management with debug logging and platform support; updated feature flags and debug areas.
shared/types/tabs.ts New shared types for tab and tab group data structures.

Sequence Diagram(s)

sequenceDiagram
    participant App
    participant MainProcess
    participant WindowManager
    participant TabManager
    participant ProfileManager
    participant IPC
    participant Renderer

    App->>MainProcess: Launch & initialize
    MainProcess->>ProfileManager: Load default profile
    MainProcess->>WindowManager: Create initial window
    WindowManager->>TabManager: Create initial tab(s)
    Renderer->>IPC: Request (e.g., create tab, switch space)
    IPC->>MainProcess: Handle IPC event
    MainProcess->>TabManager: Perform tab/space operation
    TabManager-->>MainProcess: Update state
    MainProcess-->>IPC: Notify Renderer of state change
    IPC-->>Renderer: Send updated data
Loading

Possibly related PRs

  • Spaces Management #19: Adds IPC handlers and import path updates for spaces management, which are now fully integrated and extended in this PR with broader spaces and session logic.
  • Add Settings Window #15: Removes the TabbedBrowserWindow class and introduces new window management, directly related to the refactoring and modularization of window logic in this PR.
  • Fix Extensions & Improve Omnibox #13: Refactors the Omnibox class, overlapping with this PR's changes to omnibox lifecycle, destruction checks, and URL scheme updates.

Poem

Hopping through code with a whisk and a broom,
The rabbit refactored each class in the room.
Windows and tabs now dance in neat rows,
With spaces and profiles, the architecture grows!
Onboarding is friendly, the games are a treat,
Debug logs and docs make the journey complete.
Flow Browser leaps forward—oh, what a feat!

((\
( -.-)
o_(")(")
🥕

Tip

⚡💬 Agentic Chat (Pro Plan, General Availability)
  • We're introducing multi-step agentic chat in review comments and issue comments, within and outside of PR's. This feature enhances review and issue discussions with the CodeRabbit agentic chat by enabling advanced interactions, including the ability to create pull requests directly from comments and add commits to existing pull requests.
✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@iamEvanYT iamEvanYT self-assigned this Apr 8, 2025
@iamEvanYT iamEvanYT added the enhancement New feature or request label Apr 8, 2025
@iamEvanYT iamEvanYT moved this to In progress in Roadmap - Flow Browser Apr 8, 2025
@iamEvanYT iamEvanYT marked this pull request as ready for review April 16, 2025 14:14
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 59

🔭 Outside diff range comments (2)
electron/modules/typed-event-emitter.ts (1)

155-163: 🛠️ Refactor suggestion

destroy() should be idempotent

Throwing when destroy() is called twice can crash listeners that legitimately call it in both explicit teardown and the "closed" event.
Better to convert the guard into a no‑op:

-    if (this.isDestroyed) {
-      throw new Error("Window already destroyed!");
-    }
+    if (this.isDestroyed) {
+      return; // already cleaned up
+    }

This makes the class easier to use and reduces the chance of unhandled exceptions during shutdown sequences.

electron/sessions/spaces.ts (1)

30-44: 🛠️ Refactor suggestion

Validate & type‑check datastore contents

reconcileSpaceData() trusts arbitrary datastore values and manually applies fall‑backs. Zod has already defined SpaceDataSchema; use it to parse/validate and surface bad data early:

-  return {
-    name: data.name ?? defaultName,
-    ...
-  };
+  return SpaceDataSchema.parse({
+    name: data.name ?? defaultName,
+    profileId,
+    ...data
+  });

This eliminates silent schema drift and forces callers to fix corrupted records instead of propagating them.

🧹 Nitpick comments (93)
vite/.gitignore (1)

27-27: Correct the UI directory ignore pattern

The previous entry mistakenly included a leading hyphen. Changing to ui/* properly ignores the ui directory and its contents. As a small improvement, you can simplify this to ignore the directory directly:

-ui/*
+ui/
.gitignore (1)

138-145: Exclude macOS metadata and legacy artifacts

Adding .DS_Store under a dedicated # macOS header prevents OS-specific files from being committed. Ignoring legacy folders (extensions, vite-old, vite-old-2, and electron/browser/_old) also helps keep the repo clean. For clarity and consistency, consider anchoring directory patterns and using trailing slashes:

-# macOS
-.DS_Store

-extensions/*
-vite-old
-vite-old-2
-electron/browser/_old
+# macOS
+.DS_Store

+extensions/
+vite-old/
+vite-old-2/
+electron/browser/_old/
vite/public/chrome-dino-game/appmanifest.json (1)

1-37: Well-structured web app manifest with all essential properties

The manifest follows PWA standards with appropriate properties for the Chrome Dino game. All required fields are present with correct formatting and a good set of icons at various resolutions.

One minor enhancement you might consider:

 {
 	"name": "Chrome Dino",
 	"short_name": "Chrome Dino",
 	"description": "Dino game. A pixelated dinosaur dodges cacti and pterodactyls as it runs across a desolate landscape.",
 	"version": "2.0",
 	"start_url": "index.html",
 	"display": "fullscreen",
 	"orientation": "any",
 	"background_color": "#ffffff",
+	"theme_color": "#ffffff",
 	"icons": [
vite/public/chrome-dino-game/scripts/strings.js (1)

1-2: Consider improving code readability while maintaining functionality

The code correctly defines and assigns localized strings for the Chrome Dino game. The pageData object contains all necessary game configuration including accessibility labels, image paths, and UI text.

For better maintainability, consider formatting the JSON object with proper indentation:

-var pageData = {"altGameCommonImage1x":"images/default_100_percent/offline/100-olympic-firemedal-sprites.png","altGameCommonImage2x":"images/default_200_percent/offline/200-olympic-firemedal-sprites.png","dinoGameA11yAriaLabel":"","dinoGameA11yGameOver":"Game over, your score is $1.","dinoGameA11yHighScore":"Your highest score is $1.","dinoGameA11yJump":"Jump!","dinoGameA11ySpeedToggle":"Start slower","dinoGameA11yStartGame":"Game started.","enableAltGameMode":false,"errorCode":"","fontfamily":"'Segoe UI', Tahoma, sans-serif","fontsize":"75%","heading":{"hostName":"dino","msg":"Press space to play"},"iconClass":"icon-offline","language":"en","textdirection":"ltr","title":"chrome://dino/"};
+var pageData = {
+  "altGameCommonImage1x": "images/default_100_percent/offline/100-olympic-firemedal-sprites.png",
+  "altGameCommonImage2x": "images/default_200_percent/offline/200-olympic-firemedal-sprites.png",
+  "dinoGameA11yAriaLabel": "",
+  "dinoGameA11yGameOver": "Game over, your score is $1.",
+  "dinoGameA11yHighScore": "Your highest score is $1.",
+  "dinoGameA11yJump": "Jump!",
+  "dinoGameA11ySpeedToggle": "Start slower",
+  "dinoGameA11yStartGame": "Game started.",
+  "enableAltGameMode": false,
+  "errorCode": "",
+  "fontfamily": "'Segoe UI', Tahoma, sans-serif",
+  "fontsize": "75%",
+  "heading": {
+    "hostName": "dino",
+    "msg": "Press space to play"
+  },
+  "iconClass": "icon-offline",
+  "language": "en",
+  "textdirection": "ltr",
+  "title": "chrome://dino/"
+};
vite/public/chrome-dino-game/styles/interstitial_core.css (1)

1-15: Consolidate duplicate CSS variable definitions

The CSS file has duplicate variable definitions in both :root and body selectors, which creates unnecessary redundancy.

Consider consolidating the duplicate CSS variables by keeping them only in the :root selector:

:root {
  --background-color: #fff;
  --google-blue-100: rgb(210, 227, 252);
  --google-blue-300: rgb(138, 180, 248);
  --google-blue-600: rgb(26, 115, 232);
  --google-blue-700: rgb(25, 103, 210);
  --google-gray-100: rgb(241, 243, 244);
  --google-gray-300: rgb(218, 220, 224);
  --google-gray-500: rgb(154, 160, 166);
  --google-gray-50: rgb(248, 249, 250);
  --google-gray-600: rgb(128, 134, 139);
  --google-gray-700: rgb(95, 99, 104);
  --google-gray-800: rgb(60, 64, 67);
  --google-gray-900: rgb(32, 33, 36);
+  --error-code-color: var(--google-gray-700);
+  --heading-color: var(--google-gray-900);
+  --link-color: rgb(88, 88, 88);
+  --popup-container-background-color: rgba(0,0,0,.65);
+  --primary-button-fill-color-active: var(--google-blue-700);
+  --primary-button-fill-color: var(--google-blue-600);
+  --primary-button-text-color: #fff;
+  --quiet-background-color: rgb(247, 247, 247);
+  --secondary-button-border-color: var(--google-gray-500);
+  --secondary-button-fill-color: #fff;
+  --secondary-button-hover-border-color: var(--google-gray-600);
+  --secondary-button-hover-fill-color: var(--google-gray-50);
+  --secondary-button-text-color: var(--google-gray-700);
+  --small-link-color: var(--google-gray-700);
+  --text-color: var(--google-gray-700);
}

body {
-  --background-color: #fff;
-  --error-code-color: var(--google-gray-700);
-  --google-blue-100: rgb(210, 227, 252);
-  --google-blue-300: rgb(138, 180, 248);
-  --google-blue-600: rgb(26, 115, 232);
-  --google-blue-700: rgb(25, 103, 210);
-  --google-gray-100: rgb(241, 243, 244);
-  --google-gray-300: rgb(218, 220, 224);
-  --google-gray-500: rgb(154, 160, 166);
-  --google-gray-50: rgb(248, 249, 250);
-  --google-gray-600: rgb(128, 134, 139);
-  --google-gray-700: rgb(95, 99, 104);
-  --google-gray-800: rgb(60, 64, 67);
-  --google-gray-900: rgb(32, 33, 36);
-  --heading-color: var(--google-gray-900);
-  --link-color: rgb(88, 88, 88);
-  --popup-container-background-color: rgba(0,0,0,.65);
-  --primary-button-fill-color-active: var(--google-blue-700);
-  --primary-button-fill-color: var(--google-blue-600);
-  --primary-button-text-color: #fff;
-  --quiet-background-color: rgb(247, 247, 247);
-  --secondary-button-border-color: var(--google-gray-500);
-  --secondary-button-fill-color: #fff;
-  --secondary-button-hover-border-color: var(--google-gray-600);
-  --secondary-button-hover-fill-color: var(--google-gray-50);
-  --secondary-button-text-color: var(--google-gray-700);
-  --small-link-color: var(--google-gray-700);
-  --text-color: var(--google-gray-700);
  background: var(--background-color);
  color: var(--text-color);
  word-wrap: break-word;
}

Also applies to: 26-41

vite/public/chrome-dino-game/index.html (3)

19-27: Google Analytics may silently fail offline
You’re loading gtag.js unconditionally on an offline page. In a true offline context, this external request will never succeed and may trigger console errors. Consider wrapping the GA snippet in an if (navigator.onLine) block or lazy loading it only when connectivity is detected.


29-29: Move inline font-size into external CSS
The style="font-size: 75%" on the <body> would be cleaner and more maintainable if moved into style.css.

-<body id="t" class="neterror" style="font-size: 75%">
+<body id="t" class="neterror">

and in style.css:

body.neterror {
  font-size: 75%;
}

64-70: Extract duplicated audio data URIs into external assets
You’ve embedded large base64 audio blobs directly in this HTML. This bloats the page and duplicates the same audio in every variant. Consider moving these into separate .mp3 files and referencing them via <audio src="...">.

vite/public/chrome-dino-game/style.css (1)

146-156: Remove or consolidate unused selectors
Selectors like .suggested-left > #control-buttons and .snackbar aren’t present in any of the new Dino pages. These rules add weight to the stylesheet and can be removed or moved into a narrower context if you plan to reuse them elsewhere.

vite/public/chrome-dino-game/4_swimming.html (1)

73-94: Theme switching implementation could be improved.

While the theme switching works, it requires a page reload. Consider using the History API to update the URL without a full page reload, or implementing the theme switching without navigation for a smoother experience.

function changeTheme() {
    const theme = document.getElementById("themeDino").value;
    
-   switch (theme) {
-       case "default":
-           location.href = "index.html";
-           break;
-       case "hurdling":
-           location.href = "1_hurdling.html";
-           break;
-       // other cases...
-   }
+   if (theme) {
+       // Update URL without reload (preserves game state)
+       const newUrl = theme === "default" ? "index.html" : `${theme}.html`;
+       history.pushState({}, "", newUrl);
+       
+       // Load new sprite resources
+       loadThemeResources(theme);
+   }
}

// This would need to be implemented to load the new theme resources
function loadThemeResources(theme) {
    // Load new sprite images, etc.
}
vite/public/chrome-dino-game/1_hurdling.html (2)

61-71: Duplicate code across game variants.

The touch detection code is duplicated across multiple HTML files. Consider moving this logic to a shared JavaScript file to improve maintainability.

- <script>
-     function is_touch_enabled() {
-         return ( 'ontouchstart' in window ) || 
-                ( navigator.maxTouchPoints > 0 ) ||
-                ( navigator.msMaxTouchPoints > 0 );
-     }
-     if ( is_touch_enabled() ) {
-         var box = document.getElementById("heading.msg");
-         box.innerHTML = "Touch the dino to play";
-     }
- </script>
+ <script src="scripts/touch-detection.js"></script>

This would require creating a new touch-detection.js file with the shared logic.


73-94: Theme switching logic duplication.

The theme switching function is duplicated across game variants. This should be moved to a shared JavaScript file to reduce redundancy and make maintenance easier.

- <script>
-     function changeTheme() {
-         switch (document.getElementById("themeDino").value) {
-             case "default":
-                 location.href = "index.html";
-                 break;
-             // other cases...
-         }
-     }
- </script>
+ <script src="scripts/theme-switcher.js"></script>
vite/public/chrome-dino-game/styles/neterror.css (1)

1-430: Consider using CSS variables for improved maintainability.

The stylesheet uses hardcoded color values in many places. Refactoring to use CSS custom properties (variables) would improve maintainability and theme consistency.

Consider defining a set of variables at the top of your file:

* {
  font-family: system-ui, 'Segoe UI', Tahoma, sans-serif;
}

+:root {
+  --color-background: #fff;
+  --color-text: #000;
+  --color-blue: var(--google-blue-300, #8ab4f8);
+  --color-gray: var(--google-gray-50, #f8f9fa);
+  --color-dark-gray: rgb(189,193,198);
+  /* Add more variables as needed */
+}

Then use these variables throughout the stylesheet instead of hardcoded values.

vite/public/chrome-dino-game/scripts/offline-sprite-definitions.js (3)

5-6: Consider using a proper enum for game types.

The game types are defined as string literals in an array. Using a proper enum or object with named constants would improve code readability and type safety.

/* @const */
-const GAME_TYPE = ['type_1', 'type_2', 'type_3', 'type_4', 'type_5'];
+const GAME_TYPE = {
+  HURDLING: 'type_1',
+  GYMNASTICS: 'type_2',
+  SURFING: 'type_3',
+  SWIMMING: 'type_4',
+  EQUESTRIAN: 'type_5'
+};

26-26: Use const for type definition instead of let.

Type definitions should typically be declared with const rather than let since they're not meant to be reassigned.

-let ObstacleType;
+const ObstacleType = {};  // Or just use JSDoc without variable declaration

31-687: Consider extracting common numeric values into named constants.

Several numeric values are repeated throughout the code (like collision box parameters, animation frame rates, etc.). Extracting these into named constants would improve readability and maintainability.

For example, you could define constants for common speeds, gaps, and physics parameters:

const DEFAULT_MIN_GAP = 120;
const DEFAULT_MULTIPLE_SPEED = 4;
const DEFAULT_GRAVITY = 0.6;
const LOWERED_GRAVITY = 0.36;

Then use these constants throughout your sprite definitions where appropriate.

electron/modules/output.ts (1)

12-13: Add trailing comma for consistency.
All entries in the DEBUG_AREAS object use trailing commas except ICONS. Adding a comma maintains uniform formatting.

Apply this diff:

 const DEBUG_AREAS = {
   SPACES: false, // @/sessions/spaces.ts
-  ICONS: false // @/modules/icons.ts
+  ICONS: false, // @/modules/icons.ts
 } as const;
vite/index.html (1)

6-6: Ensure a <title> tag is present for accessibility.
The document currently lacks a <title>, which is important for usability and SEO. Consider adding a descriptive title before the icon link.

Example:

<title>Flow Browser</title>
<link rel="icon" type="image/x-icon" href="/assets/favicon.ico" />
docs/references/tabs.md (1)

1-5: Add a top-level header and clarify mode descriptions.
Starting with a secondary header can be confusing. Introduce a primary title (e.g., # Tabs Reference) and expand each mode’s description for clarity.

Suggested structure:

# Tabs Reference

## Active Tab Modes

- **Standard**: Single tab layout.
- **Glance**: Two-tab glance mode (front & back).
- **Split**: Split-screen tabs side by side.
vite/eslint.config.js (1)

22-26: Disabling react-refresh linting rule

Changed the react-refresh/only-export-components rule from "warn" to "off", while maintaining the allowConstantExport option. This change likely accommodates the component structure in the refactored codebase that may not strictly adhere to the React Refresh optimization requirements.

Consider documenting the reason for disabling this rule, as it might impact hot reloading performance in some cases.

electron/browser/tabs/tab-groups/split.ts (1)

1-7: Approved, but note pending implementation.

This is a good starting structure for SplitTabGroup with proper inheritance from BaseTabGroup. The TODO comment correctly indicates that implementation for split layout is still pending.

Consider adding a JSDoc comment to describe what the split tab group will do when implemented:

import { BaseTabGroup } from "@/browser/tabs/tab-groups";

+/**
+ * Tab group implementation for split view layouts.
+ * Allows displaying multiple tabs side by side in a single window.
+ */
export class SplitTabGroup extends BaseTabGroup {
  public mode: "split" = "split";

  // TODO: Implement split tab group layout
}
electron/ipc/app/app.ts (1)

1-9: LGTM - Good implementation of app info handler.

The implementation correctly uses ipcMain.handle with async/await for the IPC handler. The properties being returned are appropriate for basic app information.

Consider adding a TypeScript interface for the returned data structure:

import { app } from "electron";
import { ipcMain } from "electron";

+interface AppInfo {
+  version: string;
+  packaged: boolean;
+}

ipcMain.handle("app:get-info", async () => {
  return {
    version: app.getVersion(),
    packaged: app.isPackaged
  } as AppInfo;
});
docs/contributing/hot-reloading.md (1)

1-40: Good documentation, could be enhanced with additional details.

This is a clear and concise guide for setting up hot reloading. The prerequisites, steps, and troubleshooting sections provide a good foundation for developers.

Consider enhancing the documentation with additional details:

  1. What types of changes trigger hot reloading vs. requiring a full restart?
  2. How can developers verify hot reloading is working correctly?
  3. Which parts of the application support hot reloading (renderer process only, or main process too)?
  4. Are there any limitations or known issues with hot reloading?

For example, you could add a section like:

## What to Expect

Hot reloading will automatically refresh the UI when you make changes to:
- React components in `src/renderer`
- CSS/SCSS files
- ...

Changes to the following will require a full restart:
- Electron main process files
- IPC handlers
- ...

You'll know hot reloading is working when you see "HMR update successful" in the browser console.
electron/saving/datastore.ts (1)

35-35: Changed visibility from private to public

The directoryPath property has been changed from private to public. This exposes an implementation detail that was previously encapsulated. Consider if this change is necessary or if it could be kept private with a getter method instead.

-  public directoryPath: string;
+  private directoryPath: string;
+
+  /**
+   * Gets the directory path for this datastore
+   * @returns The path to the directory containing this datastore
+   */
+  getDirectoryPath(): string {
+    return this.directoryPath;
+  }
electron/browser/utility/menu/items/app.ts (1)

7-22: Consider platform-specific menu customization

The menu includes macOS-specific roles like services and hideOthers that may not be applicable on other platforms. Consider making the menu structure adapt to the current platform.

export const createAppMenu = (): MenuItemConstructorOptions => ({
  role: "appMenu",
  submenu: [
    { role: "about" },
    { type: "separator" },
    {
      label: "Settings",
      click: () => {
        settings.show();
      }
    },
+   ...(process.platform === 'darwin' ? [
    { role: "services" },
    { type: "separator" },
    { role: "hide" },
    { role: "hideOthers" },
    { role: "showAllTabs" },
+   ] : []),
    { type: "separator" },
    { role: "quit" }
  ]
});
docs/references/omnibox-scores.md (1)

5-12: Consider using en dashes for numerical ranges

For better typographical correctness, use en dashes (–) instead of hyphens (-) when indicating numerical ranges. This improves readability and follows proper typographical conventions.

-**~1100 - 1500:** Open Tab (Switch) - _Encourages switching to existing tabs. Score scales with title/URL similarity._
+**~1100 – 1500:** Open Tab (Switch) - _Encourages switching to existing tabs. Score scales with title/URL similarity._
-**1400 - 1450+:** History URL (Exact Match) - _Very high score for exact URL matches in history._
+**1400 – 1450+:** History URL (Exact Match) - _Very high score for exact URL matches in history._
-**1100 - 1200:** Pedal - _Browser actions triggered by keywords (e.g., "settings"). Score scales with trigger similarity._
+**1100 – 1200:** Pedal - _Browser actions triggered by keywords (e.g., "settings"). Score scales with trigger similarity._
-**~900 - 1450:** History URL (Similarity/Prefix Match) - _Score based on URL/title similarity, visit/typed counts, and prefix matching._
+**~900 – 1450:** History URL (Similarity/Prefix Match) - _Score based on URL/title similarity, visit/typed counts, and prefix matching._
-**~600 - 1000:** Search Suggestion - _Fetched suggestions, ranked by provider order and similarity to input._
+**~600 – 1000:** Search Suggestion - _Fetched suggestions, ranked by provider order and similarity to input._
-**350 - 800:** Zero Suggest (Recent Tabs) - _Suggestions shown before typing, ranked by tab recency._
+**350 – 800:** Zero Suggest (Recent Tabs) - _Suggestions shown before typing, ranked by tab recency._
-**500 - 700:** Zero Suggest (Most Visited History) - _Suggestions shown before typing, ranked by visit count._
+**500 – 700:** Zero Suggest (Most Visited History) - _Suggestions shown before typing, ranked by visit count._
🧰 Tools
🪛 LanguageTool

[typographical] ~5-~5: If you want to indicate numerical ranges or time ranges, consider using an en dash.
Context: ...igher in the suggestion list. - ~1100 - 1500: Open Tab (Switch) - _Encourages ...

(DASH_RULE)


[typographical] ~6-~6: If you want to indicate numerical ranges or time ranges, consider using an en dash.
Context: ...les with title/URL similarity._ - 1400 - 1450+: History URL (Exact Match) - _Ve...

(DASH_RULE)


[typographical] ~8-~8: If you want to indicate numerical ranges or time ranges, consider using an en dash.
Context: ...ch for..." or typed URL entry._ - 1100 - 1200: Pedal - _Browser actions trigger...

(DASH_RULE)


[typographical] ~9-~9: If you want to indicate numerical ranges or time ranges, consider using an en dash.
Context: ...cales with trigger similarity._ - ~900 - 1450: History URL (Similarity/Prefix M...

(DASH_RULE)


[typographical] ~10-~10: If you want to indicate numerical ranges or time ranges, consider using an en dash.
Context: ...d counts, and prefix matching._ - ~600 - 1000: Search Suggestion - _Fetched sug...

(DASH_RULE)


[typographical] ~11-~11: If you want to indicate numerical ranges or time ranges, consider using an en dash.
Context: ... order and similarity to input._ - 350 - 800: Zero Suggest (Recent Tabs) - _Sug...

(DASH_RULE)


[typographical] ~12-~12: If you want to indicate numerical ranges or time ranges, consider using an en dash.
Context: ... typing, ranked by tab recency._ - 500 - 700: Zero Suggest (Most Visited Histor...

(DASH_RULE)

electron/ipc/main.ts (1)

1-21: Missing documentation for side-effect nature of imports

The file relies on side-effect imports (modules are executed and register handlers upon import), but doesn't document this intention explicitly. This might confuse developers who expect to see handler registrations in this file.

+ // This file serves as the central import point for all IPC handlers.
+ // Each imported module self-registers its IPC handlers when imported.
 // Browser APIs
 import "@/ipc/browser/browser";
 import "@/ipc/browser/tabs";
vite/public/edge-surf-game-v1/resources/js/base-error-reporting.js (1)

4-17: Consider namespacing to avoid global pollution

The function is defined in the global scope, which could lead to namespace conflicts in a complex web application environment.

-function hookErrorReporting(component) {
+// Namespace the function to avoid global pollution
+window.FlowBrowser = window.FlowBrowser || {};
+window.FlowBrowser.hookErrorReporting = function(component) {
   window.onerror = (message, source, lineno, columnNumber, error) => {
     const errorInfo = {
       column: columnNumber,
       component,
       line: lineno,
       message: error.message,
       name: error.name,
       source_url: source,
       stack: error.stack
     };
     chrome.errorReporting.reportError(errorInfo);
   };
 }
electron/browser/utility/menu/items/file.ts (1)

19-19: Consider removing unnecessary return statement

The return keyword before openNewTab(tabbedBrowserWindow) is unnecessary in a click handler since the return value isn't used by the Electron menu system.

-        return openNewTab(tabbedBrowserWindow);
+        openNewTab(tabbedBrowserWindow);
electron/browser/components/glance-modal.ts (2)

14-15: Consider extracting the hardcoded URL to a constant

The hardcoded URL "flow-internal://glance-modal/" should be extracted to a constant for better maintainability.

+const GLANCE_MODAL_URL = "flow-internal://glance-modal/";
+
 export class GlanceModal {
   public readonly view: WebContentsView;

   constructor() {
     const view = new WebContentsView({
       webPreferences: {
         transparent: true
       }
     });
     view.setBorderRadius(8);

     const webContents = view.webContents;
-    webContents.loadURL("flow-internal://glance-modal/");
+    webContents.loadURL(GLANCE_MODAL_URL);

29-31: Consider adding error handling in destroy method

The destroy method should handle potential errors when closing web contents.

 public destroy() {
-    this.view.webContents.close();
+    try {
+      this.view.webContents.close();
+    } catch (error) {
+      console.error('Error closing GlanceModal web contents:', error);
+    }
 }
electron/browser/utility/views.ts (1)

8-30: Add utility methods to enhance the ViewsManager functionality

Consider adding utility methods to improve the class's functionality, such as getting views by ID and cleaning up all views.

 export class ViewsManager {
   private window: BrowserWindow;
   private contentView: View;
   private views: Map<number, ViewData>;

   constructor(window: BrowserWindow) {
     this.window = window;
     this.contentView = window.contentView;
     this.views = new Map();
   }

   // ... existing methods ...

+  public has(view: WebContentsView): boolean {
+    return this.views.has(view.webContents.id);
+  }
+
+  public getViewById(id: number): View | undefined {
+    return this.views.get(id)?.view;
+  }
+
+  public clear() {
+    for (const [id, viewData] of this.views.entries()) {
+      this.contentView.removeChildView(viewData.view);
+      this.views.delete(id);
+    }
+  }
 }
electron/ipc/session/profiles.ts (1)

14-17: Remove debug logging before production deployment

The console.log statement should be removed as it's unnecessary in production code and may expose sensitive profile information in logs.

ipcMain.handle("profiles:update", async (event, profileId: string, profileData: Partial<ProfileData>) => {
-  console.log("Updating profile:", profileId, profileData);
  return await updateProfile(profileId, profileData);
});
electron/browser/utility/menu/items/archive.ts (2)

5-7: Consider renaming "Archive" menu to improve user understanding

The comment about renaming "Archive" to "History" or "Navigation" is valid. "Archive" is not a standard term for backward/forward navigation in browsers and may confuse users. "History" or "Navigation" would be more intuitive.

export const createArchiveMenu = (browser: Browser): MenuItemConstructorOptions => ({
-  label: "Archive", // Consider renaming to "History" or "Navigation" if more appropriate
+  label: "Navigation",
  submenu: [

5-33: Consider adding more navigation options to enhance menu functionality

The current implementation only covers basic forward/backward navigation. Consider enhancing this menu with additional navigation features like:

  • Home page navigation
  • Reload page
  • View history
  • Access to bookmarks

These would make the menu more useful and align better with standard browser navigation menus.

export const createArchiveMenu = (browser: Browser): MenuItemConstructorOptions => ({
  label: "Archive", // Consider renaming to "History" or "Navigation" if more appropriate
  submenu: [
    {
      label: "Go Back",
      accelerator: "CmdOrCtrl+Left",
      click: () => {
        const tabWc = getTabWcFromFocusedWindow(browser);
        if (!tabWc) return;
        // Check if back navigation is possible before calling goBack
        if (tabWc.canGoBack()) {
          tabWc.goBack();
        }
      }
    },
    {
      label: "Go Forward",
      accelerator: "CmdOrCtrl+Right",
      click: () => {
        const tabWc = getTabWcFromFocusedWindow(browser);
        if (!tabWc) return;
        // Check if forward navigation is possible before calling goForward
        if (tabWc.canGoForward()) {
          tabWc.goForward();
        }
      }
    },
+    { type: 'separator' },
+    {
+      label: "Reload",
+      accelerator: "CmdOrCtrl+R",
+      click: () => {
+        const tabWc = getTabWcFromFocusedWindow(browser);
+        if (!tabWc) return;
+        tabWc.reload();
+      }
+    },
+    {
+      label: "Home",
+      accelerator: "Alt+Home",
+      click: () => {
+        // Implementation for navigating to home page
+      }
+    }
  ]
});
electron/browser/utility/menu/items/edit.ts (1)

13-29: Well-implemented "Copy URL" feature

The "Copy URL" functionality is well-implemented with:

  • Proper keyboard shortcut (CmdOrCtrl+Shift+C)
  • Appropriate safety checks for window data and web contents
  • Clear clipboard operation

Consider implementing the TODO to show a notification to the user when the URL is copied. This would provide better feedback and improve user experience.

clipboard.writeText(url);
// TODO: Show notification to user that the URL has been copied
+ // Simple temporary solution:
+ tabWc.executeJavaScript(`
+   if (!window.flowNotificationTimeout) {
+     const notification = document.createElement('div');
+     notification.textContent = 'URL copied to clipboard';
+     notification.style.cssText = 'position:fixed;bottom:20px;left:50%;transform:translateX(-50%);background:#333;color:#fff;padding:8px 16px;border-radius:4px;z-index:9999;';
+     document.body.appendChild(notification);
+     window.flowNotificationTimeout = setTimeout(() => {
+       notification.remove();
+       delete window.flowNotificationTimeout;
+     }, 2000);
+   }
+ `);
electron/browser/utility/menu/items/view.ts (3)

29-32: Improve error handling for tab reload

Add error handling around the reload operation to ensure failures are properly logged and handled.

click: () => {
  const tabWc = getTabWcFromFocusedWindow(browser);
  if (!tabWc) return;
-  tabWc.reload();
+  try {
+    tabWc.reload();
+  } catch (error) {
+    console.error("Failed to reload tab:", error);
+  }
}

47-70: Simplify complex conditional logic for closing tab

The tab closing logic has multiple nested conditions which make it harder to read and maintain. Consider refactoring to improve readability.

click: () => {
  const winData = getFocusedWindowData();
  if (!winData) return;

  if (winData.type !== WindowType.BROWSER) {
    if (winData.window.closable) {
      winData.window.close();
    }
    return;
  }

  const browserWindow = winData.window;
-  if (browserWindow && isOmniboxOpen(browserWindow)) {
-    hideOmnibox(browserWindow);
-  } else {
-    const tab = getTab(browser, winData);
-    if (tab) {
-      tab.destroy();
-    } else {
-      if (winData.window) {
-        winData.window.close();
-      }
-    }
-  }
+  // Handle omnibox if it's open
+  if (browserWindow && isOmniboxOpen(browserWindow)) {
+    hideOmnibox(browserWindow);
+    return;
+  }
+  
+  // Try to close tab if it exists
+  const tab = getTab(browser, winData);
+  if (tab) {
+    tab.destroy();
+    return;
+  }
+  
+  // Fall back to closing the window
+  if (winData.window) {
+    winData.window.close();
+  }
}

76-79: Add error handling for developer tools toggle

Similar to the reload operation, add error handling around the toggleDevTools call.

click: () => {
  const tabWc = getTabWcFromFocusedWindow(browser);
  if (!tabWc) return;
-  tabWc.toggleDevTools();
+  try {
+    tabWc.toggleDevTools();
+  } catch (error) {
+    console.error("Failed to toggle developer tools:", error);
+  }
}
electron/ipc/app/new-tab.ts (1)

45-51: Strengthen error handling in IPC listener

The IPC listener doesn't have comprehensive error handling around the openNewTab operation.

-ipcMain.on("new-tab:open", (event) => {
-  const webContents = event.sender;
-  const win = browser?.getWindowFromWebContents(webContents);
-  if (!win) return;
-
-  return openNewTab(win);
-});
+ipcMain.on("new-tab:open", (event) => {
+  try {
+    const webContents = event.sender;
+    if (!browser) {
+      console.error("Browser is not initialized");
+      return;
+    }
+    
+    const win = browser.getWindowFromWebContents(webContents);
+    if (!win) {
+      console.error("Could not find window for web contents");
+      return;
+    }
+
+    openNewTab(win);
+  } catch (error) {
+    console.error("Error opening new tab:", error);
+  }
+});
electron/ipc/browser/page.ts (1)

15-21: Consider using ipcMain.handle for proper response handling

The current implementation uses ipcMain.on but returns null when a window isn't found. Since this return value isn't sent back to the renderer when using ipcMain.on, consider using ipcMain.handle instead for proper response handling.

-ipcMain.on("page:set-bounds", async (event, bounds: PageBounds) => {
+ipcMain.handle("page:set-bounds", async (event, bounds: PageBounds) => {
  const webContents = event.sender;
  const window = browser?.getWindowFromWebContents(webContents);
  if (!window) return null;

  window.setPageBounds(bounds);
+  return true;
});
electron/ipc/browser/navigation.ts (2)

4-17: Return value not sent to renderer

The handler returns boolean values but uses ipcMain.on instead of ipcMain.handle, meaning these return values aren't sent back to the renderer. If the renderer needs to know whether the navigation succeeded, consider using ipcMain.handle instead.

-ipcMain.on("navigation:go-to", (event, url: string, tabId?: number) => {
+ipcMain.handle("navigation:go-to", async (event, url: string, tabId?: number) => {
  const webContents = event.sender;
  const window = browser?.getWindowFromWebContents(webContents);
  if (!window) return false;

  const currentSpace = window.getCurrentSpace();
  if (!currentSpace) return false;

  const tab = tabId ? browser?.getTabFromId(tabId) : browser?.tabs.getFocusedTab(window.id, currentSpace);
  if (!tab) return false;

  tab.loadURL(url);
  return true;
});

49-54: Unused return value

The return value from tab.webContents?.navigationHistory?.goToIndex(index) isn't being used since this is an ipcMain.on handler, not a handle. Consider either removing the return statement or using ipcMain.handle if the renderer needs the result.

-ipcMain.on("navigation:go-to-entry", (event, tabId: number, index: number) => {
+ipcMain.on("navigation:go-to-entry", (event, tabId: number, index: number) => {
  const tab = browser?.getTabFromId(tabId);
  if (!tab) return;

-  return tab.webContents?.navigationHistory?.goToIndex(index);
+  tab.webContents?.navigationHistory?.goToIndex(index);
});
electron/onboarding/main.ts (1)

36-41: Return type can be tightened & Promise leakage avoided
createOnboardingWindow() currently returns Promise<any>. Give callers a concrete contract and avoid an edge‑case where ready-to-show fires before the listener is attached:

-function createOnboardingWindow() {
+function createOnboardingWindow(): Promise<BrowserWindow> {
   ...
-  return new Promise((resolve) => {
-    window.once("ready-to-show", () => {
-      resolve(window);
-    });
-  });
+  return new Promise<BrowserWindow>((resolve) => {
+    if (window.isReadyToShow()) {
+      resolve(window);
+    } else {
+      window.once("ready-to-show", () => resolve(window));
+    }
+  });
 }
electron/saving/open-external.ts (2)

5-16: Key derivation ignores path & query – risk of over‑broad permissions
getKey() collapses the whole requesting URL to only protocol//host.
Example: allowing https://evil.example.com will also whitelist https://evil.example.com/suspicious?download=exe.
If the intention is to scope by origin and path you should include url.pathname (and maybe .port separately) when constructing the key.

-  const minifiedUrl = `${url.protocol}//${url.host}`;
+  // Include pathname to avoid over‑broad matches
+  const minifiedUrl = `${url.protocol}//${url.host}${url.pathname}`;

[security]


34-50: Unsafe cast to boolean & silent error swallowing
filter(Boolean) coerces every object to true; you rely on preceding return null to drop invalid entries but any accidental non‑object truthy value (e.g., string "true") leaks through.
Also the catch block discards decoding errors – consider logging for diagnosis.

-    .filter(Boolean);
+    .filter((v): v is {requestingURL:string;openingProtocol:string} => v !== null);
electron/index.ts (2)

104-110: Suspicious double‑window access – probably a typo
window.window.focus() suggests window is an object wrapping BrowserWindow.
If so, prefer exposing a focus() helper or property to avoid leaking internal structure & to future‑proof refactors:

-        window.window.focus();
+        window.focus();

138-144: Duplicate async call – small perf optimisation
hasCompletedOnboarding() is executed once at startup and again on window-all-closed.
Cache its resolved value (or listen for onboarding‑completed event) to avoid touching disk twice.

docs/api/browser.md (1)

19-19: Minor grammatical issue in constructor description.

The sentence structure suggests "Automatically creates" should be "It automatically creates" to maintain subject-verb agreement.

-Creates a new Browser instance and initializes the window and profile managers. Automatically creates the initial window after initialization.
+Creates a new Browser instance and initializes the window and profile managers. It automatically creates the initial window after initialization.
🧰 Tools
🪛 LanguageTool

[grammar] ~19-~19: Possible subject-verb agreement error.
Context: ...instance and initializes the window and profile managers. Automatically creates the ini...

(IS_AND_ARE)

electron/ipc/session/spaces.ts (1)

18-61: Add error handling to IPC handlers.

The current IPC handlers directly pass through to the underlying functions without explicit error handling. While the underlying functions may handle errors internally, adding try-catch blocks would ensure IPC communication remains robust even if unexpected errors occur.

Here's an example pattern to apply:

ipcMain.handle("spaces:get-all", async (event) => {
+  try {
    return await getSpaces();
+  } catch (error) {
+    console.error("Error in spaces:get-all handler:", error);
+    return [];
+  }
});

This pattern could be applied to all handlers based on their expected return values.

vite/public/edge-surf-game-v1/resources/js/assert.js (1)

85-85: Unexpected console warning about non-JS module files.

This warning message references a Chrome bug ID and appears to be unrelated to this JavaScript module. It might be a leftover from another context or code migration.

Consider removing this warning if it's not applicable to this file, or adding a comment explaining its relevance if it's intentionally included.

electron/browser/utility/hot-reload.ts (2)

14-33: Development server detection with state caching.

The implementation checks if the development server is running and caches the result, which is efficient. However, the error handling could be improved.

Consider logging the error details to help with debugging:

    .catch((error) => {
      isDevServerRunning = false;
+     if (!app.isPackaged) {
+       console.debug('Development server not running:', error.message);
+     }
      return false;
    });

63-77: Busy-wait approach for request throttling.

The current implementation uses a busy-wait approach with randomized timeouts to manage concurrency. While it works, it could be more efficient.

Consider using a queue-based approach or a semaphore pattern for more efficient request throttling:

- while (amountOfRequests >= MAX_REQUESTS) {
-   await new Promise((resolve) => setTimeout(resolve, getRandomTimeout()));
- }
- 
- amountOfRequests++;
+ const semaphore = {
+   acquire: async () => {
+     while (amountOfRequests >= MAX_REQUESTS) {
+       await new Promise(resolve => setTimeout(resolve, getRandomTimeout()));
+     }
+     amountOfRequests++;
+   },
+   release: () => {
+     amountOfRequests--;
+   }
+ };
+ 
+ await semaphore.acquire();

And later:

- setTimeout(() => {
-   amountOfRequests--;
- }, getRandomTimeout());
+ setTimeout(() => {
+   semaphore.release();
+ }, getRandomTimeout());
electron/browser/utility/menu/helpers.ts (3)

1-4: Good imports, but unused dependency.

The file imports the necessary modules, but getSpace from @/sessions/spaces is imported but never used in this file.

Remove the unused import:

-import { getSpace } from "@/sessions/spaces";

6-10: Redundant wrapper function for getFocusedWindow.

The getFocusedWindowData function doesn't add significant value over the directly imported getFocusedWindow function.

Consider adding more functionality to justify this wrapper or use the imported function directly where needed.


12-21: Missing TypeScript return type annotations.

The function lacks explicit return type annotations, which would improve type safety and documentation.

Add explicit return types:

-export const getFocusedBrowserWindowData = () => {
+export const getFocusedBrowserWindowData = (): WindowData | null => {
electron/modules/icons.ts (3)

1-1: Remove unused ipcMain import
ipcMain is no longer referenced after the IPC handlers were moved to a dedicated module, so this import is now dead code. Eliminating it avoids potential linter warnings and keeps the dependency list tidy.

-import { app, ipcMain, NativeImage, nativeImage } from "electron";
+import { app, NativeImage, nativeImage } from "electron";

73-83: Avoid synchronous file I/O during icon transformation
fs.readFileSync blocks the main thread during start‑up and every icon change. Switching to fs.promises.readFile (or await fs.promises.readFile) keeps the event loop responsive, which matters on slower disks or when the image is large.

-    const inputBuffer = fs.readFileSync(imagePath);
+    const inputBuffer = await fs.promises.readFile(imagePath);

Also applies to: 110-113


175-182: Defer initial icon work until after app.whenReady()
setAppIcon("default") performs an expensive Sharp transform and may try to set the dock icon before Electron is ready. Wrapping it in app.whenReady() prevents unnecessary early processing and eliminates the (small) risk of calling macOS‑only APIs too early.

-setAppIcon("default").catch((error) => {
-  debugError("ICONS", "Failed initial setAppIcon call:", error);
-});
+app.whenReady().then(() =>
+  setAppIcon("default").catch((error) => {
+    debugError("ICONS", "Failed initial setAppIcon call:", error);
+  })
+);
electron/ipc/browser/tabs.ts (1)

48-55: Remove dead windowProfiles accumulation
windowProfiles is populated but never consumed. Keeping unused variables around increases cognitive load and may trigger linter warnings.

-  const windowProfiles: string[] = [];
-  const windowSpaces: string[] = [];
+  const windowSpaces: string[] = [];
electron/browser/utility/menu/items/spaces.ts (2)

1-5: Remove opinionated comments from production code
Lines 1‑4 carry a personal rant about Lucide’s naming scheme. Such comments can feel unprofessional and clutter the codebase. Recommend deleting or moving to a GitHub discussion.


114-118: browser parameter is currently unused
createSpacesMenu receives a Browser instance but never touches it. Either use it (e.g., for window retrieval) or drop the parameter to avoid misleading signatures.

electron/browser/window-manager.ts (3)

34-48: Simplify error handling in createWindow

The try/catch block in createWindow just rethrows the error without adding any value. This creates unnecessary code complexity.

  public createWindow(
    browser: Browser,
    type: BrowserWindowType = "normal",
    options: BrowserWindowCreationOptions = {}
  ): TabbedBrowserWindow {
-   try {
-     const window = new TabbedBrowserWindow(browser, type, options);
-     this.windows.set(window.id, window);
-
-     window.on("destroy", () => {
-       this.windows.delete(window.id);
-       this.eventEmitter.emit("window-destroyed", window);
-     });
-
-     this.eventEmitter.emit("window-created", window);
-     return window;
-   } catch (error) {
-     throw error;
-   }
+   const window = new TabbedBrowserWindow(browser, type, options);
+   this.windows.set(window.id, window);
+
+   window.on("destroy", () => {
+     this.windows.delete(window.id);
+     this.eventEmitter.emit("window-destroyed", window);
+   });
+
+   this.eventEmitter.emit("window-created", window);
+   return window;
  }
🧰 Tools
🪛 Biome (1.9.4)

[error] 46-46: The catch clause that only rethrows the original error is useless.

An unnecessary catch clause can be confusing.
Unsafe fix: Remove the try/catch clause.

(lint/complexity/noUselessCatch)


67-83: Add null check and early return to getWindowFromWebContents method

The method should validate if webContents is null or undefined before attempting to use it to prevent potential runtime errors.

  public getWindowFromWebContents(webContents: WebContents): TabbedBrowserWindow | null {
+   if (!webContents) {
+     return null;
+   }
+   
    for (const window of this.windows.values()) {
      for (const windowWebContents of window.coreWebContents) {
        if (webContents.id === windowWebContents.id) {
          return window;
        }
      }

      // Temporary solution for tabs in the window
      for (const windowWebContents of window.window.contentView.children) {
        if (windowWebContents instanceof WebContentsView && webContents.id === windowWebContents.webContents.id) {
          return window;
        }
      }
    }
    return null;
  }

17-24: Consider adding event documentation

The class emits events via the eventEmitter but doesn't document what events are available and their payload types.

Add JSDoc comments that describe what events the WindowManager emits through the BrowserEvents interface, such as "window-created" and "window-destroyed".

electron/browser/view-manager.ts (2)

36-38: Add hasView method to check if a view is managed

The class currently doesn't provide a way to check if a view is being managed without retrieving its z-index.

  getViewZIndex(view: View): number | undefined {
    return this.views.get(view);
  }
+
+ hasView(view: View): boolean {
+   return this.views.has(view);
+ }

57-81: Optimize and improve error handling in reorderViews method

The current implementation adds all views back to the parent, which might be inefficient. It also doesn't check if a view is already in the parent before adding it.

  private reorderViews(): void {
    // Sort views by zIndex, lowest first
    const sortedViews = Array.from(this.views.entries()).sort(([, aIndex], [, bIndex]) => aIndex - bIndex);

+   // First remove all views from parent to ensure clean state
+   sortedViews.forEach(([view]) => {
+     try {
+       this.parentView.removeChildView(view);
+     } catch (error) {
+       // View might already be removed or invalid
+       console.warn(`Failed to remove view during reorder preparation:`, error);
+     }
+   });

    // Add views back in order. addChildView brings the added view to the top
    // relative to its siblings managed by this parent.
    // Adding lowest zIndex first means highest zIndex will end up visually on top.
    sortedViews.forEach(([view]) => {
      try {
        // Check if view is still valid (not destroyed, etc.) - View API has no direct 'isDestroyed'
        // Rely on addChildView potentially throwing an error if the view is invalid
        this.parentView.addChildView(view);
      } catch (error) {
        console.error(`Failed to add/reorder view during reorder:`, error);
        // Attempt to find the ID for the failed view to remove it from the map
-       const failedViewEntry = Array.from(this.views.entries()).find(([, zIndex]) => zIndex === zIndex);
+       const failedViewEntry = Array.from(this.views.entries()).find(([v]) => v === view);
        if (failedViewEntry) {
          console.error(`Removing view with ID ${failedViewEntry[0]} from manager due to reorder error.`);
          this.views.delete(failedViewEntry[0]);
        } else {
          console.error(`Could not find ID for the failed view during reorder.`);
        }
      }
    });
  }
🧰 Tools
🪛 Biome (1.9.4)

[error] 72-72: Comparing to itself is potentially pointless.

(lint/suspicious/noSelfCompare)

electron/browser/components/omnibox.ts (3)

18-56: Fix inconsistent variable naming in constructor

The constructor uses "onmiboxView" and "onmiboxWC" instead of "omniboxView" and "omniboxWC", creating a naming inconsistency.

  constructor(parentWindow: BrowserWindow) {
    debugPrint("OMNIBOX", `Creating new omnibox for window ${parentWindow.id}`);
-   const onmiboxView = new WebContentsView({
+   const omniboxView = new WebContentsView({
      webPreferences: {
        transparent: true
      }
    });
-   const onmiboxWC = onmiboxView.webContents;
+   const omniboxWC = omniboxView.webContents;

-   onmiboxView.setBorderRadius(13);
+   omniboxView.setBorderRadius(13);

    // on focus lost, hide omnibox
-   onmiboxWC.on("blur", () => {
+   omniboxWC.on("blur", () => {
      debugPrint("OMNIBOX", "WebContents blur event received");
      this.maybeHide();
    });
    parentWindow.on("resize", () => {
      debugPrint("OMNIBOX", "Parent window resize event received");
      this.updateBounds();
    });

    // on window focus, focus omnibox if showing
    parentWindow.on("focus", () => {
      debugPrint("OMNIBOX", "Parent window focus event received");
      this.refocus();
    });

    setTimeout(() => {
      this.loadInterface(null);
      this.updateBounds();
      this.hide();
    }, 0);

    omniboxes.set(parentWindow, this);

-   this.view = onmiboxView;
-   this.webContents = onmiboxWC;
+   this.view = omniboxView;
+   this.webContents = omniboxWC;
    this.window = parentWindow;
  }

163-190: Add consistent checks for destroyed state in maybeHide method

The maybeHide method has inconsistent checks for destroyed windows. It would be more robust to check all cases consistently.

  maybeHide() {
    if (this.window.isDestroyed()) {
      return;
    }

    this.assertNotDestroyed();

    // Keep open if webContents is being inspected
-   if (!this.window.isDestroyed() && this.webContents.isDevToolsOpened()) {
+   if (this.webContents.isDevToolsOpened()) {
      debugPrint("OMNIBOX", "preventing close due to DevTools being open");
      return;
    }

    // The user may need to access a
    // program outside of the app. Closing the popup would then add
    // inconvenience.
    if (browser) {
      const hasFocus = browser.getWindows().some((win) => {
        if (win.window.isDestroyed()) {
          return false;
        }
        return win.window.isFocused();
      });
      if (!hasFocus) {
        debugPrint("OMNIBOX", "preventing close due to focus residing outside of the app");
        return;
      }
    }

    // All conditions passed, hide omnibox
    debugPrint("OMNIBOX", "All conditions passed, hiding omnibox");
    this.hide();
  }

68-70: Fix variable name inconsistency in loadInterface method

The loadInterface method uses "onmiboxWC" instead of "omniboxWC", creating a naming inconsistency.

  loadInterface(params: QueryParams | null) {
    this.assertNotDestroyed();

    debugPrint("OMNIBOX", `Loading interface with params: ${JSON.stringify(params)}`);
-   const onmiboxWC = this.webContents;
+   const omniboxWC = this.webContents;

    const url = new URL("flow-internal://omnibox/");

Fix this inconsistency throughout the method:

    const urlString = url.toString();
-   if (onmiboxWC.getURL() !== urlString) {
+   if (omniboxWC.getURL() !== urlString) {
      debugPrint("OMNIBOX", `Loading new URL: ${urlString}`);
-     onmiboxWC.loadURL(urlString);
+     omniboxWC.loadURL(urlString);
    } else {
      debugPrint("OMNIBOX", "Reloading current URL");
-     onmiboxWC.reload();
+     omniboxWC.reload();
    }
vite/public/edge-surf-game-v1/resources/js/parse_html_subset.js (1)

13-25: Guard against missing Trusted‑Types support

toTrustedHtml assumes the global trustedTypes object is always present. If this helper is invoked in a non‑Chromium environment (e.g. Node‑based unit tests) it will throw a ReferenceError.

Consider returning the input unchanged when window.trustedTypes (or trustedTypes) is not available.

electron/saving/settings.ts (1)

14-44: DRY up duplicated caching logic

newTabMode and sidebarCollapseMode follow the exact same read‑cache‑validate‑persist pattern. Extracting a small generic helper would:

• eliminate duplication
• align validation/persistence behaviour automatically for future settings
• make unit‑testing easier

Example shape (pseudo‑code):

async function loadSetting<T>(
  key: string,
  schema: z.ZodType<T>,
  defaultValue: T,
): Promise<T> {  }

Then each setting becomes a one‑liner.

Also applies to: 46-80

electron/modules/favicons.ts (2)

400-410: Docstring no longer matches implementation

The comment above normalizeURL still explains only trailing‑slash / protocol logic, but the function now also strips query, hash and (behind a flag) the path. Update the doc so future maintainers aren’t surprised by cache misses.


475-479: Use error codes instead of fragile string matching

Relying on the exact wording "ClientRequest only supports http: and https: protocols" is brittle and locale‑dependent. Prefer checking error.code === 'ERR_INVALID_PROTOCOL' (or similar) if Electron exposes one.

electron/browser/utility/protocols.ts (2)

80-89: Avoid per‑request dev‑server pings

isDevelopmentServerRunning() is called on every asset request when
hot‑reload is enabled. In dev mode a single page load can easily
generate hundreds of requests, turning the ping into a bottleneck.

Cache the result for a short interval or compute it once at startup
to shave noticeable latency off the development experience.
[performance]


170-200: Double‑check asset path normalisation

Good job using path.normalize() and a prefix check!
One tiny nit: prepend assetsDir + path.sep (like in the previous
comment) so that a sibling path such as
${assetsDir}-evil cannot pass the startsWith test.

electron/browser/tabs/tab-bounds.ts (3)

5-6: Remove dead constant

USE_IMMEDIATE is declared but never used after the rewrite.

-const USE_IMMEDIATE = false;

Deleting unused code avoids reader confusion and keeps bundle size
tight.


78-96: Prefer setInterval or requestAnimationFrame for steady frame loops

Manually chaining setTimeout introduces drift because each callback
fires after execution time plus the requested delay.
Using setInterval (or requestAnimationFrame when a view is attached
to a BrowserWindow) keeps spacing more uniform and simplifies
cancellation:

-this.animationFrameId = setTimeout(loop, MS_PER_FRAME);
+this.animationFrameId = setInterval(loop, MS_PER_FRAME);

Remember to clearInterval in stopAnimationLoop().
[performance]


210-239: Potential instability from explicit Euler integration

The spring system advances position with:

this.bounds[dim] += velocity * dt
velocity += acceleration * dt

Explicit Euler can overshoot or oscillate at high stiffness /
framerates. A semi‑implicit (symplectic) step is nearly free and far
more stable:

this.velocity[dim] += acceleration * deltaTime;
this.bounds[dim] += this.velocity[dim] * deltaTime;

(Swap the two lines.)

Not urgent, but worth considering if you observe jitter in large window
moves.

vite/public/edge-surf-game-v1/resources/js/load_time_data.js (1)

213-216: Suppress Biome false‑positive or hard‑code the allowed typeof values

Biome warns that typeof … === type uses a non‑literal on line 215.
This is intentional here, but you can silence or fix the rule:

Option A – inline ignore

// biome-ignore lint/suspicious/useValidTypeof
expect(typeof value === type, );

Option B – validate against the canonical set of typeof strings before
comparison.

🧰 Tools
🪛 Biome (1.9.4)

[error] 215-215: Invalid typeof comparison value: this expression is not a string literal

not a string literal

(lint/suspicious/useValidTypeof)

docs/api/tabs/tab.md (3)

51-65: Clarify view and webContents typings

The docs list view as PatchedWebContentsView but the class name is never introduced in the public API section (nor elsewhere in the repo, judging from the context).
• If PatchedWebContentsView is an internal alias, expose/define it up‑front or remove the “Patched” prefix in public docs so consumers know they can safely rely on the vanilla Electron WebContentsView.
• Likewise, the relationship between view and webContents could use a short sentence explaining that webContents is available via view.webContents, to avoid newcomers accidentally manipulating them out of sync.

🧰 Tools
🪛 LanguageTool

[style] ~53-~53: To form a complete sentence, be sure to include a subject.
Context: ...d: (string) The associated space ID. Can be updated. - visible: (boolean`) Wh...

(MISSING_IT_THERE)


68-77: Bullet list ⇒ definition list for readability

The “Key Methods” section repeats the pattern
- method(): description
which renders as a plain bullet list; Markdown engines wrap lines so long signatures become hard to scan.

A cleaner style is a definition list (supported by GitHub-flavoured MD):

**setWindow(window: TabbedBrowserWindow | null)**  
Attaches the tab’s view…

**loadURL(url: string, replace?: boolean)**  
Loads the specified URL…

This preserves monospace formatting for the signature while keeping the description on a new line.

🧰 Tools
🪛 LanguageTool

[uncategorized] ~68-~68: Loose punctuation mark.
Context: ...dow(window: TabbedBrowserWindow | null)`: Attaches the tab's view to a given wind...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~69-~69: Loose punctuation mark.
Context: ...loadURL(url: string, replace?: boolean)`: Loads the specified URL in the tab. If ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~70-~70: Loose punctuation mark.
Context: ...rorPage(errorCode: number, url: string)`: Loads a custom error page for the given...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~71-~71: Loose punctuation mark.
Context: ...al URL. - setLayout(layout: TabLayout): Sets the tab's layout configuration and...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~72-~72: Loose punctuation mark.
Context: ...and updates the view. - updateLayout(): Recalculates and applies the view's bou...

(UNLIKELY_OPENING_PUNCTUATION)


[style] ~72-~72: To form a complete sentence, be sure to include a subject.
Context: ...current layout and window dimensions. Should be called when the window resizes or la...

(MISSING_IT_THERE)


[uncategorized] ~73-~73: Loose punctuation mark.
Context: ... or layout changes. - updateTabState(): Reads the current state (title, URL, lo...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~74-~74: Loose punctuation mark.
Context: ...f changed, false otherwise. - show(): Makes the tab's view visible. - `hide()...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~75-~75: Loose punctuation mark.
Context: ...Makes the tab's view visible. - hide(): Hides the tab's view. - destroy(): Cl...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~76-~76: Loose punctuation mark.
Context: ...(): Hides the tab's view. - destroy()`: Cleans up resources, removes the view, ...

(UNLIKELY_OPENING_PUNCTUATION)


86-90: Misleading “Internal Helpers” headline

Everything under this section is still part of the public interface because it is documented here.
Either:

  1. Move these helpers to a dedicated “Internal design notes” page that’s excluded from generated API docs, or
  2. Mark them with a disclaimer such as “⚠️ Internal – subject to change without notice”.

Otherwise library users may assume long‑term stability and tight‑couple to them.

🧰 Tools
🪛 LanguageTool

[uncategorized] ~88-~88: Loose punctuation mark.
Context: ...nal Helpers - createWebContentsView(): Factory function used internally by the...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~89-~89: Loose punctuation mark.
Context: ...ipt, session). - setupEventListeners(): Sets up listeners on the webContents ...

(UNLIKELY_OPENING_PUNCTUATION)

electron/browser/window.ts (1)

74-81: Duplicate full‑screen events in rapid succession

Both Electron’s "enter-full-screen" and "leave-full-screen" events can fire multiple times on some platforms.
Debounce or ignore duplicates to prevent flooding listeners (e.g. React state updates). A simple timestamp check or lodash.throttle wrapper would suffice.

vite/public/edge-surf-game-v1/resources/js/cr.js (2)

11-13: Remove redundant "use strict" directive

ES modules (or code transpiled/bundled as modules) are automatically executed in strict‑mode, so the explicit directive is unnecessary and flagged by Biome.
Keeping it may look harmless, but multiple redundant directives across bundled files add noise and can even confuse some concatenation tools.

-  'use strict';
🧰 Tools
🪛 Biome (1.9.4)

[error] 12-12: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)


[error] 11-11: This variable is used before its declaration.

The variable is declared here:

(lint/correctness/noInvalidUseBeforeDeclaration)


213-223: Deprecated __defineGetter__/__defineSetter__ usage

These non‑standard APIs are deprecated and disallowed in strict ESLint
configs. Modern browsers (and Node) support Object.defineProperty
everywhere.

The surrounding comment hints at a future migration; consider prioritising it,
otherwise bundlers that tree‑shake “restricted‑properties” break builds.

electron/browser/tabs/tab.ts (1)

304-308: electron-context-menu expects a BrowserWindow, not WebContents

Passing webContents works at runtime only because the library loosely
checks the object shape, but TypeScript will flag this and future API
changes could break it. Supply the parent window instead:

-contextMenu({ window: webContents });
+contextMenu({ window: this.window.window });
vite/public/edge-surf-game-v1/resources/css/interface.css (1)

287-289: Empty style rule can be removed

#notify-shareText {} is empty and triggers Biome’s noEmptyBlock.
Delete it or add the missing declarations.

-#notify-shareText {
-}
🧰 Tools
🪛 Biome (1.9.4)

[error] 287-288: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)

electron/browser/tabs/tab-manager.ts (2)

244-253: Unbounded activation‑history may grow indefinitely

spaceActivationHistory is appended on every activation but never pruned.
Long‑running sessions with many tabs/groups can accumulate thousands of entries and increase memory usage.

Consider capping the history per space or periodically pruning invalid IDs:

-    history.push(idToStore);
+    history.push(idToStore);
+    const MAX_HISTORY = 50; // configurable
+    if (history.length > MAX_HISTORY) {
+      history.splice(0, history.length - MAX_HISTORY);
+    }

651-667: Remove unused changed flag

The local variable changed is written but never read, generating dead code and minor cognitive overhead.

-    let changed = false;
     for (const [key, history] of this.spaceActivationHistory.entries()) {
       …
-        changed = true; // Mark that a change occurred (optional)
       }
     }
-    // Method doesn't need to return anything, just modifies the map
+    // No return value needed
   }
docs/references/omnibox.md (1)

182-189: Minor grammar fix: “Machine‑Learning‑based”

“There is no complex cross‑provider scoring or Machine Learning model…”

Prefer hyphenation for compound adjectives:

- Machine Learning model
+ machine‑learning model
🧰 Tools
🪛 LanguageTool

[grammar] ~185-~185: Did you mean “to”?
Context: ...vider scoring or Machine Learning model as found in browsers like Chrome. - **Dedu...

(LEARN_NNNNS_ON_DO)

electron/browser/browser.ts (1)

22-25: Avoid duplicate references to the same manager

private readonly tabManager is already declared (line 22). Exposing it publicly again through public tabs (line 24) creates two mutable references that can easily diverge if someone accidentally re‑assigns one of them. Prefer a single readonly field:

-  private readonly tabManager: TabManager;
-  private _isDestroyed: boolean = false;
-  public tabs: TabManager;
+  public readonly tabs: TabManager;
+  private _isDestroyed = false;

This keeps the surface area minimal and eliminates the risk of state drift.

electron/preload.ts (1)

11-33: Cache the permission matrix

checkCanUseAPI() re‑evaluates location and allocates a fresh object every time a wrapper is called. Given the large number of wrappers, this is unnecessary overhead. Compute once at module load and reuse:

const CAN_USE = computePermissions();
function computePermissions() { ... }
function can(api: keyof typeof CAN_USE) {
  return CAN_USE[api];
}

Replace checkCanUseAPI().browser with can("browser"), etc.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2d433c2 and 0b298c3.

⛔ Files ignored due to path filters (75)
  • .DS_Store is excluded by !**/.DS_Store
  • assets/screenshots/beta-1.png is excluded by !**/*.png
  • assets/screenshots/beta-2.png is excluded by !**/*.png
  • assets/screenshots/beta-3.png is excluded by !**/*.png
  • assets/screenshots/beta-4.png is excluded by !**/*.png
  • assets/screenshots/beta-browser-1.png is excluded by !**/*.png
  • assets/screenshots/beta-command-1.png is excluded by !**/*.png
  • assets/screenshots/beta-newtab-1.png is excluded by !**/*.png
  • assets/screenshots/beta-onboarding-1.png is excluded by !**/*.png
  • assets/screenshots/beta-settings-1.png is excluded by !**/*.png
  • bun.lock is excluded by !**/*.lock
  • vite/bun.lock is excluded by !**/*.lock
  • vite/public/assets/favicon.ico is excluded by !**/*.ico
  • vite/public/assets/icon.png is excluded by !**/*.png
  • vite/public/chrome-dino-game/favicon.ico is excluded by !**/*.ico
  • vite/public/chrome-dino-game/icons/icon-114.png is excluded by !**/*.png
  • vite/public/chrome-dino-game/icons/icon-128.png is excluded by !**/*.png
  • vite/public/chrome-dino-game/icons/icon-16.png is excluded by !**/*.png
  • vite/public/chrome-dino-game/icons/icon-256.png is excluded by !**/*.png
  • vite/public/chrome-dino-game/icons/icon-32.png is excluded by !**/*.png
  • vite/public/chrome-dino-game/images/default_100_percent/offline/100-disabled.png is excluded by !**/*.png
  • vite/public/chrome-dino-game/images/default_100_percent/offline/100-error-offline.png is excluded by !**/*.png
  • vite/public/chrome-dino-game/images/default_100_percent/offline/100-offline-sprite.png is excluded by !**/*.png
  • vite/public/chrome-dino-game/images/default_100_percent/offline/100-olympic-firemedal-sprite.png is excluded by !**/*.png
  • vite/public/chrome-dino-game/images/default_100_percent/offline/100-olympics-equestrian-sprite.png is excluded by !**/*.png
  • vite/public/chrome-dino-game/images/default_100_percent/offline/100-olympics-gymnastics-sprite.png is excluded by !**/*.png
  • vite/public/chrome-dino-game/images/default_100_percent/offline/100-olympics-hurdling-sprite.png is excluded by !**/*.png
  • vite/public/chrome-dino-game/images/default_100_percent/offline/100-olympics-surfing-sprite.png is excluded by !**/*.png
  • vite/public/chrome-dino-game/images/default_100_percent/offline/100-olympics-swimming-sprite.png is excluded by !**/*.png
  • vite/public/chrome-dino-game/images/default_200_percent/offline/200-disabled.png is excluded by !**/*.png
  • vite/public/chrome-dino-game/images/default_200_percent/offline/200-error-offline.png is excluded by !**/*.png
  • vite/public/chrome-dino-game/images/default_200_percent/offline/200-offline-sprite.png is excluded by !**/*.png
  • vite/public/chrome-dino-game/images/default_200_percent/offline/200-olympic-firemedal-sprite.png is excluded by !**/*.png
  • vite/public/chrome-dino-game/images/default_200_percent/offline/200-olympics-equestrian-sprite.png is excluded by !**/*.png
  • vite/public/chrome-dino-game/images/default_200_percent/offline/200-olympics-gymnastics-sprite.png is excluded by !**/*.png
  • vite/public/chrome-dino-game/images/default_200_percent/offline/200-olympics-hurdling-sprite.png is excluded by !**/*.png
  • vite/public/chrome-dino-game/images/default_200_percent/offline/200-olympics-surfing-sprite.png is excluded by !**/*.png
  • vite/public/chrome-dino-game/images/default_200_percent/offline/200-olympics-swimming-sprite.png is excluded by !**/*.png
  • vite/public/edge-surf-game-v1/resources/icons/android-icon-144x144.png is excluded by !**/*.png
  • vite/public/edge-surf-game-v1/resources/icons/android-icon-192x192.png is excluded by !**/*.png
  • vite/public/edge-surf-game-v1/resources/icons/android-icon-36x36.png is excluded by !**/*.png
  • vite/public/edge-surf-game-v1/resources/icons/android-icon-48x48.png is excluded by !**/*.png
  • vite/public/edge-surf-game-v1/resources/icons/android-icon-72x72.png is excluded by !**/*.png
  • vite/public/edge-surf-game-v1/resources/icons/android-icon-96x96.png is excluded by !**/*.png
  • vite/public/edge-surf-game-v1/resources/icons/apple-icon-114x114.png is excluded by !**/*.png
  • vite/public/edge-surf-game-v1/resources/icons/apple-icon-120x120.png is excluded by !**/*.png
  • vite/public/edge-surf-game-v1/resources/icons/apple-icon-144x144.png is excluded by !**/*.png
  • vite/public/edge-surf-game-v1/resources/icons/apple-icon-152x152.png is excluded by !**/*.png
  • vite/public/edge-surf-game-v1/resources/icons/apple-icon-180x180.png is excluded by !**/*.png
  • vite/public/edge-surf-game-v1/resources/icons/apple-icon-57x57.png is excluded by !**/*.png
  • vite/public/edge-surf-game-v1/resources/icons/apple-icon-60x60.png is excluded by !**/*.png
  • vite/public/edge-surf-game-v1/resources/icons/apple-icon-72x72.png is excluded by !**/*.png
  • vite/public/edge-surf-game-v1/resources/icons/apple-icon-76x76.png is excluded by !**/*.png
  • vite/public/edge-surf-game-v1/resources/icons/apple-icon-precomposed.png is excluded by !**/*.png
  • vite/public/edge-surf-game-v1/resources/icons/apple-icon.png is excluded by !**/*.png
  • vite/public/edge-surf-game-v1/resources/icons/favicon.png is excluded by !**/*.png
  • vite/public/edge-surf-game-v1/resources/icons/favicon.svg is excluded by !**/*.svg
  • vite/public/edge-surf-game-v1/resources/icons/ms-icon-144x144.png is excluded by !**/*.png
  • vite/public/edge-surf-game-v1/resources/icons/ms-icon-150x150.png is excluded by !**/*.png
  • vite/public/edge-surf-game-v1/resources/icons/ms-icon-310x310.png is excluded by !**/*.png
  • vite/public/edge-surf-game-v1/resources/icons/ms-icon-70x70.png is excluded by !**/*.png
  • vite/public/edge-surf-game-v1/resources/ski/bg.png is excluded by !**/*.png
  • vite/public/edge-surf-game-v1/resources/ski/objects.png is excluded by !**/*.png
  • vite/public/edge-surf-game-v1/resources/ski/player.png is excluded by !**/*.png
  • vite/public/edge-surf-game-v1/resources/surf/bg.png is excluded by !**/*.png
  • vite/public/edge-surf-game-v1/resources/surf/objects.png is excluded by !**/*.png
  • vite/public/edge-surf-game-v1/resources/surf/player.png is excluded by !**/*.png
  • vite/public/edge-surf-game-v2/favicon.png is excluded by !**/*.png
  • vite/public/edge-surf-game-v2/favicon.svg is excluded by !**/*.svg
  • vite/public/edge-surf-game-v2/icons/icon-114.png is excluded by !**/*.png
  • vite/public/edge-surf-game-v2/icons/icon-128.png is excluded by !**/*.png
  • vite/public/edge-surf-game-v2/icons/icon-16.png is excluded by !**/*.png
  • vite/public/edge-surf-game-v2/icons/icon-256.png is excluded by !**/*.png
  • vite/public/edge-surf-game-v2/icons/icon-32.png is excluded by !**/*.png
  • vite/src/assets/react.svg is excluded by !**/*.svg
📒 Files selected for processing (107)
  • .gitignore (1 hunks)
  • CONTRIBUTING.md (1 hunks)
  • README.md (2 hunks)
  • docs/api/browser.md (1 hunks)
  • docs/api/tabs/tab.md (1 hunks)
  • docs/contributing/hot-reloading.md (1 hunks)
  • docs/references/omnibox-scores.md (1 hunks)
  • docs/references/omnibox.md (1 hunks)
  • docs/references/tabs.md (1 hunks)
  • docs/references/view-indexes.md (1 hunks)
  • electron/browser/browser.ts (1 hunks)
  • electron/browser/components/glance-modal.ts (1 hunks)
  • electron/browser/components/omnibox.ts (8 hunks)
  • electron/browser/events.ts (1 hunks)
  • electron/browser/ipc.ts (0 hunks)
  • electron/browser/menu.ts (0 hunks)
  • electron/browser/profile-manager.ts (1 hunks)
  • electron/browser/protocols.ts (0 hunks)
  • electron/browser/sessions.ts (1 hunks)
  • electron/browser/tabbed-browser-window.ts (0 hunks)
  • electron/browser/tabs.ts (0 hunks)
  • electron/browser/tabs/tab-bounds.ts (1 hunks)
  • electron/browser/tabs/tab-groups/glance.ts (1 hunks)
  • electron/browser/tabs/tab-groups/index.ts (1 hunks)
  • electron/browser/tabs/tab-groups/split.ts (1 hunks)
  • electron/browser/tabs/tab-manager.ts (1 hunks)
  • electron/browser/tabs/tab.ts (1 hunks)
  • electron/browser/utility/hot-reload.ts (1 hunks)
  • electron/browser/utility/menu.ts (1 hunks)
  • electron/browser/utility/menu/helpers.ts (1 hunks)
  • electron/browser/utility/menu/items/app.ts (1 hunks)
  • electron/browser/utility/menu/items/archive.ts (1 hunks)
  • electron/browser/utility/menu/items/edit.ts (1 hunks)
  • electron/browser/utility/menu/items/file.ts (1 hunks)
  • electron/browser/utility/menu/items/spaces.ts (1 hunks)
  • electron/browser/utility/menu/items/view.ts (1 hunks)
  • electron/browser/utility/menu/items/window.ts (1 hunks)
  • electron/browser/utility/protocols.ts (1 hunks)
  • electron/browser/utility/views.ts (1 hunks)
  • electron/browser/view-manager.ts (1 hunks)
  • electron/browser/window-manager.ts (1 hunks)
  • electron/browser/window.ts (1 hunks)
  • electron/index.ts (3 hunks)
  • electron/ipc/app/app.ts (1 hunks)
  • electron/ipc/app/icons.ts (1 hunks)
  • electron/ipc/app/new-tab.ts (1 hunks)
  • electron/ipc/app/onboarding.ts (1 hunks)
  • electron/ipc/app/open-external.ts (1 hunks)
  • electron/ipc/browser/browser.ts (1 hunks)
  • electron/ipc/browser/interface.ts (1 hunks)
  • electron/ipc/browser/navigation.ts (1 hunks)
  • electron/ipc/browser/page.ts (1 hunks)
  • electron/ipc/browser/tabs.ts (1 hunks)
  • electron/ipc/main.ts (1 hunks)
  • electron/ipc/session/profiles.ts (1 hunks)
  • electron/ipc/session/spaces.ts (1 hunks)
  • electron/ipc/window/omnibox.ts (1 hunks)
  • electron/ipc/window/settings.ts (1 hunks)
  • electron/modules/favicons.ts (7 hunks)
  • electron/modules/flags.ts (2 hunks)
  • electron/modules/icons.ts (4 hunks)
  • electron/modules/output.ts (1 hunks)
  • electron/modules/typed-event-emitter.ts (1 hunks)
  • electron/modules/windows.ts (3 hunks)
  • electron/onboarding/main.ts (1 hunks)
  • electron/package.json (2 hunks)
  • electron/preload.ts (2 hunks)
  • electron/saving/datastore.ts (2 hunks)
  • electron/saving/onboarding.ts (1 hunks)
  • electron/saving/open-external.ts (1 hunks)
  • electron/saving/settings.ts (2 hunks)
  • electron/sessions/profiles.ts (5 hunks)
  • electron/sessions/spaces.ts (4 hunks)
  • electron/settings/main.ts (2 hunks)
  • electron/tsconfig.json (1 hunks)
  • package.json (2 hunks)
  • shared/types/tabs.ts (1 hunks)
  • vite/.gitignore (1 hunks)
  • vite/README.md (0 hunks)
  • vite/background.js (0 hunks)
  • vite/eslint.config.js (1 hunks)
  • vite/index.html (1 hunks)
  • vite/manifest.json (0 hunks)
  • vite/package.json (2 hunks)
  • vite/public/chrome-dino-game/1_hurdling.html (1 hunks)
  • vite/public/chrome-dino-game/2_gymnastics.html (1 hunks)
  • vite/public/chrome-dino-game/3_surfing.html (1 hunks)
  • vite/public/chrome-dino-game/4_swimming.html (1 hunks)
  • vite/public/chrome-dino-game/5_equestrian.html (1 hunks)
  • vite/public/chrome-dino-game/appmanifest.json (1 hunks)
  • vite/public/chrome-dino-game/index.html (1 hunks)
  • vite/public/chrome-dino-game/scripts/load_time_data.js (1 hunks)
  • vite/public/chrome-dino-game/scripts/neterror.slim.js (1 hunks)
  • vite/public/chrome-dino-game/scripts/offline-sprite-definitions.js (1 hunks)
  • vite/public/chrome-dino-game/scripts/strings.js (1 hunks)
  • vite/public/chrome-dino-game/style.css (1 hunks)
  • vite/public/chrome-dino-game/styles/interstitial_common.css (1 hunks)
  • vite/public/chrome-dino-game/styles/interstitial_core.css (1 hunks)
  • vite/public/chrome-dino-game/styles/neterror.css (1 hunks)
  • vite/public/edge-surf-game-v1/index.html (1 hunks)
  • vite/public/edge-surf-game-v1/resources/css/interface.css (1 hunks)
  • vite/public/edge-surf-game-v1/resources/js/assert.js (1 hunks)
  • vite/public/edge-surf-game-v1/resources/js/base-error-reporting.js (1 hunks)
  • vite/public/edge-surf-game-v1/resources/js/cr.js (1 hunks)
  • vite/public/edge-surf-game-v1/resources/js/load_time_data.js (1 hunks)
  • vite/public/edge-surf-game-v1/resources/js/parse_html_subset.js (1 hunks)
  • vite/public/edge-surf-game-v1/resources/js/promise_resolver.js (1 hunks)
⛔ Files not processed due to max files limit (56)
  • vite/public/edge-surf-game-v1/resources/js/strings.js
  • vite/public/edge-surf-game-v1/resources/js/surf-error-reporting.js
  • vite/public/edge-surf-game-v1/resources/js/util.js
  • vite/public/edge-surf-game-v2/index.html
  • vite/public/edge-surf-game-v2/js/assert.js
  • vite/public/edge-surf-game-v2/js/load_time_data.js
  • vite/public/edge-surf-game-v2/js/strings.m.js
  • vite/public/edge-surf-game-v2/js/surf-trusted.js
  • vite/public/edge-surf-game-v2/surf-iframe.html
  • vite/src/App.tsx
  • vite/src/components/browser-ui/browser-action.tsx
  • vite/src/components/browser-ui/browser-content.tsx
  • vite/src/components/browser-ui/browser-sidebar.tsx
  • vite/src/components/browser-ui/main.tsx
  • vite/src/components/browser-ui/sidebar/content/new-tab-button.tsx
  • vite/src/components/browser-ui/sidebar/content/sidebar-content.tsx
  • vite/src/components/browser-ui/sidebar/content/sidebar-tab-groups.tsx
  • vite/src/components/browser-ui/sidebar/content/space-sidebar.tsx
  • vite/src/components/browser-ui/sidebar/content/space-title.tsx
  • vite/src/components/browser-ui/sidebar/header/action-buttons.tsx
  • vite/src/components/browser-ui/sidebar/header/address-bar.tsx
  • vite/src/components/browser-ui/sidebar/header/navigation-buttons.tsx
  • vite/src/components/browser-ui/sidebar/spaces-switcher.tsx
  • vite/src/components/browser-ui/sidebar/tab.tsx
  • vite/src/components/browser-ui/sidebar/tabs.tsx
  • vite/src/components/horizonal-scroller/horizonal-scroller.tsx
  • vite/src/components/logic/tab-disabler.tsx
  • vite/src/components/main/browser-context.tsx
  • vite/src/components/main/dynamic-lucide-icon.tsx
  • vite/src/components/main/platform.tsx
  • vite/src/components/main/theme.tsx
  • vite/src/components/main/website-favicon.tsx
  • vite/src/components/new-tab/main.tsx
  • vite/src/components/new-tab/quick-links.tsx
  • vite/src/components/old-ui/address-bar.tsx
  • vite/src/components/old-ui/browser-content.tsx
  • vite/src/components/old-ui/browser-header.tsx
  • vite/src/components/old-ui/navigation-controls.tsx
  • vite/src/components/old-ui/tab-list.tsx
  • vite/src/components/old-ui/tab.tsx
  • vite/src/components/old-ui/toolbar.tsx
  • vite/src/components/old-ui/window-controls.tsx
  • vite/src/components/omnibox/main.tsx
  • vite/src/components/onboarding/main.tsx
  • vite/src/components/onboarding/screen.tsx
  • vite/src/components/onboarding/stages/finish.tsx
  • vite/src/components/onboarding/stages/icon.tsx
  • vite/src/components/onboarding/stages/initial-space/colors.tsx
  • vite/src/components/onboarding/stages/initial-space/create.tsx
  • vite/src/components/onboarding/stages/initial-space/icon.tsx
  • vite/src/components/onboarding/stages/initial-space/main.tsx
  • vite/src/components/onboarding/stages/new-tab.tsx
  • vite/src/components/onboarding/stages/sidebar-collapse-mode.tsx
  • vite/src/components/onboarding/stages/welcome.tsx
  • vite/src/components/providers/settings-provider.tsx
  • vite/src/components/providers/spaces-provider.tsx
💤 Files with no reviewable changes (8)
  • vite/background.js
  • vite/README.md
  • electron/browser/ipc.ts
  • electron/browser/protocols.ts
  • electron/browser/menu.ts
  • electron/browser/tabs.ts
  • vite/manifest.json
  • electron/browser/tabbed-browser-window.ts
🧰 Additional context used
🧬 Code Graph Analysis (30)
electron/browser/tabs/tab-groups/split.ts (1)
electron/browser/tabs/tab-groups/index.ts (1)
  • BaseTabGroup (28-227)
electron/ipc/window/settings.ts (4)
electron/settings/main.ts (1)
  • settings (40-71)
electron/saving/settings.ts (3)
  • getCurrentSidebarCollapseMode (63-65)
  • SidebarCollapseMode (48-48)
  • setCurrentSidebarCollapseMode (66-80)
vite/src/lib/flow/interfaces/windows/settings.ts (1)
  • SidebarCollapseMode (2-2)
electron/index.ts (1)
  • browser (9-9)
electron/ipc/session/profiles.ts (2)
electron/browser/utility/utils.ts (1)
  • generateID (24-26)
electron/sessions/profiles.ts (4)
  • createProfile (61-96)
  • ProfileData (21-21)
  • updateProfile (98-111)
  • deleteProfile (113-132)
electron/ipc/app/onboarding.ts (1)
electron/saving/onboarding.ts (2)
  • setOnboardingCompleted (14-21)
  • resetOnboarding (23-26)
electron/ipc/app/icons.ts (1)
electron/modules/icons.ts (5)
  • icons (27-68)
  • supportedPlatforms (11-17)
  • getCurrentIconId (226-228)
  • IconId (70-70)
  • setCurrentIconId (229-249)
electron/ipc/app/open-external.ts (1)
electron/saving/open-external.ts (2)
  • getAlwaysOpenExternal (34-50)
  • unsetAlwaysOpenExternal (29-32)
electron/browser/sessions.ts (4)
electron/modules/output.ts (1)
  • debugPrint (18-24)
electron/saving/open-external.ts (2)
  • shouldAlwaysOpenExternal (18-22)
  • setAlwaysOpenExternal (24-27)
electron/sessions/profiles.ts (1)
  • getProfilePath (40-42)
electron/browser/utility/protocols.ts (1)
  • registerProtocolsWithSession (273-279)
electron/ipc/browser/navigation.ts (1)
electron/index.ts (1)
  • browser (9-9)
electron/saving/onboarding.ts (3)
electron/saving/settings.ts (1)
  • SettingsDataStore (5-5)
electron/onboarding/main.ts (1)
  • onboarding (43-74)
electron/index.ts (1)
  • browser (9-9)
electron/ipc/window/omnibox.ts (2)
electron/modules/output.ts (1)
  • debugPrint (18-24)
electron/browser/components/omnibox.ts (4)
  • setOmniboxBounds (211-216)
  • loadOmnibox (218-223)
  • showOmnibox (225-230)
  • hideOmnibox (232-237)
electron/onboarding/main.ts (1)
electron/modules/windows.ts (1)
  • registerWindow (78-86)
electron/browser/utility/menu/items/edit.ts (3)
electron/index.ts (1)
  • browser (9-9)
electron/browser/browser.ts (1)
  • Browser (19-175)
electron/browser/utility/menu/helpers.ts (2)
  • getFocusedWindowData (6-10)
  • getTabWc (47-51)
electron/settings/main.ts (1)
electron/modules/windows.ts (1)
  • registerWindow (78-86)
electron/ipc/browser/browser.ts (1)
electron/index.ts (1)
  • browser (9-9)
electron/ipc/session/spaces.ts (4)
electron/sessions/spaces.ts (10)
  • getSpaces (217-241)
  • getSpacesFromProfile (170-215)
  • createSpace (82-127)
  • deleteSpace (156-168)
  • SpaceData (27-27)
  • updateSpace (129-154)
  • setSpaceLastUsed (243-253)
  • getLastUsedSpace (273-289)
  • reorderSpaces (303-317)
  • spacesEmitter (8-10)
electron/browser/utility/utils.ts (1)
  • generateID (24-26)
electron/index.ts (1)
  • browser (9-9)
electron/browser/window.ts (1)
  • TabbedBrowserWindow (25-190)
electron/ipc/app/new-tab.ts (6)
electron/saving/settings.ts (2)
  • getCurrentNewTabMode (27-29)
  • setCurrentNewTabMode (30-44)
vite/src/lib/flow/interfaces/app/newTab.ts (1)
  • NewTabMode (1-1)
electron/browser/window.ts (1)
  • TabbedBrowserWindow (25-190)
electron/browser/components/omnibox.ts (5)
  • isOmniboxOpen (239-242)
  • hideOmnibox (232-237)
  • loadOmnibox (218-223)
  • setOmniboxBounds (211-216)
  • showOmnibox (225-230)
electron/index.ts (1)
  • browser (9-9)
electron/sessions/spaces.ts (1)
  • getSpace (51-60)
electron/ipc/browser/page.ts (1)
electron/index.ts (1)
  • browser (9-9)
electron/browser/tabs/tab-groups/glance.ts (1)
electron/browser/tabs/tab-groups/index.ts (1)
  • BaseTabGroup (28-227)
vite/public/edge-surf-game-v1/resources/js/assert.js (1)
vite/public/edge-surf-game-v2/js/assert.js (3)
  • assert (4-4)
  • assertNotReached (4-4)
  • assertInstanceof (4-4)
electron/browser/utility/menu/helpers.ts (3)
electron/modules/windows.ts (2)
  • getFocusedWindow (60-63)
  • WindowData (6-11)
electron/index.ts (1)
  • browser (9-9)
electron/browser/browser.ts (1)
  • Browser (19-175)
vite/public/edge-surf-game-v1/resources/js/promise_resolver.js (1)
vite/public/edge-surf-game-v2/js/assert.js (1)
  • assertNotReached (4-4)
electron/browser/utility/hot-reload.ts (1)
electron/modules/flags.ts (1)
  • FLAGS (16-40)
electron/index.ts (2)
electron/saving/onboarding.ts (1)
  • hasCompletedOnboarding (9-12)
electron/onboarding/main.ts (1)
  • onboarding (43-74)
electron/browser/components/omnibox.ts (2)
electron/modules/output.ts (1)
  • debugPrint (18-24)
electron/index.ts (1)
  • browser (9-9)
electron/browser/utility/menu/items/app.ts (1)
electron/settings/main.ts (1)
  • settings (40-71)
electron/ipc/browser/interface.ts (1)
electron/browser/window.ts (1)
  • TabbedBrowserWindow (25-190)
electron/saving/open-external.ts (1)
electron/saving/datastore.ts (1)
  • getDatastore (266-280)
electron/browser/tabs/tab-bounds.ts (1)
electron/browser/tabs/tab.ts (1)
  • Tab (84-657)
electron/saving/settings.ts (2)
electron/ipc/window/settings.ts (1)
  • fireOnSettingsChanged (23-25)
vite/src/lib/flow/interfaces/windows/settings.ts (1)
  • SidebarCollapseMode (2-2)
electron/preload.ts (5)
electron/sessions/profiles.ts (1)
  • ProfileData (21-21)
electron/sessions/spaces.ts (1)
  • SpaceData (27-27)
vite/src/lib/flow/interfaces/windows/settings.ts (2)
  • NewTabMode (1-1)
  • SidebarCollapseMode (2-2)
electron/saving/settings.ts (2)
  • NewTabMode (12-12)
  • SidebarCollapseMode (48-48)
vite/src/lib/flow/interfaces/app/newTab.ts (1)
  • NewTabMode (1-1)
🪛 Biome (1.9.4)
electron/browser/sessions.ts

[error] 40-43: This case is falling through to the next case.

Add a break or return statement to the end of this case to prevent fallthrough.

(lint/suspicious/noFallthroughSwitchClause)

electron/browser/view-manager.ts

[error] 72-72: Comparing to itself is potentially pointless.

(lint/suspicious/noSelfCompare)

electron/browser/window-manager.ts

[error] 46-46: The catch clause that only rethrows the original error is useless.

An unnecessary catch clause can be confusing.
Unsafe fix: Remove the try/catch clause.

(lint/complexity/noUselessCatch)

vite/public/edge-surf-game-v1/resources/js/parse_html_subset.js

[error] 62-62: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)


[error] 203-203: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Unsafe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 236-236: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

vite/public/edge-surf-game-v1/resources/js/cr.js

[error] 12-12: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)


[error] 101-101: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Unsafe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 137-137: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Unsafe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 11-11: This variable is used before its declaration.

The variable is declared here:

(lint/correctness/noInvalidUseBeforeDeclaration)

vite/public/edge-surf-game-v1/resources/js/load_time_data.js

[error] 215-215: Invalid typeof comparison value: this expression is not a string literal

not a string literal

(lint/suspicious/useValidTypeof)

vite/public/edge-surf-game-v1/resources/css/interface.css

[error] 287-288: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)

vite/public/chrome-dino-game/scripts/load_time_data.js

[error] 204-204: Invalid typeof comparison value: this expression is not a string literal

not a string literal

(lint/suspicious/useValidTypeof)

🪛 LanguageTool
README.md

[style] ~41-~41: Using many exclamation marks might seem excessive (in this case: 5 exclamation marks for a text that’s 3157 characters long)
Context: ...sets/screenshots/beta-onboarding-1.png) Browser - macOS Command - macOS ![New Tab - macOS](./assets/screenshots/b...

(EN_EXCESSIVE_EXCLAMATION)

docs/references/omnibox-scores.md

[typographical] ~5-~5: If you want to indicate numerical ranges or time ranges, consider using an en dash.
Context: ...igher in the suggestion list. - ~1100 - 1500: Open Tab (Switch) - _Encourages ...

(DASH_RULE)


[typographical] ~6-~6: If you want to indicate numerical ranges or time ranges, consider using an en dash.
Context: ...les with title/URL similarity._ - 1400 - 1450+: History URL (Exact Match) - _Ve...

(DASH_RULE)


[typographical] ~8-~8: If you want to indicate numerical ranges or time ranges, consider using an en dash.
Context: ...ch for..." or typed URL entry._ - 1100 - 1200: Pedal - _Browser actions trigger...

(DASH_RULE)


[typographical] ~9-~9: If you want to indicate numerical ranges or time ranges, consider using an en dash.
Context: ...cales with trigger similarity._ - ~900 - 1450: History URL (Similarity/Prefix M...

(DASH_RULE)


[typographical] ~10-~10: If you want to indicate numerical ranges or time ranges, consider using an en dash.
Context: ...d counts, and prefix matching._ - ~600 - 1000: Search Suggestion - _Fetched sug...

(DASH_RULE)


[typographical] ~11-~11: If you want to indicate numerical ranges or time ranges, consider using an en dash.
Context: ... order and similarity to input._ - 350 - 800: Zero Suggest (Recent Tabs) - _Sug...

(DASH_RULE)


[typographical] ~12-~12: If you want to indicate numerical ranges or time ranges, consider using an en dash.
Context: ... typing, ranked by tab recency._ - 500 - 700: Zero Suggest (Most Visited Histor...

(DASH_RULE)

docs/api/tabs/tab.md

[uncategorized] ~38-~38: Loose punctuation mark.
Context: ... ###TabCreationDetails -browser: The main Browser` controller instance....

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~39-~39: Loose punctuation mark.
Context: ...sercontroller instance. -tabManager: The TabManager` instance responsible f...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~40-~40: Loose punctuation mark.
Context: ... responsible for this tab. - profileId: The ID of the user profile associated w...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~41-~41: Loose punctuation mark.
Context: ...le associated with this tab. - spaceId: The ID of the space this tab belongs to...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~42-~42: Loose punctuation mark.
Context: ...e space this tab belongs to. - session: The Electron Session object to use fo...

(UNLIKELY_OPENING_PUNCTUATION)


[style] ~53-~53: To form a complete sentence, be sure to include a subject.
Context: ...d: (string) The associated space ID. Can be updated. - visible: (boolean`) Wh...

(MISSING_IT_THERE)


[uncategorized] ~68-~68: Loose punctuation mark.
Context: ...dow(window: TabbedBrowserWindow | null)`: Attaches the tab's view to a given wind...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~69-~69: Loose punctuation mark.
Context: ...loadURL(url: string, replace?: boolean)`: Loads the specified URL in the tab. If ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~70-~70: Loose punctuation mark.
Context: ...rorPage(errorCode: number, url: string)`: Loads a custom error page for the given...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~71-~71: Loose punctuation mark.
Context: ...al URL. - setLayout(layout: TabLayout): Sets the tab's layout configuration and...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~72-~72: Loose punctuation mark.
Context: ...and updates the view. - updateLayout(): Recalculates and applies the view's bou...

(UNLIKELY_OPENING_PUNCTUATION)


[style] ~72-~72: To form a complete sentence, be sure to include a subject.
Context: ...current layout and window dimensions. Should be called when the window resizes or la...

(MISSING_IT_THERE)


[uncategorized] ~73-~73: Loose punctuation mark.
Context: ... or layout changes. - updateTabState(): Reads the current state (title, URL, lo...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~74-~74: Loose punctuation mark.
Context: ...f changed, false otherwise. - show(): Makes the tab's view visible. - `hide()...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~75-~75: Loose punctuation mark.
Context: ...Makes the tab's view visible. - hide(): Hides the tab's view. - destroy(): Cl...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~76-~76: Loose punctuation mark.
Context: ...(): Hides the tab's view. - destroy()`: Cleans up resources, removes the view, ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~82-~82: Loose punctuation mark.
Context: ...emits the following events: - focused: Emitted when the tab's webContents ga...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~83-~83: Loose punctuation mark.
Context: ...erto track the active tab. -updated`: Emitted when the tab's state (e.g., tit...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~84-~84: Loose punctuation mark.
Context: ...ds like show()/hide(). - destroyed: Emitted when the destroy() method is ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~88-~88: Loose punctuation mark.
Context: ...nal Helpers - createWebContentsView(): Factory function used internally by the...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~89-~89: Loose punctuation mark.
Context: ...ipt, session). - setupEventListeners(): Sets up listeners on the webContents ...

(UNLIKELY_OPENING_PUNCTUATION)

docs/api/browser.md

[grammar] ~19-~19: Possible subject-verb agreement error.
Context: ...instance and initializes the window and profile managers. Automatically creates the ini...

(IS_AND_ARE)


[uncategorized] ~23-~23: Loose punctuation mark.
Context: ...tion. ## Properties - profileManager: Manages browser profiles - `windowManag...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~39-~39: Loose punctuation mark.
Context: ... its ID. Parameters: - profileId: The ID of the profile to retrieve **Re...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~67-~67: Loose punctuation mark.
Context: ... needed. Parameters: - profileId: The ID of the profile to load **Return...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~83-~83: Loose punctuation mark.
Context: ...e by ID. Parameters: - profileId: The ID of the profile to unload **Retu...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~104-~104: Loose punctuation mark.
Context: ...owser window. Parameters: - type: The type of window to create (default: ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~133-~133: Loose punctuation mark.
Context: ...y its ID. Parameters: - windowId: The ID of the window to retrieve **Ret...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~149-~149: Loose punctuation mark.
Context: ...tents. Parameters: - webContents: The WebContents instance to find the wi...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~165-~165: Loose punctuation mark.
Context: ...y its ID. Parameters: - windowId: The ID of the window to destroy **Retu...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~214-~214: Loose punctuation mark.
Context: ...b by its ID. Parameters: - tabId: The ID of the tab to retrieve **Return...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~224-~224: Loose punctuation mark.
Context: ...emits the following events: - destroy: Emitted when the browser is destroyed

(UNLIKELY_OPENING_PUNCTUATION)

docs/references/omnibox.md

[uncategorized] ~14-~14: Loose punctuation mark.
Context: ...callback. 2. AutocompleteController: Orchestrates the suggestion generatio...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~45-~45: Loose punctuation mark.
Context: ...pes or focuses the omnibox. - text: The current text in the input field. ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~46-~46: Loose punctuation mark.
Context: ...xt in the input field. - eventType: 'focus' or 'keystroke'. The `...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~85-~85: Loose punctuation mark.
Context: ...ous?: boolean) => void;** - results: An array of AutocompleteMatch` objects...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~86-~86: Loose punctuation mark.
Context: ..., sorted by relevance. - continuous?: An optional boolean indicating if more ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~91-~91: Loose punctuation mark.
Context: ...ut state for a query. - text: string: The user's typed text. - `currentURL?...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~93-~93: Loose punctuation mark.
Context: ...used). - type: 'focus' | 'keystroke': The event that triggered the query. -...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~99-~99: Loose punctuation mark.
Context: ...gestion item. - providerName: string: Name of the originating provider. - `...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~100-~100: Loose punctuation mark.
Context: ...nating provider. - relevance: number: Score indicating importance (higher is ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~101-~101: Loose punctuation mark.
Context: ...igher is better). - contents: string: Primary text displayed. - `descriptio...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~102-~102: Loose punctuation mark.
Context: ...xt displayed. - description?: string: Secondary text (optional). - `destina...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~103-~103: Loose punctuation mark.
Context: ...(optional). - destinationUrl: string: The URL to navigate to, the search quer...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~104-~104: Loose punctuation mark.
Context: ...ou-typed" | "search-query" | "open-tab": The type of suggestion. - isDefault?...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~105-~105: Loose punctuation mark.
Context: ...of suggestion. - isDefault?: boolean: Hint if this could be the default actio...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~106-~106: Loose punctuation mark.
Context: ...n Enter. - inlineCompletion?: string: Text suggested for inline completion (o...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~107-~107: Loose punctuation mark.
Context: ...RLProvider). - pedalAction?: string`: Identifier for a browser action (option...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~111-~111: Loose punctuation mark.
Context: ...ase-provider.tsx) - **name: string**: Identifier for the provider. - **start...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~112-~112: Loose punctuation mark.
Context: ...Results: OmniboxUpdateCallback): void`**: Starts generating suggestions. Results ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~113-~113: Loose punctuation mark.
Context: ...nt via onResults. - stop(): void: Stops any ongoing asynchronous operatio...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~123-~123: Loose punctuation mark.
Context: ...tch[])**: Adds matches. - **clear()`**: Resets the internal matches array. - **...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~124-~124: Loose punctuation mark.
Context: ...nal matches array. - deduplicate(): Removes matches with duplicate `destina...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~125-~125: Loose punctuation mark.
Context: ... by relevance beforehand. - sort(): Sorts matches primarily by relevance (d...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~126-~126: Loose punctuation mark.
Context: ...). - getTopMatches(limit?: number): Returns the top matches, up to a specif...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~131-~131: Loose punctuation mark.
Context: ...r[], onUpdate: OmniboxUpdateCallback)`**: Stores providers and the update callbac...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~132-~132: Loose punctuation mark.
Context: ... - start(input: AutocompleteInput): Stops previous query, clears results, g...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~133-~133: Loose punctuation mark.
Context: ...updateResults initially. - **stop()**: Calls stop()` on all active providers....

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~134-~134: Loose punctuation mark.
Context: ...roviders. - onProviderResults(...): Callback for providers. Checks request ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~135-~135: Loose punctuation mark.
Context: ...updateResults. - updateResults(): Calls deduplicate() and sort() on `...

(UNLIKELY_OPENING_PUNCTUATION)


[grammar] ~185-~185: Did you mean “to”?
Context: ...vider scoring or Machine Learning model as found in browsers like Chrome. - **Dedu...

(LEARN_NNNNS_ON_DO)

🔇 Additional comments (113)
vite/public/chrome-dino-game/styles/interstitial_core.css (1)

83-100: Well-implemented dark mode support

The CSS includes proper dark mode support using the prefers-color-scheme media query with appropriate color overrides for a better user experience in dark environments.

vite/public/chrome-dino-game/styles/interstitial_common.css (5)

1-3: Copyright notice properly included.

The CSS file correctly includes the original Chromium license and copyright notice, which is good practice when adapting code from Chromium's codebase.


5-17: Button styling follows modern best practices.

The button styling uses CSS variables for theming, proper box-sizing, and transitions for hover effects, making it consistent with modern web standards.


107-111: Good use of CSS variables for icon sizing.

The icon sizing is consistent and uses appropriate sizing for visual elements in the UI.


113-229: Well-implemented custom checkbox styling.

The checkbox styling uses pseudo-elements to create custom checkmarks while maintaining accessibility, with proper handling of the :checked state.


247-517: Extensive responsive design implementation.

The file includes comprehensive media queries for different screen sizes and orientations, ensuring a good user experience across devices. The mobile-specific styling is particularly well thought out with special handling for portrait and landscape modes.

vite/public/chrome-dino-game/4_swimming.html (4)

1-9: Proper document structure and responsive meta tags.

The HTML document includes proper DOCTYPE declaration, language attributes, and responsive viewport meta tags, which are essential for a good mobile experience.


39-42: Strong accessibility implementation.

The game canvas is wrapped in a container with appropriate ARIA attributes and an assertive live region that describes the game to screen reader users. This is excellent for accessibility compliance.


51-59: Offline resources properly embedded.

The game includes offline resources like sprites and embedded audio in base64 format, ensuring the game works properly without internet connectivity, which is essential for an offline game.


62-71: Touch detection enhances mobile usability.

The script detects touch capabilities and dynamically changes instructions for touch devices, which improves the user experience on mobile and tablet devices.

vite/public/chrome-dino-game/1_hurdling.html (2)

1-16: Consistent structure across game variants.

The HTML structure maintains consistency with other game variants, which is good for maintainability and user experience.


26-36: Theme selector is well organized.

The theme selector dropdown is well-structured with all the Olympic game variants, making it easy for users to switch between different game themes.

vite/public/chrome-dino-game/scripts/load_time_data.js (5)

1-15: Comprehensive JSDoc documentation.

The file includes excellent JSDoc comments that clearly explain the purpose of the LoadTimeData class and its limitations, which helps with maintainability and developer understanding.


17-25: Singleton pattern implementation.

The LoadTimeData class is properly implemented as a singleton, which is appropriate for managing global localization data.


80-89: String substitution functionality is valuable for localization.

The implementation of string substitution with positional parameters ($1, $2, etc.) is valuable for localization support, allowing for different word order in different languages.


207-213: Ensuring singleton instance is properly exposed.

The code correctly ensures the LoadTimeData instance is only created once and exposed globally, which is important for consistent access throughout the application.


202-205:

Details

✅ Verification successful

Potential issue with typeof comparison.

The static analysis tool flagged line 204, suggesting the typeof comparison should use a string literal. However, this is a false positive as the function is called with string literals throughout the code (e.g., line 68).


🏁 Script executed:

#!/bin/bash
# Check how expectIsType is used in the codebase
grep -n "expectIsType" vite/public/chrome-dino-game/scripts/load_time_data.js

Length of output: 253


No action needed for typeof comparison
The expectIsType function is only ever called with string literals ('string', 'boolean', 'number'), so using typeof value === type is correct and the static analysis warning is a false positive.

🧰 Tools
🪛 Biome (1.9.4)

[error] 204-204: Invalid typeof comparison value: this expression is not a string literal

not a string literal

(lint/suspicious/useValidTypeof)

vite/public/chrome-dino-game/styles/neterror.css (2)

1-3: Well-structured font selection.

Using system-ui with fallbacks ensures the game interface will have a consistent, native appearance across different operating systems.


378-429: Good implementation of dark mode support.

The dark mode implementation using prefers-color-scheme: dark is comprehensive and properly handles color inversions, background adjustments, and contrast for readability in dark environments.

vite/public/chrome-dino-game/scripts/offline-sprite-definitions.js (1)

31-687: Well-structured sprite definitions with proper organization.

The sprite definitions are well-organized by game type and display density, with clear separation of concerns between different game elements (obstacles, character animations, background elements, etc.). The detailed collision boxes and game parameters provide a solid foundation for the game mechanics.

CONTRIBUTING.md (1)

33-33: Approve documentation update for hot reloading guide.
The new line correctly directs developers to the Hot Reloading Guide and complements the existing Getting Started instructions.

vite/index.html (1)

10-10:

Details

✅ Verification successful

Verify script entrypoint path.
Confirm that the absolute path /src/main.tsx aligns with your Vite configuration; otherwise, the UI may not load correctly.


🏁 Script executed:

#!/bin/bash
# Verify that src/main.tsx exists at the expected location
rg --files | grep -E '^src/main\.tsx$'

Length of output: 40


To locate the actual entrypoint file in your src folder, let’s broaden the search:


🏁 Script executed:

#!/bin/bash
# Search for main or index files under src directory with common extensions
rg --files src | grep -E '(main|index)\.(js|jsx|ts|tsx)$'

Length of output: 103


Let’s search the whole repo for any entrypoint in case the src folder isn’t at the root:


🏁 Script executed:

#!/bin/bash
# 1) Look for main or index files across the repo
rg --files | grep -E '(main|index)\.(js|jsx|ts|tsx)$'
# 2) Fallback: list every .tsx file
rg --files --glob '*.tsx'

Length of output: 5311


Let’s verify if there’s a custom base or root set in your Vite config:


🏁 Script executed:

#!/bin/bash
# 1) Locate any Vite config file
rg --files | grep -E 'vite.config\.(ts|js|mjs|cjs)$'
# 2) Inspect that config for base or root settings
grep -R "base" vite.config.*
grep -R "root" vite.config.*

Length of output: 230


Let’s inspect your Vite config directly to see if it sets a custom root or base:


🏁 Script executed:

#!/bin/bash
# Show any base or root settings in vite/vite.config.ts
grep -E "^(\\s*)(base|root)\\s*:" -n vite/vite.config.ts || echo "No base/root field found"
# Dump the first 200 lines to review context
sed -n '1,200p' vite/vite.config.ts

Length of output: 495


Entrypoint path /src/main.tsx is correct
The file vite/src/main.tsx exists and, with no custom root and a base: "./" setting in vite/vite.config.ts, /src/main.tsx will resolve properly in both dev and build. No updates needed.

electron/tsconfig.json (1)

12-13: Great addition of the shared path alias

Adding the "~/*" path alias to the TypeScript configuration is a good architectural decision that will make it easier to import shared code from the sibling shared directory. This supports the modular architecture refactoring effort and will help maintain clean import paths across the codebase.

package.json (2)

3-3: Version bump reflects major features

The version bump from 0.3.2 to 0.4.0 properly reflects the significant changes described in the PR objectives, including the addition of profiles, spaces, and Flow Games.


15-16: Improved development workflow

Adding separate scripts for running the Vite development server and Electron process is a good practice. This separation allows developers to:

  1. Run the frontend independently for faster iterations
  2. Restart only the needed process during development
  3. Debug each part of the application separately

This change will improve developer experience and productivity.

vite/eslint.config.js (2)

14-14: Code style: Added trailing comma

Added trailing comma after the globals object for consistent code style.


18-18: Code style: Added trailing comma

Added trailing comma after the reactRefresh plugin for consistent code style.

electron/browser/utility/menu/items/window.ts (1)

1-5: Clean modular menu implementation

This new file is part of a good architectural change to modularize the menu system. Breaking down menu items into separate modules improves:

  1. Code organization and maintainability
  2. Separation of concerns
  3. Testability of individual menu components

The implementation is clean and follows a consistent pattern with other menu item modules mentioned in the summary.

electron/package.json (3)

4-4: Version bump to 0.4.0 aligns with the major rewrite

The version bump from 0.3.2 to 0.4.0 reflects the significant changes in this pull request, including profile and spaces support, onboarding process, Flow Games, and other major feature additions.


26-26: New dependencies support enhanced functionality

The addition of electron-context-menu will provide improved right-click menu functionality. The lucide package adds a comprehensive icon library that will likely be used for UI enhancements. The sharp package upgrade provides improved image processing capabilities.

Also applies to: 30-30, 32-32


38-47:

Details

✅ Verification successful

Dependency updates maintain security and compatibility

Updating Electron Forge components to version 7.8.0 and Electron to 35.1.5 ensures the application has the latest security fixes and features. This is particularly important for browser applications that handle user data.

Also applies to: 53-53


🏁 Script executed:

#!/bin/bash
# Check for any security advisories related to electron 35.1.5
gh api graphql -f query='
{
  securityVulnerabilities(first: 5, ecosystem: NPM, package: "electron") {
    nodes {
      advisory {
        summary
        severity
        publishedAt
      }
      vulnerableVersionRange
      firstPatchedVersion {
        identifier
      }
    }
  }
}'

Length of output: 1559


Approve: Electron Forge v7.8.0 & Electron 35.1.5
No known security advisories affect Electron 35.1.5 (latest ASAR Integrity bypass issues only impacted ≤ 27.x and have been patched). Upgrading Forge plugins to 7.8.0 and Electron to 35.1.5 keeps our app secure and up‑to‑date—good to merge.

electron/saving/datastore.ts (1)

215-236: Good implementation of remove method

The remove method provides a clean way to delete entries from the datastore. It includes proper input validation, uses the existing queue mechanism to ensure atomic operations, and returns a boolean indicating success. This is a valuable addition that complements the existing get and set methods.

electron/browser/utility/menu/items/app.ts (1)

1-24: Well-structured modular menu implementation

This new file follows a good modular design pattern by isolating app menu creation logic. The menu structure follows platform conventions with standard roles and appropriate separators. The custom Settings item is properly integrated and uses the centralized settings management system.

docs/references/omnibox-scores.md (1)

1-15: Well-organized documentation of omnibox scoring system

This documentation clearly explains the scoring system used for organizing omnibox suggestions. The hierarchical organization and explanations provide valuable context for developers working with the omnibox component.

🧰 Tools
🪛 LanguageTool

[typographical] ~5-~5: If you want to indicate numerical ranges or time ranges, consider using an en dash.
Context: ...igher in the suggestion list. - ~1100 - 1500: Open Tab (Switch) - _Encourages ...

(DASH_RULE)


[typographical] ~6-~6: If you want to indicate numerical ranges or time ranges, consider using an en dash.
Context: ...les with title/URL similarity._ - 1400 - 1450+: History URL (Exact Match) - _Ve...

(DASH_RULE)


[typographical] ~8-~8: If you want to indicate numerical ranges or time ranges, consider using an en dash.
Context: ...ch for..." or typed URL entry._ - 1100 - 1200: Pedal - _Browser actions trigger...

(DASH_RULE)


[typographical] ~9-~9: If you want to indicate numerical ranges or time ranges, consider using an en dash.
Context: ...cales with trigger similarity._ - ~900 - 1450: History URL (Similarity/Prefix M...

(DASH_RULE)


[typographical] ~10-~10: If you want to indicate numerical ranges or time ranges, consider using an en dash.
Context: ...d counts, and prefix matching._ - ~600 - 1000: Search Suggestion - _Fetched sug...

(DASH_RULE)


[typographical] ~11-~11: If you want to indicate numerical ranges or time ranges, consider using an en dash.
Context: ... order and similarity to input._ - 350 - 800: Zero Suggest (Recent Tabs) - _Sug...

(DASH_RULE)


[typographical] ~12-~12: If you want to indicate numerical ranges or time ranges, consider using an en dash.
Context: ... typing, ranked by tab recency._ - 500 - 700: Zero Suggest (Most Visited Histor...

(DASH_RULE)

electron/ipc/main.ts (1)

1-21: Well-organized modular IPC architecture

The centralized organization of IPC imports by domain (Browser, Session, App, Windows) creates a clean entry point for all IPC handlers. This approach improves maintainability by making it easy to locate and modify specific IPC modules.

electron/browser/utility/menu/items/file.ts (1)

6-30: Well-structured menu implementation

The File menu implementation follows good practices by:

  1. Properly checking for window existence before performing operations
  2. Using appropriate accelerator keys following platform conventions
  3. Keeping the code modular and focused on a single responsibility

Nice work!

electron/ipc/app/icons.ts (1)

1-18: Clean and well-organized IPC handler implementation

The icon management IPC handlers are implemented correctly:

  • Each handler has a single, well-defined responsibility
  • The code properly leverages the existing icon management functions
  • Type safety is maintained with the IconId type

The modular approach aligns well with the overall application architecture refactoring mentioned in the PR objectives.

electron/ipc/window/omnibox.ts (2)

5-18: Well-implemented omnibox show handler with robust error checking

The handler correctly:

  1. Retrieves the parent window from the event sender
  2. Validates the parent window exists before proceeding
  3. Provides helpful debug logging
  4. Follows the proper sequence of operations (set bounds → load → show)

This implementation aligns with the PR objective of implementing a more modular architecture with dedicated managers.


20-28: Consistent implementation of omnibox hide handler

The handler follows the same pattern as the show handler with proper error checking and logging.

electron/ipc/window/settings.ts (2)

1-22: Clean separation of settings-related IPC handlers

The module properly:

  1. Separates concerns with dedicated handlers for different settings operations
  2. Uses the appropriate IPC patterns (on for actions, handle for requests that return values)
  3. Maintains type safety with the imported SidebarCollapseMode type

This implementation supports the PR objective of implementing a modular architecture with enhanced APIs.


23-25:

Details

✅ Verification successful

Verify browser initialization before usage

The optional chaining operator (?.) indicates that browser might be null when fireOnSettingsChanged is called. Consider adding additional validation or implementing a queue mechanism if settings changes need to be guaranteed to propagate.


🏁 Script executed:

#!/bin/bash
# Check where fireOnSettingsChanged is called from and if browser might be null
echo "Searching for calls to fireOnSettingsChanged..."
rg "fireOnSettingsChanged\(\)" -A 3 -B 3

echo "Checking browser initialization..."
rg "browser = " -A 3 -B 3

Length of output: 4524


🏁 Script executed:

#!/bin/bash
echo "=== electron/ipc/window/settings.ts ==="
head -n 100 electron/ipc/window/settings.ts

echo
echo "=== electron/index.ts ==="
head -n 200 electron/index.ts

Length of output: 4425


🏁 Script executed:

#!/bin/bash
echo "=== electron/saving/settings.ts ==="
head -n 200 electron/saving/settings.ts

echo
echo "=== electron/settings/main.ts ==="
head -n 200 electron/settings/main.ts

Length of output: 4232


No additional guard needed for fireOnSettingsChanged

The Browser instance is assigned in initializeApp() before any renderer‑triggered “settings:set‑…” IPC handlers can run. By the time setCurrentSidebarCollapseMode (or any settings setter) calls fireOnSettingsChanged(), browser is guaranteed non‑null. The optional chaining is simply a safe no‑op fallback and can remain as‑is.

electron/modules/flags.ts (1)

27-39: LGTM - Well-structured flag organization

The flag values are well organized with descriptive comments explaining each flag's purpose. The consistent use of spacing and separators between flag groups improves readability.

electron/browser/components/glance-modal.ts (2)

3-19: New GlanceModal component initialization looks good

The class effectively initializes a WebContentsView with transparent background and proper border radius, loading the internal glance modal URL.


21-27: LGTM - Clean interface methods

The public methods for managing bounds and visibility are well-implemented and provide a clean interface for the component.

electron/browser/tabs/tab-groups/glance.ts (1)

3-6: LGTM - Clean class structure with proper typing

The class properly extends BaseTabGroup with specific properties for the glance functionality.

electron/browser/utility/views.ts (1)

3-11: LGTM - Well-structured type and class definition

The ViewData type and ViewsManager class properties are well-structured with proper typing.

electron/ipc/session/profiles.ts (4)

1-3: Well-structured imports for profile management IPC handlers

The imports are properly organized, pulling in the necessary profile management functions from the sessions module, the ID generation utility, and Electron's IPC main interface.


5-7: Clean implementation of get-all profiles handler

The handler correctly implements an asynchronous response pattern for retrieving all profiles.


9-12: Good implementation of profile creation with unique ID generation

This handler appropriately uses the generateID utility to create a unique identifier before calling the profile creation function, maintaining separation of concerns.


19-21: Clean implementation of profile deletion handler

The handler correctly implements profile deletion by passing the provided ID to the underlying function.

electron/browser/events.ts (1)

1-12: Well-designed TypeScript event type definitions

The BrowserEvents type definition provides excellent type safety for the browser's event system. It clearly documents the event names and their expected payload types using modern TypeScript tuple syntax, making it easier for developers to correctly subscribe to and handle these events.

The event names are descriptive and follow a consistent pattern (e.g., "window-created"/"window-destroyed" and "profile-loaded"/"profile-unloaded"), which enhances code readability and maintainability.

electron/modules/windows.ts (3)

3-3: Updated import path for TabbedBrowserWindow

The import path has been correctly updated to reflect the new location of the TabbedBrowserWindow class as part of the architectural refactoring.


16-17: Added onboarding window type to support new onboarding flow

Good addition of the ONBOARDING window type to the WindowType enum to support the onboarding flow mentioned in the PR objectives.


41-41: Updated property access reflecting TabbedBrowserWindow interface changes

Changed from calling win.getBrowserWindow() to directly accessing win.window, reflecting the updated class interface that now exposes the BrowserWindow as a property rather than through a getter method.

electron/browser/utility/menu/items/archive.ts (3)

1-4: Clean imports for menu creation

The imports are well-structured, bringing in the necessary Electron types, Browser class, and helper functions.


8-19: Well-implemented "Go Back" navigation with proper checks

The "Go Back" menu item is well implemented with:

  1. An appropriate keyboard shortcut (CmdOrCtrl+Left)
  2. Proper error handling for when no tab is focused
  3. A safety check using canGoBack() before attempting navigation

This implementation prevents errors that could occur from attempting to navigate when it's not possible.


20-31: Well-implemented "Go Forward" navigation with proper checks

Similarly, the "Go Forward" menu item is well implemented with appropriate shortcuts, error handling, and navigation capability checks.

README.md (7)

16-16: Version updated to v0.4.0

The README has been updated to reflect the new version number, which is consistent with the updated download links.


28-29: Download URL updated to match the new version

The macOS download URL properly points to the v0.4.0 release.


33-33: Windows download link updated

The Windows setup link has been properly updated to the v0.4.0 release.


41-45: New screenshots added to showcase updated UI

The screenshots effectively demonstrate the new UI components including onboarding, browser interface, command palette, new tab, and settings screens.

🧰 Tools
🪛 LanguageTool

[style] ~41-~41: Using many exclamation marks might seem excessive (in this case: 5 exclamation marks for a text that’s 3157 characters long)
Context: ...sets/screenshots/beta-onboarding-1.png) Browser - macOS Command - macOS ![New Tab - macOS](./assets/screenshots/b...

(EN_EXCESSIVE_EXCLAMATION)


49-56: New features list clearly documents major additions

The features list effectively communicates the significant new capabilities added in this version, including profiles, spaces, sidebar, command palette, security improvements, onboarding, and offline games.


58-71: Helpful roadmap of upcoming features

The addition of an "Upcoming Features" section is valuable for setting user expectations and providing transparency about future development plans. This helps users understand which features are currently missing but planned.


73-75: User feedback channel added

The addition of a dedicated feedback link improves the user experience by providing a clear channel for feature requests and bug reports.

electron/browser/utility/menu.ts (3)

1-13: Clean modular imports for menu creation

The menu system has been well-organized with modular imports from separate files, following good separation of concerns principles.


14-31: Well-structured menu setup function

The setupMenu function is well-designed with:

  • Platform-specific conditionals for macOS menu differences
  • Clean template construction
  • Proper async handling for spaces menu creation

This structure will be easier to maintain and extend than a monolithic menu definition.


32-34: Dynamic menu updates on space changes

The event listener properly updates the menu when spaces change, ensuring the UI stays in sync with the application state.

electron/browser/utility/menu/items/edit.ts (2)

5-12: Standard edit menu with appropriate roles

The edit menu includes all the expected standard operations with proper role assignments.


30-34: Complete set of edit operations

The menu includes all necessary edit operations including paste and match style, delete, and select all.

electron/ipc/browser/interface.ts (2)

5-17: Robust window button handlers with safety checks

The IPC handlers for window button positioning and visibility include appropriate safety checks:

  • Verifying the window exists
  • Checking if the required methods are available before calling them

This approach prevents potential runtime errors when running on different platforms.


19-23: Efficient sidebar toggle implementation

The toggleSidebar function correctly sends the toggle message to all core web contents of the window, ensuring all UI components can respond appropriately.

vite/public/edge-surf-game-v1/index.html (3)

26-34:

Details

✅ Verification successful

Verify JavaScript dependencies exist

The page references multiple JavaScript files for error reporting, assertions, and other utilities. Ensure all of these files exist in the correct locations.


🏁 Script executed:

#!/bin/bash
# Check if the referenced JavaScript files exist
fd -t f -e js "assert|base-error-reporting|surf-error-reporting|promise_resolver|cr|parse_html_subset|load_time_data|util|strings" vite/public/edge-surf-game-v1/resources/js/

Length of output: 705


✅ All JavaScript dependencies are present

I’ve confirmed that each of the scripts referenced in vite/public/edge-surf-game-v1/index.html exists under vite/public/edge-surf-game-v1/resources/js/. No further action is needed.


11-24:

Details

✅ Verification successful

Verify icon resources exist

Multiple icon references are included for various device platforms. Ensure all referenced icon files actually exist in the resources directory to avoid 404 errors.


🏁 Script executed:

#!/bin/bash
# Check if the icon files exist in the resources directory
fd -t f -e png -e svg ".*icon.*" vite/public/edge-surf-game-v1/resources/icons/

Length of output: 1624


All referenced icon files are present
I’ve verified that every <link> icon (apple-icon-*, android-icon-192x192.png, favicon.svg, ms-icon-144x144.png) exists in vite/public/edge-surf-game-v1/resources/icons/. No missing assets detected.


41-43:

Details

✅ Verification successful

Verify bundle files exist

The page loads three JavaScript bundles. Ensure these bundle files exist in the correct location.


🏁 Script executed:

#!/bin/bash
# Check if the JavaScript bundle files exist
fd -t f "lib_react.chunk.js|lib_common.chunk.js|surf.bundle.js" vite/public/edge-surf-game-v1/resources/js/

Length of output: 292


Bundle files verification passed

All three JavaScript bundles are present in vite/public/edge-surf-game-v1/resources/js/:

  • lib_react.chunk.js
  • lib_common.chunk.js
  • surf.bundle.js
electron/ipc/browser/page.ts (1)

1-13: Well-structured type definitions

The PageBounds and PageBoundsWithWindow types are well-defined and logically structured for representing rectangular bounds with optional window association.

electron/ipc/browser/navigation.ts (3)

19-24: Consistent error handling and proper optional chaining

Good use of optional chaining and null checks to safely access the webContents.stop() method, providing robust error handling.


26-31: Clear and concise implementation

The reload tab handler is well-implemented with proper error checking and clean code structure.


33-47: Well-structured async handler with comprehensive navigation status

Good use of ipcMain.handle for an async operation that returns a result. The handler correctly checks for tab and navigation history existence before attempting to access properties.

electron/browser/sessions.ts (3)

7-8: Efficient session caching

Using a Map to store sessions by profile ID is a good approach for caching and quick lookup.


9-58: Robust permission handling for external URLs

The permission handler is well-implemented with good security practices:

  1. Checks if URLs should be automatically allowed
  2. Provides user-friendly dialog with clear options
  3. Remembers user preferences when requested
  4. Sanitizes URLs for display

This improves security while maintaining usability for trusted sites.

🧰 Tools
🪛 Biome (1.9.4)

[error] 40-43: This case is falling through to the next case.

Add a break or return statement to the end of this case to prevent fallthrough.

(lint/suspicious/noFallthroughSwitchClause)


60-76: Efficient and modular session management

The session creation and retrieval implementation follows good practices:

  1. Creates isolated sessions per profile
  2. Properly registers protocols and permission handlers
  3. Implements efficient caching to avoid recreating sessions
  4. Uses clear function naming and responsibilities

This modular approach improves maintainability and performance.

electron/settings/main.ts (3)

24-24: Updated URL scheme

The URL has been changed to use the new flow-internal protocol, which aligns with the architectural changes in the PR.


33-37: Improved async window creation

The function now returns a Promise that resolves when the window is ready to show, which is a better pattern for async window creation. This prevents race conditions where the window might be used before it's fully initialized.


41-44: Properly updated show method to be async

The show method has been correctly updated to be async and await window creation. This ensures the window is fully created before attempting to show it, preventing potential race conditions.

docs/api/browser.md (1)

1-225: Well-structured and comprehensive documentation.

The documentation provides a clear overview of the Browser class with complete method signatures, parameters descriptions, and return types. This will be valuable for developers working with the codebase and understanding the architecture.

🧰 Tools
🪛 LanguageTool

[grammar] ~19-~19: Possible subject-verb agreement error.
Context: ...instance and initializes the window and profile managers. Automatically creates the ini...

(IS_AND_ARE)


[uncategorized] ~23-~23: Loose punctuation mark.
Context: ...tion. ## Properties - profileManager: Manages browser profiles - `windowManag...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~39-~39: Loose punctuation mark.
Context: ... its ID. Parameters: - profileId: The ID of the profile to retrieve **Re...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~67-~67: Loose punctuation mark.
Context: ... needed. Parameters: - profileId: The ID of the profile to load **Return...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~83-~83: Loose punctuation mark.
Context: ...e by ID. Parameters: - profileId: The ID of the profile to unload **Retu...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~104-~104: Loose punctuation mark.
Context: ...owser window. Parameters: - type: The type of window to create (default: ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~133-~133: Loose punctuation mark.
Context: ...y its ID. Parameters: - windowId: The ID of the window to retrieve **Ret...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~149-~149: Loose punctuation mark.
Context: ...tents. Parameters: - webContents: The WebContents instance to find the wi...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~165-~165: Loose punctuation mark.
Context: ...y its ID. Parameters: - windowId: The ID of the window to destroy **Retu...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~214-~214: Loose punctuation mark.
Context: ...b by its ID. Parameters: - tabId: The ID of the tab to retrieve **Return...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~224-~224: Loose punctuation mark.
Context: ...emits the following events: - destroy: Emitted when the browser is destroyed

(UNLIKELY_OPENING_PUNCTUATION)

electron/sessions/profiles.ts (3)

17-20: Good addition of createdAt timestamp field.

Adding a creation timestamp is a valuable improvement that enables chronological sorting, filtering, and auditing of profiles.


154-160: Improved profile sorting by creation time.

The sorting implementation ensures profiles are displayed in chronological order, providing a more intuitive user experience.


61-96: Good enhancement to the createProfile function.

Making space creation optional with the shouldCreateSpace parameter improves flexibility, and using generateID() instead of a fixed "default" string for space IDs increases security and prevents collisions.

vite/package.json (1)

2-58: Package updates and dependency improvements look good.

Updates include:

  1. Renaming to "flow-frontend" for better clarity
  2. Updating to modern tooling (Tailwind v4, React 19)
  3. Adding new dependencies like "sonner" for toast notifications
  4. Using SWC for faster builds via the new React plugin and trusted dependencies

These changes should improve development experience and performance.

electron/ipc/session/spaces.ts (3)

63-65: Good design of setWindowSpace function.

This utility function provides a clean interface for updating the space associated with a window and ensures all core web contents receive the notification.


1-71: Well-structured IPC handler implementation.

The module provides a comprehensive set of IPC handlers for space management, following a consistent pattern. The integration with browser windows and event emission is well-designed.


67-69: 🛠️ Refactor suggestion

Add null check in fireOnSpacesChanged function.

The current implementation calls browser?.sendMessageToCoreWebContents but doesn't verify if the browser exists before using it. While the optional chaining operator prevents runtime errors, the function will silently fail if browser is null.

function fireOnSpacesChanged() {
-  browser?.sendMessageToCoreWebContents("spaces:on-changed");
+  if (browser) {
+    browser.sendMessageToCoreWebContents("spaces:on-changed");
+  }
}

Likely an incorrect or invalid review comment.

vite/public/edge-surf-game-v1/resources/js/assert.js (4)

1-7: Well-structured file header with appropriate license and documentation.

The file header includes proper copyright notice, license information, and clear documentation of the file's purpose using JSDoc.


9-39: Well-implemented assertion function with thorough documentation.

The assert function is well-documented with detailed JSDoc annotations, including template typing for type safety and closurePrimitive integration for the Closure compiler. It properly handles error messages and returns the condition for fluent API usage. The implementation also includes a thoughtful debugging feature with the traceAssertionsForTesting flag.


41-65: Well-documented utility for marking unreachable code.

The assertNotReached function is thoroughly documented with a practical example of its usage in switch statements. This function helps identify programmer errors or unexpected inputs by marking code paths that should never be executed.


67-83: Type-safe instance checking with optimized error message creation.

The assertInstanceof function effectively validates object types with template typing for enhanced type safety. The implementation optimizes error message creation by only constructing messages when necessary, which is a good performance practice.

electron/browser/utility/hot-reload.ts (2)

1-12: Good implementation of file descriptor limit increase for development.

The setupHotReloadFileDescriptors function appropriately increases the file descriptor limit when hot reloading is enabled in development mode. This helps prevent the common "too many open files" errors that can occur during development with live reloading.


35-43: Good approach to request concurrency management.

The implementation of concurrency limits and randomized timeouts helps prevent Electron's INSUFFICIENT_RESOURCES errors effectively.

electron/browser/profile-manager.ts (7)

12-17: Well-designed LoadedProfile type with appropriate immutability.

The LoadedProfile type uses readonly properties to ensure immutability of critical profile data, while including a mutation method (unload) for lifecycle management. This is a good pattern for encapsulating related data and functionality.


22-31: Clean class structure with proper dependency injection.

The ProfileManager class is well-structured with clear separation of concerns. It properly manages its dependencies through constructor injection, making it easier to test and maintain.


36-45: Efficient profile retrieval methods.

The profile retrieval methods are concise and efficient, using appropriate data structures (Map) and conversion methods (Array.from).


50-88: Comprehensive profile loading with error handling.

The loadProfile method includes proper validation, error handling, and state management. The user agent scrubbing is also a nice touch for better browser emulation.


107-120: Clean profile unloading with error handling.

The unloadProfile method provides appropriate validation and error handling when unloading individual profiles.


125-134: Robust error handling during mass profile unloading.

The unloadAll method ensures that errors in one profile don't prevent others from being unloaded, which is good for system stability during shutdown.


93-102:

Details

❓ Verification inconclusive

Potential session cleanup issue in handleProfileUnload.

When unloading a profile, the tabs are destroyed, but there's no explicit cleanup for the Electron session object.


🏁 Script executed:

#!/bin/bash
# Check if Session objects need explicit cleanup
rg -B 3 -A 3 "session\.(clearCache|clearStorageData|flushStorageData|clearHostResolverCache)" --type ts

# Check if session cleanup is handled elsewhere
rg -B 3 -A 3 "(session|Session).*destroy" --type ts

Length of output: 159


Ensure Electron session cleanup in handleProfileUnload

It looks like handleProfileUnload removes the profile and destroys its tabs, but never calls any Electron session cleanup APIs. Without explicit session teardown (e.g. clearCache, clearStorageData, etc.), you risk retaining stale data or memory leaks.

• File: electron/browser/profile-manager.ts
Lines: 93–102

Please verify whether session objects for unloaded profiles are cleaned up elsewhere or if you need to add explicit calls such as:

const ses = this.browser.getSessionForProfile(profileId);
ses.clearCache();
ses.clearStorageData();
electron/browser/utility/menu/helpers.ts (2)

23-39: Thorough null-checking in tab retrieval function.

The getTab function properly validates each step of retrieving a tab, with appropriate null checks and type narrowing. This defensive programming approach helps prevent runtime errors.


41-57: Well-composed helper functions for common tab operations.

These functions build upon each other to provide convenient access to commonly needed window and tab information with proper null handling throughout.

electron/browser/utility/menu/items/spaces.ts (1)

99-100: Use CmdOrCtrl for cross‑platform accelerators
Ctrl+N‑style shortcuts do not work on macOS. Replace with CmdOrCtrl+${index+1} to honour platform conventions.

-    accelerator: `Ctrl+${index + 1}`,
+    accelerator: `CmdOrCtrl+${index + 1}`,
shared/types/tabs.ts (1)

1-38: LGTM - Well-structured type definitions

The type definitions are well-organized, comprehensive, and properly structured. These types provide a solid foundation for the tab management system.

electron/browser/window.ts (1)

70-73: show: false but no explicit .show() for pop‑ups

Only the "ready-to-show" listener calls window.show(); that listener is always attached, but comment says “Show after ready”.
For popup windows the UI comment says // TODO: Show popup UI, yet no condition overrides the default hidden state. Ensure pop‑ups become visible or explicitly document that some external code calls window.show() later.

electron/browser/tabs/tab.ts (1)

333-361: Background‑tab logic focuses the tab

setActiveTab(newTab) is called for background tabs, contradicting the
expected behaviour (the opener should stay focused).

-if ((isForegroundTab && !glanced) || isBackgroundTab) {
-  this.tabManager.setActiveTab(newTab);
-}
+if (isForegroundTab && !glanced) {
+  this.tabManager.setActiveTab(newTab);
+}
electron/browser/tabs/tab-groups/index.ts (1)

160-171: Ensure disconnect callbacks exist before invocation

disconnectAll() is declared before disconnect1…disconnect6 are initialised; if any tab emits destroyed synchronously during connect(), disconnectAll() could execute while the variables are still undefined, raising TypeError: disconnectX is not a function.

A defensive guard prevents unintended runtime failures:

-    const disconnectAll = () => {
-      disconnect1();
-      disconnect2();
-
-    };
+    const disconnectAll = () => {
+      disconnect1?.();
+      disconnect2?.();
+      disconnect3?.();
+      disconnect4?.();
+      disconnect5?.();
+      disconnect6?.();
+    };
electron/sessions/spaces.ts (1)

291-317: updateSpaceOrder / reorderSpaces allow duplicate orders

Without uniqueness checks, two spaces can end up with the same order, breaking the deterministic sort in getSpaces(). Before writing, verify that:

  1. No duplicates exist in the incoming orderMap.
  2. Existing orders are updated atomically (single transaction or Promise.allSettled rollback).

At minimum:

const seen = new Set<number>();
for (const { order } of orderMap) {
  if (seen.has(order)) throw new Error(`Duplicate order ${order}`);
  seen.add(order);
}

Comment on lines +202 to +211
public get tabs(): Tab[] {
this.errorIfDestroyed();

const tabManager = this.tabManager;
return this.tabIds
.map((id) => {
return getTabFromId(tabManager, id);
})
.filter((tab) => tab !== null);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix return‑type mismatch in tabs getter

Array.prototype.filter() does not narrow the union type, so the current implementation still returns (Tab | null)[], which violates the declared return type Tab[] and fails tsc.

-    return this.tabIds
-      .map((id) => {
-        return getTabFromId(tabManager, id);
-      })
-      .filter((tab) => tab !== null);
+    return this.tabIds
+      .map((id) => getTabFromId(tabManager, id))
+      // Type‑predicate ensures the array is narrowed to Tab[]
+      .filter((tab): tab is Tab => tab !== null);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public get tabs(): Tab[] {
this.errorIfDestroyed();
const tabManager = this.tabManager;
return this.tabIds
.map((id) => {
return getTabFromId(tabManager, id);
})
.filter((tab) => tab !== null);
}
public get tabs(): Tab[] {
this.errorIfDestroyed();
const tabManager = this.tabManager;
return this.tabIds
.map((id) => getTabFromId(tabManager, id))
// Type‑predicate ensures the array is narrowed to Tab[]
.filter((tab): tab is Tab => tab !== null);
}

Comment on lines +150 to +158
const onActiveTabChanged = (windowId: number, spaceId: string) => {
if (windowId === this.windowId && spaceId === this.spaceId) {
const activeTab = this.tabManager.getActiveTab(windowId, spaceId);
if (activeTab === tab) {
// Set this tab group as active instead of just the tab
// @ts-expect-error: the base class won't be used directly anyways
this.tabManager.setActiveTab(this);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Remove the @ts-expect-error by widening TabManager.setActiveTab’s type

The cast is only required because setActiveTab accepts Tab | TabGroup, whereas BaseTabGroup (this) is not assignable to the union.
A cleaner approach is to make BaseTabGroup itself part of the union:

-export type TabGroup = GlanceTabGroup | SplitTabGroup;
+export type TabGroup = GlanceTabGroup | SplitTabGroup | BaseTabGroup;

(or alter setActiveTab to accept BaseTabGroup).
This removes the need for @ts-expect-error, keeps strict type‑safety, and prevents hiding legitimate future errors.

Comment on lines +142 to 157
try {
// Destroy all windows
this.windowManager.destroyAll();

// Unload all profiles
this.profileManager.unloadAll();

// Mark as destroyed and emit event
this._isDestroyed = true;
this.emit("destroy");
} catch (error) {
console.error("Error during browser destruction:", error);
} finally {
// Always destroy the emitter
this.destroyEmitter();
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

destroy() can leave the instance half‑destroyed when an error occurs

If windowManager.destroyAll() or profileManager.unloadAll() throws, _isDestroyed is never set, yet destroyEmitter() is still called. Subsequent calls will therefore:

  1. Pass the if (this._isDestroyed) check (it’s still false).
  2. Attempt to emit on an already‑destroyed emitter → runtime error.

Move the flag assignment into finally to guarantee a consistent state:

-      // Mark as destroyed and emit event
-      this._isDestroyed = true;
-      this.emit("destroy");
-    } catch (error) {
+      this.emit("destroy");
+    } catch (error) {
       console.error("Error during browser destruction:", error);
-    } finally {
-      // Always destroy the emitter
-      this.destroyEmitter();
+    } finally {
+      this._isDestroyed = true;
+      this.destroyEmitter();           // always run last
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
try {
// Destroy all windows
this.windowManager.destroyAll();
// Unload all profiles
this.profileManager.unloadAll();
// Mark as destroyed and emit event
this._isDestroyed = true;
this.emit("destroy");
} catch (error) {
console.error("Error during browser destruction:", error);
} finally {
// Always destroy the emitter
this.destroyEmitter();
}
try {
// Destroy all windows
this.windowManager.destroyAll();
// Unload all profiles
this.profileManager.unloadAll();
// Emit destroy event only if teardown succeeded
this.emit("destroy");
} catch (error) {
console.error("Error during browser destruction:", error);
} finally {
// Always mark destroyed and then destroy the emitter
this._isDestroyed = true;
this.destroyEmitter(); // always run last
}

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (4)
electron/browser/tabs/tab.ts (4)

158-175: ⚠️ Potential issue

createWindow is not supported in setWindowOpenHandler – links will spawn native windows

Electron’s setWindowOpenHandler only recognises { action, overrideBrowserWindowOptions, outlivesOpener }.
The custom createWindow key is silently ignored, so the handler falls back to the default behaviour and opens a new BrowserWindow, bypassing your tab system.

Reuse the pattern recommended in the previous review:

 this.webContents.setWindowOpenHandler(({ url, disposition, overrideBrowserWindowOptions }) => {
-  return {
-    action: "allow",
-    outlivesOpener: true,
-    createWindow: (constructorOptions) => {
-      return this.createNewTab(url, disposition, constructorOptions);
-    }
-  };
+  if (["new-window", "foreground-tab", "background-tab"].includes(disposition)) {
+    this.createNewTab(url, disposition, overrideBrowserWindowOptions);
+    return { action: "deny" };          // We handled it.
+  }
+  return { action: "allow" };           // Let Electron do the rest.
 });

193-200: ⚠️ Potential issue

Still using the non‑existent window.fullScreen property

BrowserWindow exposes .isFullScreen(); there is no fullScreen boolean.
As written, the guard clauses always evaluate to undefined, so fullscreen toggling misbehaves and can recurse indefinitely.

-      if (!window.fullScreen) {
+      if (!window.isFullScreen()) {
         window.setFullScreen(true);
       }
 …
-      if (window.fullScreen) {
+      if (window.isFullScreen()) {
         window.setFullScreen(false);
       }

462-466: ⚠️ Potential issue

URL.parse does not exist – runtime crash on error pages

URL is a constructor, it has no static parse method.
Calling it throws and breaks the error‑handling flow, potentially sending the renderer into an exception loop.

-    const parsedURL = URL.parse(url);
-    if (parsedURL && parsedURL.protocol === "flow:" && parsedURL.hostname === "error") {
+    let parsedURL: URL | null = null;
+    try {
+      parsedURL = new URL(url);
+    } catch { /* malformed – ignore */ }
+    if (parsedURL && parsedURL.protocol === "flow:" && parsedURL.hostname === "error") {
       return;
     }

630-634: ⚠️ Potential issue

Native resources of WebContentsView never freed

removeViewFromWindow() only detaches the view; the underlying WebContentsView still holds native resources.
Call its .destroy() method after closing the WebContents to avoid memory leaks.

 this.removeViewFromWindow();
 this.webContents.close();
+this.view.destroy();   // <-- free native resources
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0b298c3 and 051798b.

📒 Files selected for processing (3)
  • electron/browser/tabs/tab-context-menu.ts (1 hunks)
  • electron/browser/tabs/tab.ts (1 hunks)
  • electron/browser/utility/menu/items/archive.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • electron/browser/utility/menu/items/archive.ts
🧰 Additional context used
🧬 Code Graph Analysis (1)
electron/browser/tabs/tab.ts (10)
electron/browser/browser.ts (1)
  • Browser (19-175)
electron/browser/tabs/tab-manager.ts (2)
  • TabManager (25-668)
  • NEW_TAB_URL (11-11)
electron/browser/window.ts (1)
  • TabbedBrowserWindow (25-190)
electron/modules/typed-event-emitter.ts (1)
  • TypedEventEmitter (8-107)
shared/types/tabs.ts (1)
  • TabGroupMode (1-1)
electron/browser/tabs/tab-bounds.ts (2)
  • TabBoundsController (51-266)
  • isRectangleEqual (22-33)
electron/modules/favicons.ts (1)
  • cacheFavicon (424-486)
electron/browser/tabs/tab-context-menu.ts (1)
  • createTabContextMenu (8-100)
electron/modules/flags.ts (1)
  • FLAGS (16-40)
electron/browser/tabs/tab-groups/glance.ts (1)
  • GlanceTabGroup (3-21)

Comment on lines +17 to +25
contextMenu({
window: webContents,
menu(
defaultActions,
parameters,
_browserWindow,
dictionarySuggestions,
_event
): Electron.MenuItemConstructorOptions[] {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Dispose the context‑menu to avoid per‑tab memory leaks

electron-context-menu returns a dispose function that must be called once the tab (or its WebContents) is destroyed.
Without this, every opened/closed tab keeps an event‐listener chain alive and the module’s global registry slowly grows, leaking memory and slowing down menu generation.

-  contextMenu({
+  const disposeCtxMenu = contextMenu({
     window: webContents,
     menu(
       ...
     ): Electron.MenuItemConstructorOptions[] {
       ...
     }
   });

+  // ❶ Dispose when the WebContents goes away
+  webContents.once("destroyed", disposeCtxMenu);

If you prefer keeping the clean‑up logic inside Tab, expose the dispose function to the caller and attach it there.
Either way, ensure the listener is released exactly once.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
contextMenu({
window: webContents,
menu(
defaultActions,
parameters,
_browserWindow,
dictionarySuggestions,
_event
): Electron.MenuItemConstructorOptions[] {
const disposeCtxMenu = contextMenu({
window: webContents,
menu(
defaultActions,
parameters,
_browserWindow,
dictionarySuggestions,
_event
): Electron.MenuItemConstructorOptions[] {
// … existing menu setup …
}
});
// ❶ Dispose when the WebContents goes away
webContents.once("destroyed", disposeCtxMenu);

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (4)
electron/browser/tabs/tab.ts (4)

159-176: Unsupported createWindow key – handler will silently ignore it

webContents.setWindowOpenHandler does not recognise a createWindow property; only action, overrideBrowserWindowOptions, and outlivesOpener are honoured (Electron ≥ 12).
As written, links with target="_blank" will still spawn native windows, defeating the tabbing model.

-this.webContents.setWindowOpenHandler((details) => {
-
-  return {
-    action: "allow",
-    outlivesOpener: true,
-    createWindow: (constructorOptions) => {
-      return this.createNewTab(details.url, details.disposition, constructorOptions);
-    }
-  };
-});
+this.webContents.setWindowOpenHandler(({ url, disposition }) => {
+  if (["new-window", "foreground-tab", "background-tab"].includes(disposition)) {
+    this.createNewTab(url, disposition as any);
+    return { action: "deny" };                   // we handled it
+  }
+  return { action: "allow" };
+});

Re‑introducing this fix will bring the implementation in line with Electron’s API and with the guidance from the prior review.


194-201: BrowserWindow.fullScreen is not a property – use isFullScreen()

window.fullScreen is always undefined; consequently these guards never execute and you risk infinite recursion or phantom fullscreen toggles.

-if (!window.fullScreen) {
-  window.setFullScreen(true);
-}
+if (!window.isFullScreen()) {
+  window.setFullScreen(true);
+}-if (window.fullScreen) {
-  window.setFullScreen(false);
-}
+if (window.isFullScreen()) {
+  window.setFullScreen(false);
+}

Same issue was highlighted in the earlier review; please replace the property access everywhere it appears.


462-466: URL.parse does not exist – causes runtime crash on error pages

URL is the WHATWG constructor; it has no static parse method. Calling it throws and the fallback logic never triggers, potentially looping on error pages.

-const parsedURL = URL.parse(url);
-if (parsedURL && parsedURL.protocol === "flow:" && parsedURL.hostname === "error") {
+let parsed: URL | null = null;
+try {
+  parsed = new URL(url);
+} catch {/* malformed */}
+if (parsed && parsed.protocol === "flow:" && parsed.hostname === "error") {
   return;
 }

This exact defect was previously reported; please amend it to prevent renderer crashes.


631-635: Potential native‑resource leak – view.destroy() never called

removeViewFromWindow() only detaches the view; the underlying WebContentsView still owns GPU and window‑server resources.
Call this.view.destroy() after closing the webContents to release them.

 this.removeViewFromWindow();
 this.webContents.close();
+this.view.destroy();         // ← free native resources

Leaving the objects alive can accumulate leaked surfaces when many tabs are opened/closed.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 051798b and ea76cef.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (4)
  • electron/browser/tabs/tab.ts (1 hunks)
  • electron/modules/flags.ts (2 hunks)
  • electron/package.json (2 hunks)
  • vite/package.json (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • electron/modules/flags.ts
  • electron/package.json
  • vite/package.json

Comment on lines +450 to +456
if (replace) {
// Replace mode is not very reliable, don't know if this works :)
const sanitizedUrl = url.replace(/`/g, "\\`").replace(/"/g, '\\"');
this.webContents.executeJavaScript(`window.location.replace("${sanitizedUrl}")`);
} else {
this.webContents.loadURL(url);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Potential XSS / injection via unsanitised string interpolation

loadURL(..., replace=true) injects the raw URL into executeJavaScript, escaping only back‑ticks and double‑quotes.
Characters such as ${}, <, > or single quotes can still break out of the string literal and execute arbitrary JS in the renderer.

-const sanitizedUrl = url.replace(/`/g, "\\`").replace(/"/g, '\\"');
-this.webContents.executeJavaScript(`window.location.replace("${sanitizedUrl}")`);
+const sanitizedUrl = encodeURIComponent(url);
+this.webContents.executeJavaScript(
+  `window.location.replace(decodeURIComponent("${sanitizedUrl}"))`
+);

encodeURIComponent ensures the value is opaque to the JS parser while preserving fidelity after decoding.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (replace) {
// Replace mode is not very reliable, don't know if this works :)
const sanitizedUrl = url.replace(/`/g, "\\`").replace(/"/g, '\\"');
this.webContents.executeJavaScript(`window.location.replace("${sanitizedUrl}")`);
} else {
this.webContents.loadURL(url);
}
if (replace) {
// Replace mode is not very reliable, don't know if this works :)
const sanitizedUrl = encodeURIComponent(url);
this.webContents.executeJavaScript(
`window.location.replace(decodeURIComponent("${sanitizedUrl}"))`
);
} else {
this.webContents.loadURL(url);
}

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

♻️ Duplicate comments (2)
electron/browser/window.ts (2)

133-137: ⚠️ Potential issue

Promise callback needs isDestroyed guard (repeat of earlier feedback)

getLastUsedSpace() may resolve after the window has already been destroyed; the callback then calls setCurrentSpace, touching objects that no longer exist and possibly throwing.
This was pointed out in a previous review but has not been addressed.

-    getLastUsedSpace().then((space) => {
-      if (space) {
-        this.setCurrentSpace(space.id);
-      }
-    });
+    getLastUsedSpace().then((space) => {
+      if (!this.isDestroyed && space) {
+        this.setCurrentSpace(space.id);
+      }
+    });

151-155: ⚠️ Potential issue

Broadcast failures still not handled – add try/catch per WebContents

WebContents.send throws if the target has been destroyed.
A single failure aborts the loop, silently preventing delivery to the remaining views.

-    for (const content of this.coreWebContents) {
-      content.send(channel, ...args);
-    }
+    for (const content of this.coreWebContents) {
+      try {
+        if (!content.isDestroyed()) {
+          content.send(channel, ...args);
+        }
+      } catch {
+        /* ignore dead targets; optionally purge them from the array */
+      }
+    }
🧹 Nitpick comments (8)
electron/browser/utility/menu/items/view.ts (2)

29-31: Consider simplifying the redundant window check.

Since winData has already been checked at line 12, and we only reach this code if winData exists, the additional check for winData.window at line 29 might be redundant. However, this is a minor point and could be considered defensive programming.

-      if (winData.window) {
         winData.window.close();
-      }

42-48: Consider combining the null checks for better readability.

The null checks could be combined to make the code more concise while maintaining the same functionality.

      click: () => {
        const winData = getFocusedBrowserWindowData();
-       if (!winData) return;
-       if (winData.tabbedBrowserWindow) {
+       if (winData?.tabbedBrowserWindow) {
          toggleSidebar(winData.tabbedBrowserWindow);
        }
      }
electron/browser/close-preventer.ts (3)

35-40: Consider a more efficient approach to detecting new WebContents.

The current implementation uses a frequent polling interval (100ms) to detect new WebContents. While functional, this could potentially have performance implications.

Consider using Electron's events to detect new WebContents instead of polling:

-if (enabled) {
-    scan();
-    setInterval(() => {
-        scan();
-    }, 100);
-}
+if (enabled) {
+    scan(); // Initial scan
+    
+    // Listen for new-web-contents event on app
+    const { app } = require('electron');
+    app.on('web-contents-created', (event, webContents) => {
+        newWebContents(webContents);
+    });
+}

This approach would be more efficient as it only registers new WebContents when they're actually created.


12-27: Add cleanup to prevent potential memory leaks.

The current implementation doesn't remove event listeners when WebContents are destroyed, which could lead to memory leaks over time.

Consider adding cleanup logic to remove listeners when WebContents are destroyed:

function newWebContents(webContents: WebContents) {
    if (!enabled) return;

    if (registeredWebContentIds.has(webContents.id)) return;
    registeredWebContentIds.add(webContents.id);

    webContents.on("before-input-event", (event, input) => {
        if (input.key === "w" && input.control) {
            event.preventDefault();

            if (browser && input.type === "keyDown") {
                menuCloseTab(browser);
            }
        }
    });
+    
+    // Clean up when the WebContents is destroyed
+    webContents.once('destroyed', () => {
+        registeredWebContentIds.delete(webContents.id);
+    });
}

This ensures proper cleanup when WebContents are destroyed.


18-26: Add error handling to menuCloseTab call.

There's no error handling around the call to menuCloseTab, which could cause issues if that function throws an error.

Consider adding try/catch to handle potential errors:

webContents.on("before-input-event", (event, input) => {
    if (input.key === "w" && input.control) {
        event.preventDefault();

        if (browser && input.type === "keyDown") {
-            menuCloseTab(browser);
+            try {
+                menuCloseTab(browser);
+            } catch (error) {
+                console.error('Error closing tab:', error);
+            }
        }
    }
});

This prevents keyboard event handling from breaking if an error occurs in the tab closing logic.

vite/src/components/onboarding/stages/initial-space/create.tsx (3)

69-79: Unclear space ID generation logic.

The code creates a space with a name and then looks up the space by name to get its ID. Consider adding a comment explaining how space IDs are generated or directly specifying the ID if possible.

- const created = await flow.spaces.createSpace(mainProfile.id, spaceName);
+ // Space IDs are generated by the API based on the space name
+ const created = await flow.spaces.createSpace(mainProfile.id, spaceName);

84-87: Consider longer success delay for better user experience.

The automatic advancement after space creation only waits 1 second, which might be too quick for users to read and comprehend the success message.

- setTimeout(() => {
-   advance();
- }, 1000);
+ // Give users a bit more time to read the success message
+ setTimeout(() => {
+   advance();
+ }, 2500);

117-136: Consider extracting repeated message UI patterns.

Several UI sections (loading, error, missing profile, etc.) share similar structures but with different content. Consider extracting this pattern into a reusable component for better maintainability.

// MessageCard component that could be defined elsewhere
function MessageCard({ 
  icon, 
  iconColor = "text-amber-400", 
  title, 
  message, 
  actionButton 
}) {
  return (
    <div className="flex flex-col items-center justify-center h-56 text-center">
      {icon && <div className={`h-10 w-10 ${iconColor} mb-3`}>{icon}</div>}
      <div className="text-white text-lg font-medium mb-1">{title}</div>
      <div className="text-gray-400 max-w-md mb-4">{message}</div>
      {actionButton}
    </div>
  );
}

// Usage example:
<MessageCard
  icon={<AlertCircle />}
  title="Something went wrong"
  message={errorMessage}
  actionButton={
    <Button
      onClick={advance}
      className="remove-app-drag cursor-pointer px-6 py-2 bg-[#0066FF]/10 hover:bg-[#0066FF]/20 text-white backdrop-blur-md border border-[#0066FF]/30"
    >
      Skip & Continue
    </Button>
  }
/>

Also applies to: 137-150, 151-164, 165-170

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ea76cef and d55f632.

📒 Files selected for processing (6)
  • electron/browser/close-preventer.ts (1 hunks)
  • electron/browser/utility/hot-reload.ts (1 hunks)
  • electron/browser/utility/menu/items/view.ts (1 hunks)
  • electron/browser/window.ts (1 hunks)
  • electron/onboarding/main.ts (1 hunks)
  • vite/src/components/onboarding/stages/initial-space/create.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • electron/browser/utility/hot-reload.ts
  • electron/onboarding/main.ts
🧰 Additional context used
🧬 Code Graph Analysis (2)
electron/browser/close-preventer.ts (2)
electron/index.ts (1)
  • browser (9-9)
electron/browser/utility/menu/items/view.ts (1)
  • menuCloseTab (10-34)
vite/src/components/onboarding/stages/initial-space/create.tsx (6)
vite/src/components/onboarding/main.tsx (1)
  • OnboardingAdvanceCallback (11-11)
vite/src/lib/flow/interfaces/sessions/profiles.ts (1)
  • Profile (1-4)
electron/sessions/spaces.ts (1)
  • createSpace (82-127)
vite/src/components/ui/button.tsx (1)
  • Button (50-50)
vite/src/components/ui/label.tsx (1)
  • Label (19-19)
vite/src/components/ui/input.tsx (1)
  • Input (21-21)
🔇 Additional comments (16)
electron/browser/utility/menu/items/view.ts (2)

10-34: Well-structured tab/window closing logic with good defensive checks.

The menuCloseTab function handles different closing scenarios appropriately by checking window type and omnibox state before taking action. The early return pattern makes the control flow clear and maintainable.


36-92: Well-organized view menu with appropriate keyboard shortcuts.

The menu structure follows Electron best practices with clear grouping using separators, platform-specific keyboard shortcuts, and appropriate use of built-in roles for standard operations. Each menu item correctly handles potential null cases before performing actions.

electron/browser/close-preventer.ts (5)

1-6: LGTM! Good documentation of purpose.

The file starts with clear comments explaining its purpose - to prevent Ctrl+W from closing the entire window on Windows and instead close only the current tab.


8-9: LGTM! Good platform-specific implementation.

Correctly implementing the feature only for Windows platform where this behavior is needed.


10-11: LGTM! Good use of Set for tracking registered web contents.

Using a Set to track registered WebContents IDs prevents duplicate event listeners.


12-27: LGTM! Well-implemented event handling.

The event handling logic is clean and focused:

  1. Skips registration if not on Windows or if already registered
  2. Correctly intercepts Ctrl+W
  3. Only triggers on keyDown events to avoid duplicate calls
  4. Checks that browser is available before calling menuCloseTab

29-33: LGTM! Simple scanning implementation.

The scan function efficiently retrieves all WebContents and registers them.

vite/src/components/onboarding/stages/initial-space/create.tsx (9)

1-9: Good component imports and type definitions.

The imports are well-organized, with clear separation between React components, custom components, third-party libraries, and type definitions.


12-18: Well-structured component props.

The component props have clear TypeScript typing, which enhances code maintainability and provides good developer experience with type safety.


19-28: Good use of granular state variables.

The component uses separate state variables for different aspects of the UI state, which makes the code more readable and easier to reason about.


31-58: Proper async data fetching with error handling.

The useEffect hook correctly implements async data fetching with proper loading states and error handling. The effect runs only on mount with an empty dependency array, which is appropriate for this initialization logic.


97-116: Good use of motion animations for transitions.

The component uses motion animations effectively to create a smooth and polished onboarding experience, with appropriate timing and easing functions.


187-202: Good button state handling.

The create button properly disables during the creation process and shows a loading spinner, preventing duplicate submissions and providing clear user feedback.


208-225: Well-implemented skip button with conditional rendering.

The skip button is appropriately shown only in relevant states and provides a good escape route for users who want to bypass this step.


1-228: Comprehensive onboarding component with good UX considerations.

Overall, this is a well-implemented onboarding component with thorough state management, error handling, and user feedback. It handles multiple states gracefully and provides appropriate UI for each scenario. The component effectively integrates with the Flow API for profile and space management.


61-95:

Details

❌ Incorrect review comment

Potential API mismatch in createSpace function call.

The createSpace function appears to be called with only two parameters (profileId and spaceName), but based on the provided code snippets, the implementation might expect three parameters (profileId, spaceId, and spaceName).

Please verify that the flow.spaces.createSpace API matches the implementation. Run this script to check the actual implementation:


🏁 Script executed:

#!/bin/bash
# Find the implementation of the createSpace function in the Flow API
rg -A 5 "createSpace.*\(.*\)" --glob "*.ts"

Length of output: 3433


createSpace API correctly uses two parameters

The flow.spaces.createSpace method in the UI is intentionally defined to accept only (profileId, spaceName). Internally, the IPC handler generates the spaceId before invoking the lower‑level implementation. No changes are needed here.

• vite/src/lib/flow/interfaces/sessions/spaces.ts:
  createSpace: (profileId: string, spaceName: string) => Promise<boolean>;
• electron/preload.ts:
  createSpace: async (profileId: string, spaceName: string) => { … }
• electron/ipc/session/spaces.ts:
  ipcMain.handle("spaces:create", …) { return createSpace(profileId, generateID(), spaceName); }

Likely an incorrect or invalid review comment.

Comment on lines +157 to +177
destroy() {
if (this.isDestroyed) {
throw new Error("Window already destroyed!");
}

// Destroy the window
this.isDestroyed = true;
this.emit("destroy");
this.browser.destroyWindowById(this.id);

// WE CANNOT CALL REMOVECHILDVIEW AFTER DESTROY, OR IT WILL CRASH!!!!
const windowDestroyed = this.window.isDestroyed();
this.viewManager.destroy(windowDestroyed);

this.glanceModal.destroy();
this.omnibox.destroy();

if (!windowDestroyed) {
this.window.destroy();
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

destroy() throws on double invocation – make it idempotent

BrowserWindow emits "closed" after window.destroy(); if some code calls destroy() first, the "closed" event triggers a second call, causing the explicit throw.
Fail‑fast here bubbles an unhandled exception during normal teardown.

-    if (this.isDestroyed) {
-      throw new Error("Window already destroyed!");
-    }
+    if (this.isDestroyed) {
+      return; // already cleaned up
+    }

As an additional safeguard you could remove the "closed" listener inside destroy() or gate the listener itself with if (!this.isDestroyed).

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
destroy() {
if (this.isDestroyed) {
throw new Error("Window already destroyed!");
}
// Destroy the window
this.isDestroyed = true;
this.emit("destroy");
this.browser.destroyWindowById(this.id);
// WE CANNOT CALL REMOVECHILDVIEW AFTER DESTROY, OR IT WILL CRASH!!!!
const windowDestroyed = this.window.isDestroyed();
this.viewManager.destroy(windowDestroyed);
this.glanceModal.destroy();
this.omnibox.destroy();
if (!windowDestroyed) {
this.window.destroy();
}
destroy() {
- if (this.isDestroyed) {
- throw new Error("Window already destroyed!");
- }
+ if (this.isDestroyed) {
+ return; // already cleaned up
+ }
// Destroy the window
this.isDestroyed = true;
this.emit("destroy");
this.browser.destroyWindowById(this.id);
// WE CANNOT CALL REMOVECHILDVIEW AFTER DESTROY, OR IT WILL CRASH!!!!
const windowDestroyed = this.window.isDestroyed();
this.viewManager.destroy(windowDestroyed);
this.glanceModal.destroy();
this.omnibox.destroy();
if (!windowDestroyed) {
this.window.destroy();
}
}

Comment on lines 75 to 88

if (newSpace) {
// Save the space ID for the next steps
setActiveSpaceId(newSpace.id);

// Show success message
setCreateSuccess(true);

// Automatically advance after short delay
setTimeout(() => {
advance();
}, 1000);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add error handling for when space is created but not found.

If space creation succeeds but the newly created space isn't found when fetching the updated list, the code doesn't handle this edge case.

 const newSpace = spaces.find((s) => s.name === spaceName);

 if (newSpace) {
   // Save the space ID for the next steps
   setActiveSpaceId(newSpace.id);

   // Show success message
   setCreateSuccess(true);

   // Automatically advance after short delay
   setTimeout(() => {
     advance();
   }, 1000);
+} else {
+  // Space was created but not found in the updated list
+  console.error("Space was created but not found in the updated list");
+  setErrorMessage("Space created but couldn't be activated. You can manage spaces later in settings.");
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (newSpace) {
// Save the space ID for the next steps
setActiveSpaceId(newSpace.id);
// Show success message
setCreateSuccess(true);
// Automatically advance after short delay
setTimeout(() => {
advance();
}, 1000);
}
}
if (newSpace) {
// Save the space ID for the next steps
setActiveSpaceId(newSpace.id);
// Show success message
setCreateSuccess(true);
// Automatically advance after short delay
setTimeout(() => {
advance();
}, 1000);
} else {
// Space was created but not found in the updated list
console.error("Space was created but not found in the updated list");
setErrorMessage("Space created but couldn't be activated. You can manage spaces later in settings.");
}
}

Comment on lines +171 to +184
<div className="overflow-hidden backdrop-blur-md bg-white/5 border border-white/10 rounded-lg p-6 remove-app-drag">
{/* Space Name */}
<div className="space-y-2 mb-6">
<Label htmlFor="space-name" className="text-white text-sm">
Space Name
</Label>
<Input
id="space-name"
value={spaceName}
onChange={(e) => setSpaceName(e.target.value)}
className="bg-white/10 border-white/30 text-white"
placeholder={DEFAULT_SPACE_NAME}
/>
</div>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add validation for space name input.

The component disables the create button for empty space names but doesn't provide validation feedback or constraints on space name format or length.

 <Input
   id="space-name"
   value={spaceName}
   onChange={(e) => setSpaceName(e.target.value)}
   className="bg-white/10 border-white/30 text-white"
   placeholder={DEFAULT_SPACE_NAME}
+  maxLength={50}
+  aria-describedby="space-name-validation"
 />
+{spaceName.trim() === "" && (
+  <p id="space-name-validation" className="text-sm text-amber-400 mt-1">
+    Space name cannot be empty
+  </p>
+)}

@iamEvanYT iamEvanYT merged commit 7787cce into main Apr 17, 2025
1 check was pending
@github-project-automation github-project-automation bot moved this from In progress to Done in Roadmap - Flow Browser Apr 17, 2025
@iamEvanYT iamEvanYT deleted the evan/reorganization branch April 17, 2025 11:37
@coderabbitai coderabbitai bot mentioned this pull request Apr 18, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

No open projects
Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant