update to new browseros patches, v20 release

This commit is contained in:
Nikhil Sonti
2025-08-11 11:46:10 -07:00
parent 235c91521c
commit 1785b589d9
41 changed files with 5047 additions and 7695 deletions

View File

@@ -1 +1 @@
46
49

View File

@@ -5,6 +5,7 @@
is_debug = true
is_official_build = false
is_component_build = false
use_siso=false
# Compiler
use_sysroot = true
@@ -42,4 +43,4 @@ v8_enable_i18n_support = true
# Debug specific
dcheck_always_on = true
enable_iterator_debugging = false
enable_iterator_debugging = false

View File

@@ -130,7 +130,7 @@ class BuildContext:
def get_nxtscape_patches_dir(self) -> Path:
"""Get Nxtscape specific patches directory"""
return join_paths(self.get_patches_dir(), "nxtscape")
return join_paths(self.get_patches_dir(), "browseros")
def get_sparkle_dir(self) -> Path:
"""Get Sparkle directory"""

View File

@@ -8,6 +8,23 @@
<language>en</language>
<!-- Updates -->
<item>
<title>Nxtscape - 0.20.0</title>
<description sparkle:format="plain-text">
- New updated Agent UI!
- Fixed MacOS bug which caused the app to crash on startup for some users. This unfortunately also makes a breaking change, requiring re-installation of extensions and logins.
</description>
<sparkle:version>7200.69</sparkle:version>
<sparkle:shortVersionString>0.20.1</sparkle:shortVersionString>
<pubDate>Fri, 09 Aug 2025 16:30:00 -0700</pubDate>
<link>https://nxtscape.ai</link>
<enclosure
url="http://cdn.browseros.com/dmg/BrowserOS_v0.20.1_x64.dmg"
sparkle:edSignature="T4s+dVxu+pPQn2pE061esTHIaD8e3mYdYItFEIfXjQtopfxutUbzHoYei3CuccKGIS1oDTVgZAR3EXaWBK5xBQ=="
length="135460780"
type="application/octet-stream" />
<sparkle:minimumSystemVersion>10.15</sparkle:minimumSystemVersion>
</item>
<item>
<title>Nxtscape - 0.19.0</title>
<description sparkle:format="plain-text">

View File

@@ -8,6 +8,23 @@
<language>en</language>
<!-- Updates -->
<item>
<title>Nxtscape - 0.20.0</title>
<description sparkle:format="plain-text">
- New updated Agent UI!
- Fixed MacOS bug which caused the app to crash on startup for some users. This unfortunately also makes a breaking change, requiring re-installation of extensions and logins.
</description>
<sparkle:version>7200.69</sparkle:version>
<sparkle:shortVersionString>0.20.1</sparkle:shortVersionString>
<pubDate>Fri, 09 Aug 2025 16:30:00 -0700</pubDate>
<link>https://nxtscape.ai</link>
<enclosure
url="http://cdn.browseros.com/dmg/BrowserOS_v0.20.1_arm64.dmg"
sparkle:edSignature="E91Zyc0wi3fVmarYBAct5qldCeZ0cw9ZpmG4WgeW+b1/2DiYNIAO/3f1qYh5osoKLETHrjwumYDANC0ao9kfCw=="
length="126189210"
type="application/octet-stream" />
<sparkle:minimumSystemVersion>10.15</sparkle:minimumSystemVersion>
</item>
<item>
<title>Nxtscape - 0.19.0</title>
<description sparkle:format="plain-text">

View File

@@ -1,17 +1,17 @@
From 5baf27ebd196f1762523600c41dda406e092c7a0 Mon Sep 17 00:00:00 2001
From 84acdc3e97b088b1c68b3cfbda04ddac80fbd35a Mon Sep 17 00:00:00 2001
From: Nikhil Sonti <nikhilsv92@gmail.com>
Date: Tue, 1 Jul 2025 13:57:56 -0700
Subject: [PATCH] patch app info with Sparkler udpater
Date: Tue, 22 Jul 2025 21:35:46 -0700
Subject: [PATCH] patch: app-info.plist changes
---
chrome/app/app-Info.plist | 10 ++++++++++
1 file changed, 10 insertions(+)
chrome/app/app-Info.plist | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/chrome/app/app-Info.plist b/chrome/app/app-Info.plist
index 9190c5ef6c092..debc1d8dabd34 100644
index 9190c5ef6c092..cf0106b8ba53e 100644
--- a/chrome/app/app-Info.plist
+++ b/chrome/app/app-Info.plist
@@ -409,5 +409,15 @@
@@ -409,5 +409,17 @@
<array>
<string>_googlecast._tcp</string>
</array>
@@ -25,6 +25,8 @@ index 9190c5ef6c092..debc1d8dabd34 100644
+ <true/>
+ <key>SUAutomaticallyUpdate</key>
+ <true/>
+ <key>CrProductDirName</key>
+ <string>BrowserOS</string>
</dict>
</plist>
--

View File

@@ -1,7 +1,7 @@
From bf9470a28e2b18c40599c7e6d5e7f5c592f29c53 Mon Sep 17 00:00:00 2001
From 0dc6cadba7a7f65ea9ef822ee7641e314372d663 Mon Sep 17 00:00:00 2001
From: Nikhil Sonti <nikhilsv92@gmail.com>
Date: Fri, 11 Jul 2025 08:55:19 -0700
Subject: [PATCH] adding new vector icons
Date: Tue, 22 Jul 2025 21:35:58 -0700
Subject: [PATCH] patch: adding-new-vector-icons
---
components/vector_icons/BUILD.gn | 2 +

View File

@@ -1,7 +1,7 @@
From bd59642e3bda4d9d87dd7b0a553e25bd4b49ef9a Mon Sep 17 00:00:00 2001
From 8d1ca75ba0a9a2f9f9e18c5644e7769cbec977a6 Mon Sep 17 00:00:00 2001
From: Nikhil Sonti <nikhilsv92@gmail.com>
Date: Thu, 24 Jul 2025 13:26:50 -0700
Subject: [PATCH 18/20] browseros branding for file paths
Subject: [PATCH] browseros branding for file paths
---
chrome/common/chrome_constants.cc | 18 +++++++++---------

View File

@@ -0,0 +1,954 @@
From a927b95e4e5ae7dae919521dd2cf9f2925695377 Mon Sep 17 00:00:00 2001
From: Nikhil Sonti <nikhilsv92@gmail.com>
Date: Fri, 8 Aug 2025 18:11:08 -0700
Subject: [PATCH] browseros metrics
---
.../metrics/chrome_metrics_service_client.cc | 2 +
chrome/browser/prefs/browser_prefs.cc | 2 +
...hrome_browser_main_extra_parts_profiles.cc | 2 +
chrome/browser/ui/BUILD.gn | 2 +
.../settings/browseros_metrics_handler.cc | 56 +++++
.../settings/browseros_metrics_handler.h | 39 ++++
.../browser/ui/webui/settings/settings_ui.cc | 2 +
chrome/common/pref_names.h | 4 +
components/metrics/browseros_metrics/BUILD.gn | 39 ++++
components/metrics/browseros_metrics/DEPS | 14 ++
.../browseros_metrics/browseros_metrics.cc | 100 +++++++++
.../browseros_metrics/browseros_metrics.h | 40 ++++
.../browseros_metrics_prefs.cc | 25 +++
.../browseros_metrics_prefs.h | 24 +++
.../browseros_metrics_service.cc | 201 ++++++++++++++++++
.../browseros_metrics_service.h | 81 +++++++
.../browseros_metrics_service_factory.cc | 56 +++++
.../browseros_metrics_service_factory.h | 48 +++++
18 files changed, 737 insertions(+)
create mode 100644 chrome/browser/ui/webui/settings/browseros_metrics_handler.cc
create mode 100644 chrome/browser/ui/webui/settings/browseros_metrics_handler.h
create mode 100644 components/metrics/browseros_metrics/BUILD.gn
create mode 100644 components/metrics/browseros_metrics/DEPS
create mode 100644 components/metrics/browseros_metrics/browseros_metrics.cc
create mode 100644 components/metrics/browseros_metrics/browseros_metrics.h
create mode 100644 components/metrics/browseros_metrics/browseros_metrics_prefs.cc
create mode 100644 components/metrics/browseros_metrics/browseros_metrics_prefs.h
create mode 100644 components/metrics/browseros_metrics/browseros_metrics_service.cc
create mode 100644 components/metrics/browseros_metrics/browseros_metrics_service.h
create mode 100644 components/metrics/browseros_metrics/browseros_metrics_service_factory.cc
create mode 100644 components/metrics/browseros_metrics/browseros_metrics_service_factory.h
diff --git a/chrome/browser/metrics/chrome_metrics_service_client.cc b/chrome/browser/metrics/chrome_metrics_service_client.cc
index ea4e1a621b201..21a7a3aef2872 100644
--- a/chrome/browser/metrics/chrome_metrics_service_client.cc
+++ b/chrome/browser/metrics/chrome_metrics_service_client.cc
@@ -75,6 +75,7 @@
#include "components/component_updater/component_updater_service.h"
#include "components/crash/core/common/crash_keys.h"
#include "components/history/core/browser/history_service.h"
+#include "components/metrics/browseros_metrics/browseros_metrics.h"
#include "components/metrics/call_stacks/call_stack_profile_metrics_provider.h"
#include "components/metrics/component_metrics_provider.h"
#include "components/metrics/content/content_stability_metrics_provider.h"
@@ -1041,6 +1042,7 @@ void ChromeMetricsServiceClient::RegisterUKMProviders() {
}
void ChromeMetricsServiceClient::NotifyApplicationNotIdle() {
+ browseros_metrics::BrowserOSMetrics::Log("alive", 0.01);
metrics_service_->OnApplicationNotIdle();
}
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index 9a00400829ae1..c83cfdfe3708c 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -102,6 +102,7 @@
#include "components/breadcrumbs/core/breadcrumbs_status.h"
#include "components/browsing_data/core/pref_names.h"
#include "components/certificate_transparency/pref_names.h"
+#include "components/metrics/browseros_metrics/browseros_metrics_prefs.h"
#include "components/collaboration/public/pref_names.h"
#include "components/commerce/core/pref_names.h"
#include "components/content_settings/core/browser/host_content_settings_map.h"
@@ -1868,6 +1869,7 @@ void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry,
AnnouncementNotificationService::RegisterProfilePrefs(registry);
autofill::prefs::RegisterProfilePrefs(registry);
browsing_data::prefs::RegisterBrowserUserPrefs(registry);
+ browseros_metrics::RegisterProfilePrefs(registry);
capture_policy::RegisterProfilePrefs(registry);
certificate_transparency::prefs::RegisterPrefs(registry);
ChromeContentBrowserClient::RegisterProfilePrefs(registry);
diff --git a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
index c6e46fb1d8030..f06e6e0e07cfa 100644
--- a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
+++ b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
@@ -49,6 +49,7 @@
#include "chrome/browser/collaboration/messaging/messaging_backend_service_factory.h"
#include "chrome/browser/commerce/shopping_service_factory.h"
#include "chrome/browser/consent_auditor/consent_auditor_factory.h"
+#include "components/metrics/browseros_metrics/browseros_metrics_service_factory.h"
#include "chrome/browser/content_index/content_index_provider_factory.h"
#include "chrome/browser/content_settings/cookie_settings_factory.h"
#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
@@ -722,6 +723,7 @@ void ChromeBrowserMainExtraPartsProfiles::
#endif
BitmapFetcherServiceFactory::GetInstance();
BluetoothChooserContextFactory::GetInstance();
+ browseros_metrics::BrowserOSMetricsServiceFactory::GetInstance();
#if defined(TOOLKIT_VIEWS)
BookmarkExpandedStateTrackerFactory::GetInstance();
BookmarkMergedSurfaceServiceFactory::GetInstance();
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 93096ad92c1a3..b14d64308080f 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -1566,6 +1566,8 @@ static_library("ui") {
"webui/settings/reset_settings_handler.h",
"webui/settings/search_engines_handler.cc",
"webui/settings/search_engines_handler.h",
+ "webui/settings/browseros_metrics_handler.cc",
+ "webui/settings/browseros_metrics_handler.h",
"webui/settings/settings_clear_browsing_data_handler.cc",
"webui/settings/settings_clear_browsing_data_handler.h",
"webui/settings/settings_localized_strings_privacy_sandbox_provider.cc",
diff --git a/chrome/browser/ui/webui/settings/browseros_metrics_handler.cc b/chrome/browser/ui/webui/settings/browseros_metrics_handler.cc
new file mode 100644
index 0000000000000..a213967b46676
--- /dev/null
+++ b/chrome/browser/ui/webui/settings/browseros_metrics_handler.cc
@@ -0,0 +1,56 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/settings/browseros_metrics_handler.h"
+
+#include "base/logging.h"
+#include "base/values.h"
+#include "components/metrics/browseros_metrics/browseros_metrics.h"
+
+namespace settings {
+
+BrowserOSMetricsHandler::BrowserOSMetricsHandler() = default;
+
+BrowserOSMetricsHandler::~BrowserOSMetricsHandler() = default;
+
+void BrowserOSMetricsHandler::RegisterMessages() {
+ web_ui()->RegisterMessageCallback(
+ "logBrowserOSMetric",
+ base::BindRepeating(&BrowserOSMetricsHandler::HandleLogBrowserOSMetric,
+ base::Unretained(this)));
+}
+
+void BrowserOSMetricsHandler::HandleLogBrowserOSMetric(
+ const base::Value::List& args) {
+ if (args.size() < 1 || !args[0].is_string()) {
+ LOG(WARNING) << "browseros: Invalid metric event name";
+ return;
+ }
+
+ const std::string& event_name = args[0].GetString();
+
+ if (args.size() > 1) {
+ // Has properties
+ if (args[1].is_dict()) {
+ base::Value::Dict properties = args[1].GetDict().Clone();
+ browseros_metrics::BrowserOSMetrics::Log(event_name, std::move(properties));
+ } else {
+ LOG(WARNING) << "browseros: Invalid metric properties format";
+ browseros_metrics::BrowserOSMetrics::Log(event_name);
+ }
+ } else {
+ // No properties
+ browseros_metrics::BrowserOSMetrics::Log(event_name);
+ }
+}
+
+void BrowserOSMetricsHandler::OnJavascriptAllowed() {
+ // No special setup needed
+}
+
+void BrowserOSMetricsHandler::OnJavascriptDisallowed() {
+ // No cleanup needed
+}
+
+} // namespace settings
\ No newline at end of file
diff --git a/chrome/browser/ui/webui/settings/browseros_metrics_handler.h b/chrome/browser/ui/webui/settings/browseros_metrics_handler.h
new file mode 100644
index 0000000000000..dfcb0485c0432
--- /dev/null
+++ b/chrome/browser/ui/webui/settings/browseros_metrics_handler.h
@@ -0,0 +1,39 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_SETTINGS_BROWSEROS_METRICS_HANDLER_H_
+#define CHROME_BROWSER_UI_WEBUI_SETTINGS_BROWSEROS_METRICS_HANDLER_H_
+
+#include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h"
+
+namespace base {
+class Value;
+} // namespace base
+
+namespace settings {
+
+// Handler for BrowserOS metrics messages from the settings page.
+class BrowserOSMetricsHandler : public SettingsPageUIHandler {
+ public:
+ BrowserOSMetricsHandler();
+ ~BrowserOSMetricsHandler() override;
+
+ BrowserOSMetricsHandler(const BrowserOSMetricsHandler&) = delete;
+ BrowserOSMetricsHandler& operator=(const BrowserOSMetricsHandler&) = delete;
+
+ // WebUIMessageHandler:
+ void RegisterMessages() override;
+
+ private:
+ // Handler for logBrowserOSMetric message from JavaScript
+ void HandleLogBrowserOSMetric(const base::Value::List& args);
+
+ // SettingsPageUIHandler:
+ void OnJavascriptAllowed() override;
+ void OnJavascriptDisallowed() override;
+};
+
+} // namespace settings
+
+#endif // CHROME_BROWSER_UI_WEBUI_SETTINGS_BROWSEROS_METRICS_HANDLER_H_
\ No newline at end of file
diff --git a/chrome/browser/ui/webui/settings/settings_ui.cc b/chrome/browser/ui/webui/settings/settings_ui.cc
index 83e3f47da279e..67c338a86ccc8 100644
--- a/chrome/browser/ui/webui/settings/settings_ui.cc
+++ b/chrome/browser/ui/webui/settings/settings_ui.cc
@@ -59,6 +59,7 @@
#include "chrome/browser/ui/webui/settings/accessibility_main_handler.h"
#include "chrome/browser/ui/webui/settings/appearance_handler.h"
#include "chrome/browser/ui/webui/settings/browser_lifetime_handler.h"
+#include "chrome/browser/ui/webui/settings/browseros_metrics_handler.h"
#include "chrome/browser/ui/webui/settings/downloads_handler.h"
#include "chrome/browser/ui/webui/settings/font_handler.h"
#include "chrome/browser/ui/webui/settings/hats_handler.h"
@@ -292,6 +293,7 @@ SettingsUI::SettingsUI(content::WebUI* web_ui)
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
AddSettingsPageUIHandler(std::make_unique<PasskeysHandler>());
#endif
+ AddSettingsPageUIHandler(std::make_unique<BrowserOSMetricsHandler>());
#if BUILDFLAG(IS_CHROMEOS)
InitBrowserSettingsWebUIHandlers();
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index 12f83b0cc1ab5..fb0a6d63e909a 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -4273,6 +4273,10 @@ inline constexpr char kServiceWorkerToControlSrcdocIframeEnabled[] =
// is set as a SharedWorker script URL.
inline constexpr char kSharedWorkerBlobURLFixEnabled[] =
"worker.shared_worker_blob_url_fix_enabled";
+
+// String containing the stable client ID for BrowserOS metrics
+inline constexpr char kBrowserOSMetricsClientId[] =
+ "browseros.metrics_client_id";
} // namespace prefs
#endif // CHROME_COMMON_PREF_NAMES_H_
diff --git a/components/metrics/browseros_metrics/BUILD.gn b/components/metrics/browseros_metrics/BUILD.gn
new file mode 100644
index 0000000000000..c57c43bb575ea
--- /dev/null
+++ b/components/metrics/browseros_metrics/BUILD.gn
@@ -0,0 +1,39 @@
+# Copyright 2025 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/features.gni")
+
+static_library("browseros_metrics") {
+ sources = [
+ "browseros_metrics.cc",
+ "browseros_metrics.h",
+ "browseros_metrics_prefs.cc",
+ "browseros_metrics_prefs.h",
+ "browseros_metrics_service.cc",
+ "browseros_metrics_service.h",
+ "browseros_metrics_service_factory.cc",
+ "browseros_metrics_service_factory.h",
+ ]
+
+ deps = [
+ "//base",
+ "//chrome/browser/profiles:profile",
+ "//chrome/common:constants",
+ "//components/keyed_service/content",
+ "//components/keyed_service/core",
+ "//components/pref_registry",
+ "//components/prefs",
+ "//components/version_info",
+ "//content/public/browser",
+ "//net",
+ "//services/network/public/cpp",
+ "//services/network/public/mojom",
+ "//url",
+ ]
+
+ public_deps = [
+ "//base",
+ "//components/keyed_service/core",
+ ]
+}
\ No newline at end of file
diff --git a/components/metrics/browseros_metrics/DEPS b/components/metrics/browseros_metrics/DEPS
new file mode 100644
index 0000000000000..365047c83b7f2
--- /dev/null
+++ b/components/metrics/browseros_metrics/DEPS
@@ -0,0 +1,14 @@
+include_rules = [
+ "+base",
+ "+chrome/browser/profiles/profile.h",
+ "+chrome/common/pref_names.h",
+ "+components/keyed_service/content",
+ "+components/keyed_service/core",
+ "+components/pref_registry",
+ "+components/prefs",
+ "+components/version_info",
+ "+content/public/browser",
+ "+net",
+ "+services/network/public",
+ "+url",
+]
\ No newline at end of file
diff --git a/components/metrics/browseros_metrics/browseros_metrics.cc b/components/metrics/browseros_metrics/browseros_metrics.cc
new file mode 100644
index 0000000000000..02a1dc121bb7a
--- /dev/null
+++ b/components/metrics/browseros_metrics/browseros_metrics.cc
@@ -0,0 +1,100 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/metrics/browseros_metrics/browseros_metrics.h"
+
+#include "base/logging.h"
+#include "base/rand_util.h"
+#include "base/task/thread_pool.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "components/metrics/browseros_metrics/browseros_metrics_service_factory.h"
+#include "components/metrics/browseros_metrics/browseros_metrics_service.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/browser_thread.h"
+
+namespace browseros_metrics {
+
+namespace {
+
+// Helper to get the metrics service
+BrowserOSMetricsService* GetMetricsService() {
+ // Must be called on UI thread
+ if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) {
+ return nullptr;
+ }
+
+ // Get the profile manager
+ ProfileManager* profile_manager = g_browser_process->profile_manager();
+ if (!profile_manager) {
+ return nullptr;
+ }
+
+ // Get the last used profile (or the default one)
+ Profile* profile = profile_manager->GetLastUsedProfile();
+ if (!profile || profile->IsOffTheRecord()) {
+ return nullptr;
+ }
+
+ // Get the metrics service
+ return BrowserOSMetricsServiceFactory::GetForBrowserContext(profile);
+}
+
+void LogOnUIThread(const std::string& event_name, base::Value::Dict properties) {
+ auto* service = GetMetricsService();
+ if (service) {
+ service->CaptureEvent(event_name, std::move(properties));
+ } else {
+ VLOG(1) << "browseros: Metrics service not available for event: " << event_name;
+ }
+}
+
+} // namespace
+
+// static
+void BrowserOSMetrics::Log(const std::string& event_name, double sample_rate) {
+ Log(event_name, base::Value::Dict(), sample_rate);
+}
+
+// static
+void BrowserOSMetrics::Log(const std::string& event_name,
+ std::initializer_list<std::pair<std::string, base::Value>> properties,
+ double sample_rate) {
+ base::Value::Dict dict;
+ for (const auto& [key, value] : properties) {
+ dict.Set(key, value.Clone());
+ }
+ Log(event_name, std::move(dict), sample_rate);
+}
+
+// static
+void BrowserOSMetrics::Log(const std::string& event_name, base::Value::Dict properties,
+ double sample_rate) {
+ if (sample_rate <= 0.0 || sample_rate > 1.0) {
+ return;
+ }
+
+ if (sample_rate < 1.0) {
+ double random_value = base::RandDouble();
+ if (random_value > sample_rate) {
+ return;
+ }
+ }
+
+ if (sample_rate < 1.0) {
+ properties.Set("sample_rate", sample_rate);
+ }
+
+ // If we're already on the UI thread, log directly
+ if (content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) {
+ LogOnUIThread(event_name, std::move(properties));
+ } else {
+ // Post to UI thread
+ content::GetUIThreadTaskRunner({})->PostTask(
+ FROM_HERE,
+ base::BindOnce(&LogOnUIThread, event_name, std::move(properties)));
+ }
+}
+
+} // namespace browseros_metrics
diff --git a/components/metrics/browseros_metrics/browseros_metrics.h b/components/metrics/browseros_metrics/browseros_metrics.h
new file mode 100644
index 0000000000000..73e98afdaa28a
--- /dev/null
+++ b/components/metrics/browseros_metrics/browseros_metrics.h
@@ -0,0 +1,40 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_METRICS_BROWSEROS_METRICS_BROWSEROS_METRICS_H_
+#define COMPONENTS_METRICS_BROWSEROS_METRICS_BROWSEROS_METRICS_H_
+
+#include <string>
+#include <utility>
+
+#include "base/values.h"
+
+namespace browseros_metrics {
+
+// Simple static API for logging BrowserOS metrics.
+// Usage: BrowserOSMetrics::Log("event.name");
+class BrowserOSMetrics {
+ public:
+ // Log an event with no properties
+ // sample_rate: 0.0 to 1.0, defaults to 1.0 (always log)
+ // For example, sample_rate=0.1 means log only 10% of the time
+ static void Log(const std::string& event_name, double sample_rate = 1.0);
+
+ // Log an event with properties using initializer list
+ // Example: Log("event", {{"key1", "value1"}, {"key2", 123}})
+ static void Log(const std::string& event_name,
+ std::initializer_list<std::pair<std::string, base::Value>> properties,
+ double sample_rate = 1.0);
+
+ // Log an event with pre-built properties dict
+ static void Log(const std::string& event_name, base::Value::Dict properties,
+ double sample_rate = 1.0);
+
+ private:
+ BrowserOSMetrics() = delete;
+};
+
+} // namespace browseros_metrics
+
+#endif // COMPONENTS_METRICS_BROWSEROS_METRICS_BROWSEROS_METRICS_H_
\ No newline at end of file
diff --git a/components/metrics/browseros_metrics/browseros_metrics_prefs.cc b/components/metrics/browseros_metrics/browseros_metrics_prefs.cc
new file mode 100644
index 0000000000000..87f898f345e74
--- /dev/null
+++ b/components/metrics/browseros_metrics/browseros_metrics_prefs.cc
@@ -0,0 +1,25 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/metrics/browseros_metrics/browseros_metrics_prefs.h"
+
+#include "chrome/common/pref_names.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/pref_registry/pref_registry_syncable.h"
+
+namespace browseros_metrics {
+
+void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
+ // Register the stable client ID pref - this should not sync across devices
+ // as each browser instance needs its own unique ID
+ registry->RegisterStringPref(
+ prefs::kBrowserOSMetricsClientId,
+ std::string());
+}
+
+void RegisterLocalStatePrefs(PrefRegistrySimple* registry) {
+ // Currently no local state prefs, but keeping this for future expansion
+}
+
+} // namespace browseros_metrics
\ No newline at end of file
diff --git a/components/metrics/browseros_metrics/browseros_metrics_prefs.h b/components/metrics/browseros_metrics/browseros_metrics_prefs.h
new file mode 100644
index 0000000000000..a417e8d8af351
--- /dev/null
+++ b/components/metrics/browseros_metrics/browseros_metrics_prefs.h
@@ -0,0 +1,24 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_METRICS_BROWSEROS_METRICS_BROWSEROS_METRICS_PREFS_H_
+#define COMPONENTS_METRICS_BROWSEROS_METRICS_BROWSEROS_METRICS_PREFS_H_
+
+class PrefRegistrySimple;
+
+namespace user_prefs {
+class PrefRegistrySyncable;
+} // namespace user_prefs
+
+namespace browseros_metrics {
+
+// Registers BrowserOS metrics preferences for the profile.
+void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
+
+// Registers BrowserOS metrics preferences for local state.
+void RegisterLocalStatePrefs(PrefRegistrySimple* registry);
+
+} // namespace browseros_metrics
+
+#endif // COMPONENTS_METRICS_BROWSEROS_METRICS_BROWSEROS_METRICS_PREFS_H_
\ No newline at end of file
diff --git a/components/metrics/browseros_metrics/browseros_metrics_service.cc b/components/metrics/browseros_metrics/browseros_metrics_service.cc
new file mode 100644
index 0000000000000..707ac50393820
--- /dev/null
+++ b/components/metrics/browseros_metrics/browseros_metrics_service.cc
@@ -0,0 +1,201 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/metrics/browseros_metrics/browseros_metrics_service.h"
+
+#include <memory>
+#include <string>
+
+#include "base/uuid.h"
+#include "base/json/json_writer.h"
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/system/sys_info.h"
+#include "base/time/time.h"
+#include "chrome/common/pref_names.h"
+#include "components/prefs/pref_service.h"
+#include "components/version_info/version_info.h"
+#include "net/base/load_flags.h"
+#include "net/http/http_status_code.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
+#include "services/network/public/cpp/resource_request.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "services/network/public/cpp/simple_url_loader.h"
+#include "services/network/public/mojom/url_response_head.mojom.h"
+
+namespace browseros_metrics {
+
+namespace {
+
+// Event naming convention:
+// All events from C++ code are prefixed with "browseros.native." to distinguish
+// them from extension events which would use "browseros.extension." prefix.
+// This helps with analytics filtering and understanding event sources.
+
+// PostHog API configuration
+constexpr char kPostHogApiKey[] = "phc_PRrpVnBMVJgUumvaXzUnwKZ1dDs3L8MSICLhTdnc8jC";
+constexpr char kPostHogEndpoint[] = "https://us.i.posthog.com/i/v0/e/";
+constexpr size_t kMaxUploadSize = 256 * 1024; // 256KB max upload size
+
+constexpr net::NetworkTrafficAnnotationTag kBrowserOSMetricsTrafficAnnotation =
+ net::DefineNetworkTrafficAnnotation("browseros_metrics", R"(
+ semantics {
+ sender: "BrowserOS Metrics"
+ description:
+ "Sends anonymous usage metrics to PostHog for BrowserOS features. "
+ "This helps improve the browser by understanding how features are "
+ "used. No personally identifiable information is collected."
+ trigger:
+ "Triggered when BrowserOS features are used, such as extension "
+ "actions or settings changes."
+ data:
+ "Event name, timestamp, anonymous client ID, browser version, "
+ "OS information, and feature-specific properties without PII."
+ destination: OTHER
+ destination_other:
+ "PostHog analytics service at us.i.posthog.com"
+ }
+ policy {
+ cookies_allowed: NO
+ setting:
+ "This feature cannot be disabled through settings. Events are "
+ "sent anonymously without user identification."
+ policy_exception_justification:
+ "Not implemented. Analytics are anonymous and help improve "
+ "the browser experience."
+ })");
+
+} // namespace
+
+BrowserOSMetricsService::BrowserOSMetricsService(
+ PrefService* pref_service,
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
+ : pref_service_(pref_service),
+ url_loader_factory_(std::move(url_loader_factory)) {
+ CHECK(pref_service_);
+ CHECK(url_loader_factory_);
+ InitializeClientId();
+}
+
+BrowserOSMetricsService::~BrowserOSMetricsService() = default;
+
+void BrowserOSMetricsService::CaptureEvent(const std::string& event_name,
+ base::Value::Dict properties) {
+ if (event_name.empty()) {
+ LOG(WARNING) << "browseros: Attempted to capture event with empty name";
+ return;
+ }
+
+ VLOG(1) << "browseros: Capturing event: " << event_name;
+
+ // Add default properties
+ AddDefaultProperties(properties);
+
+ // Send to PostHog
+ SendEventToPostHog(event_name, std::move(properties));
+}
+
+std::string BrowserOSMetricsService::GetClientId() const {
+ return client_id_;
+}
+
+void BrowserOSMetricsService::Shutdown() {
+ // Cancel any pending network requests
+ weak_factory_.InvalidateWeakPtrs();
+}
+
+void BrowserOSMetricsService::InitializeClientId() {
+ CHECK(pref_service_);
+
+ // Check if we have an existing client ID
+ const std::string& stored_id =
+ pref_service_->GetString(prefs::kBrowserOSMetricsClientId);
+
+ if (!stored_id.empty() && base::Uuid::ParseCaseInsensitive(stored_id).is_valid()) {
+ client_id_ = stored_id;
+ VLOG(1) << "browseros: Using existing metrics client ID";
+ } else {
+ // Generate a new UUID
+ client_id_ = base::Uuid::GenerateRandomV4().AsLowercaseString();
+ pref_service_->SetString(prefs::kBrowserOSMetricsClientId, client_id_);
+ LOG(INFO) << "browseros: Generated new metrics client ID";
+ }
+ VLOG(1) << "browseros: Metrics client ID: " << client_id_;
+}
+
+void BrowserOSMetricsService::SendEventToPostHog(
+ const std::string& event_name,
+ base::Value::Dict properties) {
+ // Build the request payload
+ base::Value::Dict payload;
+ payload.Set("api_key", kPostHogApiKey);
+ payload.Set("event", "browseros.native." + event_name);
+ payload.Set("distinct_id", client_id_);
+ payload.Set("properties", std::move(properties));
+
+ // Convert to JSON
+ std::string json_payload;
+ if (!base::JSONWriter::Write(payload, &json_payload)) {
+ LOG(ERROR) << "browseros: Failed to serialize metrics payload";
+ return;
+ }
+
+ // Create the request
+ auto resource_request = std::make_unique<network::ResourceRequest>();
+ resource_request->url = GURL(kPostHogEndpoint);
+ resource_request->method = "POST";
+ resource_request->load_flags = net::LOAD_DISABLE_CACHE;
+ resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit;
+
+ // Create the URL loader
+ auto url_loader = network::SimpleURLLoader::Create(
+ std::move(resource_request), kBrowserOSMetricsTrafficAnnotation);
+ url_loader->SetAllowHttpErrorResults(true);
+ url_loader->AttachStringForUpload(json_payload, "application/json");
+
+ // Send the request
+ network::SimpleURLLoader* loader_ptr = url_loader.get();
+ loader_ptr->DownloadToString(
+ url_loader_factory_.get(),
+ base::BindOnce(&BrowserOSMetricsService::OnPostHogResponse,
+ weak_factory_.GetWeakPtr(), std::move(url_loader)),
+ kMaxUploadSize);
+}
+
+void BrowserOSMetricsService::OnPostHogResponse(
+ std::unique_ptr<network::SimpleURLLoader> loader,
+ std::unique_ptr<std::string> response_body) {
+ int response_code = 0;
+ if (loader->ResponseInfo() && loader->ResponseInfo()->headers) {
+ response_code = loader->ResponseInfo()->headers->response_code();
+ }
+
+ if (response_code == net::HTTP_OK) {
+ VLOG(2) << "browseros: Metrics event sent successfully";
+ } else {
+ LOG(WARNING) << "browseros: Failed to send metrics event. Response code: "
+ << response_code;
+ if (response_body && !response_body->empty()) {
+ LOG(WARNING) << "browseros: Error response: " << *response_body;
+ }
+ }
+}
+
+void BrowserOSMetricsService::AddDefaultProperties(
+ base::Value::Dict& properties) {
+ // Add browser version
+ properties.Set("$browser_version", version_info::GetVersionNumber());
+
+ // Add OS information
+ properties.Set("$os", base::SysInfo::OperatingSystemName());
+ properties.Set("$os_version", base::SysInfo::OperatingSystemVersion());
+
+ // Ensure anonymous tracking
+ properties.Set("$process_person_profile", false);
+
+ // Add platform architecture
+ properties.Set("$arch", base::SysInfo::OperatingSystemArchitecture());
+}
+
+} // namespace browseros_metrics
diff --git a/components/metrics/browseros_metrics/browseros_metrics_service.h b/components/metrics/browseros_metrics/browseros_metrics_service.h
new file mode 100644
index 0000000000000..db124fd11382a
--- /dev/null
+++ b/components/metrics/browseros_metrics/browseros_metrics_service.h
@@ -0,0 +1,81 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_METRICS_BROWSEROS_METRICS_BROWSEROS_METRICS_SERVICE_H_
+#define COMPONENTS_METRICS_BROWSEROS_METRICS_BROWSEROS_METRICS_SERVICE_H_
+
+#include <memory>
+#include <string>
+
+#include "base/functional/callback.h"
+#include "base/memory/weak_ptr.h"
+#include "base/values.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "services/network/public/cpp/simple_url_loader.h"
+#include "url/gurl.h"
+
+class PrefService;
+
+namespace network {
+class SharedURLLoaderFactory;
+} // namespace network
+
+namespace browseros_metrics {
+
+// Service for capturing and sending analytics events to PostHog.
+// This service manages a stable client ID and sends events to the PostHog API.
+class BrowserOSMetricsService : public KeyedService {
+ public:
+ explicit BrowserOSMetricsService(
+ PrefService* pref_service,
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory);
+
+ BrowserOSMetricsService(const BrowserOSMetricsService&) = delete;
+ BrowserOSMetricsService& operator=(const BrowserOSMetricsService&) = delete;
+
+ ~BrowserOSMetricsService() override;
+
+ // Captures a single event with the given name and properties.
+ // Properties should not contain PII. Common properties like client_id,
+ // browser version, and OS are added automatically.
+ void CaptureEvent(const std::string& event_name,
+ base::Value::Dict properties);
+
+ // Returns the stable client ID for this browser instance.
+ std::string GetClientId() const;
+
+ // KeyedService:
+ void Shutdown() override;
+
+ private:
+ // Initializes or retrieves the stable client ID from preferences.
+ void InitializeClientId();
+
+ // Sends the event to PostHog API.
+ void SendEventToPostHog(const std::string& event_name,
+ base::Value::Dict properties);
+
+ // Handles the response from PostHog API.
+ void OnPostHogResponse(std::unique_ptr<network::SimpleURLLoader> loader,
+ std::unique_ptr<std::string> response_body);
+
+ // Adds default properties to the event.
+ void AddDefaultProperties(base::Value::Dict& properties);
+
+ // PrefService for storing the stable client ID.
+ raw_ptr<PrefService> pref_service_;
+
+ // Factory for creating URL loaders.
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
+
+ // Stable client ID for this browser instance.
+ std::string client_id_;
+
+ // Weak pointer factory for callbacks.
+ base::WeakPtrFactory<BrowserOSMetricsService> weak_factory_{this};
+};
+
+} // namespace browseros_metrics
+
+#endif // COMPONENTS_METRICS_BROWSEROS_METRICS_BROWSEROS_METRICS_SERVICE_H_
\ No newline at end of file
diff --git a/components/metrics/browseros_metrics/browseros_metrics_service_factory.cc b/components/metrics/browseros_metrics/browseros_metrics_service_factory.cc
new file mode 100644
index 0000000000000..bddc97f6d9a05
--- /dev/null
+++ b/components/metrics/browseros_metrics/browseros_metrics_service_factory.cc
@@ -0,0 +1,56 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/metrics/browseros_metrics/browseros_metrics_service_factory.h"
+
+#include <memory>
+
+#include "base/no_destructor.h"
+#include "chrome/browser/profiles/profile.h"
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "components/metrics/browseros_metrics/browseros_metrics_service.h"
+#include "components/prefs/pref_service.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/storage_partition.h"
+
+namespace browseros_metrics {
+
+// static
+BrowserOSMetricsService* BrowserOSMetricsServiceFactory::GetForBrowserContext(
+ content::BrowserContext* context) {
+ return static_cast<BrowserOSMetricsService*>(
+ GetInstance()->GetServiceForBrowserContext(context, true));
+}
+
+// static
+BrowserOSMetricsServiceFactory*
+BrowserOSMetricsServiceFactory::GetInstance() {
+ static base::NoDestructor<BrowserOSMetricsServiceFactory> instance;
+ return instance.get();
+}
+
+BrowserOSMetricsServiceFactory::BrowserOSMetricsServiceFactory()
+ : BrowserContextKeyedServiceFactory(
+ "BrowserOSMetricsService",
+ BrowserContextDependencyManager::GetInstance()) {}
+
+BrowserOSMetricsServiceFactory::~BrowserOSMetricsServiceFactory() = default;
+
+std::unique_ptr<KeyedService>
+BrowserOSMetricsServiceFactory::BuildServiceInstanceForBrowserContext(
+ content::BrowserContext* context) const {
+ Profile* profile = Profile::FromBrowserContext(context);
+
+ // Don't create service for incognito profiles
+ if (profile->IsOffTheRecord()) {
+ return nullptr;
+ }
+
+ return std::make_unique<BrowserOSMetricsService>(
+ profile->GetPrefs(),
+ profile->GetDefaultStoragePartition()
+ ->GetURLLoaderFactoryForBrowserProcess());
+}
+
+} // namespace browseros_metrics
\ No newline at end of file
diff --git a/components/metrics/browseros_metrics/browseros_metrics_service_factory.h b/components/metrics/browseros_metrics/browseros_metrics_service_factory.h
new file mode 100644
index 0000000000000..014eb17aba442
--- /dev/null
+++ b/components/metrics/browseros_metrics/browseros_metrics_service_factory.h
@@ -0,0 +1,48 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_METRICS_BROWSEROS_METRICS_BROWSEROS_METRICS_SERVICE_FACTORY_H_
+#define COMPONENTS_METRICS_BROWSEROS_METRICS_BROWSEROS_METRICS_SERVICE_FACTORY_H_
+
+#include "base/no_destructor.h"
+#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+
+namespace content {
+class BrowserContext;
+} // namespace content
+
+namespace browseros_metrics {
+
+class BrowserOSMetricsService;
+
+// Factory for creating BrowserOSMetricsService instances per profile.
+class BrowserOSMetricsServiceFactory
+ : public BrowserContextKeyedServiceFactory {
+ public:
+ BrowserOSMetricsServiceFactory(const BrowserOSMetricsServiceFactory&) =
+ delete;
+ BrowserOSMetricsServiceFactory& operator=(
+ const BrowserOSMetricsServiceFactory&) = delete;
+
+ // Returns the BrowserOSMetricsService for |context|, creating one if needed.
+ static BrowserOSMetricsService* GetForBrowserContext(
+ content::BrowserContext* context);
+
+ // Returns the singleton factory instance.
+ static BrowserOSMetricsServiceFactory* GetInstance();
+
+ private:
+ friend base::NoDestructor<BrowserOSMetricsServiceFactory>;
+
+ BrowserOSMetricsServiceFactory();
+ ~BrowserOSMetricsServiceFactory() override;
+
+ // BrowserContextKeyedServiceFactory:
+ std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
+ content::BrowserContext* context) const override;
+};
+
+} // namespace browseros_metrics
+
+#endif // COMPONENTS_METRICS_BROWSEROS_METRICS_BROWSEROS_METRICS_SERVICE_FACTORY_H_
\ No newline at end of file
--
2.49.0

View File

@@ -1,4 +1,4 @@
From 105d7bed3a2f334860a5bcb2caebf3f381e18207 Mon Sep 17 00:00:00 2001
From 76248fc35ecce3c9c53c0b60713e524d8105f395 Mon Sep 17 00:00:00 2001
From: Nikhil Sonti <nikhilsv92@gmail.com>
Date: Tue, 29 Jul 2025 16:48:31 -0700
Subject: [PATCH] BrowserOS extensions OTA updater

View File

@@ -1,7 +1,7 @@
From 27b2e9d7dde108ffb3a77ee8ea75e3541b9fdf4a Mon Sep 17 00:00:00 2001
From 902c643edfb75d406434eb165ca31ade2a24f9a6 Mon Sep 17 00:00:00 2001
From: Nikhil Sonti <nikhilsv92@gmail.com>
Date: Fri, 4 Jul 2025 16:50:10 -0700
Subject: [PATCH] importer patch
Date: Tue, 22 Jul 2025 21:33:24 -0700
Subject: [PATCH] patch(M): chrome importer
---
chrome/app/generated_resources.grd | 3 +
@@ -9,11 +9,11 @@ Subject: [PATCH] importer patch
.../api/settings_private/prefs_util.cc | 2 +
.../external_process_importer_client.cc | 8 +
.../external_process_importer_client.h | 2 +
chrome/browser/importer/importer_list.cc | 214 +++++
chrome/browser/importer/importer_list.cc | 214 +++++++
chrome/browser/importer/importer_uma.cc | 4 +
.../importer/in_process_importer_bridge.cc | 16 +
.../importer/in_process_importer_bridge.h | 2 +
chrome/browser/importer/profile_writer.cc | 144 ++++
chrome/browser/importer/profile_writer.cc | 144 +++++
chrome/browser/importer/profile_writer.h | 4 +
.../people_page/import_data_browser_proxy.ts | 1 +
.../people_page/import_data_dialog.html | 5 +
@@ -27,21 +27,21 @@ Subject: [PATCH] importer patch
...ofile_import_process_param_traits_macros.h | 4 +-
chrome/common/pref_names.h | 2 +
chrome/utility/BUILD.gn | 2 +
chrome/utility/importer/chrome_importer.cc | 736 ++++++++++++++++++
chrome/utility/importer/chrome_importer.h | 91 +++
chrome/utility/importer/chrome_importer.cc | 591 ++++++++++++++++++
chrome/utility/importer/chrome_importer.h | 80 +++
.../external_process_importer_bridge.cc | 7 +
.../external_process_importer_bridge.h | 2 +
chrome/utility/importer/importer_creator.cc | 3 +
.../histograms/metadata/sql/histograms.xml | 1 +
29 files changed, 1268 insertions(+), 3 deletions(-)
29 files changed, 1112 insertions(+), 3 deletions(-)
create mode 100644 chrome/utility/importer/chrome_importer.cc
create mode 100644 chrome/utility/importer/chrome_importer.h
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 444323aed7636..d8243b834206d 100644
index 186d94b83cb9c..a7e94095c4dc5 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -10885,6 +10885,9 @@ Check your passwords anytime in <ph name="GOOGLE_PASSWORD_MANAGER">$1<ex>Google
@@ -10882,6 +10882,9 @@ Check your passwords anytime in <ph name="GOOGLE_PASSWORD_MANAGER">$1<ex>Google
<message name="IDS_IMPORT_FROM_FIREFOX" desc="browser combo box: Mozilla Firefox">
Mozilla Firefox
</message>
@@ -66,10 +66,10 @@ index 8d41891d1717b..8064a065bbb54 100644
<message name="IDS_SETTINGS_IMPORT_CHOOSE_FILE" desc="Text for the Choose File on dialog">
Choose File
diff --git a/chrome/browser/extensions/api/settings_private/prefs_util.cc b/chrome/browser/extensions/api/settings_private/prefs_util.cc
index 1803d96b758e1..1869a54c5b4e4 100644
index 97bb4be60af93..c27e0e96e4bce 100644
--- a/chrome/browser/extensions/api/settings_private/prefs_util.cc
+++ b/chrome/browser/extensions/api/settings_private/prefs_util.cc
@@ -1190,6 +1190,8 @@ const PrefsUtil::TypedPrefMap& PrefsUtil::GetAllowlistedKeys() {
@@ -1164,6 +1164,8 @@ const PrefsUtil::TypedPrefMap& PrefsUtil::GetAllowlistedKeys() {
settings_api::PrefType::kBoolean;
(*s_allowlist)[::prefs::kImportDialogSearchEngine] =
settings_api::PrefType::kBoolean;
@@ -798,10 +798,10 @@ index aad8bc1ac7d4f..bd24de192a0ee 100644
if (is_mac) {
diff --git a/chrome/utility/importer/chrome_importer.cc b/chrome/utility/importer/chrome_importer.cc
new file mode 100644
index 0000000000000..9026dcc1ec6b1
index 0000000000000..5a7c392fd775a
--- /dev/null
+++ b/chrome/utility/importer/chrome_importer.cc
@@ -0,0 +1,736 @@
@@ -0,0 +1,591 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
@@ -824,9 +824,6 @@ index 0000000000000..9026dcc1ec6b1
+#include "chrome/common/importer/importer_url_row.h"
+#include "chrome/grit/generated_resources.h"
+#include "chrome/utility/importer/favicon_reencode.h"
+#include "components/os_crypt/sync/os_crypt.h"
+#include "components/password_manager/core/browser/password_form.h"
+#include "components/password_manager/core/browser/password_store/login_database.h"
+#include "sql/database.h"
+#include "sql/statement.h"
+#include "ui/base/l10n/l10n_util.h"
@@ -1210,123 +1207,15 @@ index 0000000000000..9026dcc1ec6b1
+}
+
+void ChromeImporter::ImportPasswords() {
+ LOG(INFO) << "ChromeImporter: Starting passwords import";
+
+ // Set up encryption keys for decrypting passwords
+ base::FilePath source_path = source_path_;
+#if BUILDFLAG(IS_WIN)
+ // On Windows, the path is different
+ source_path = source_path_.DirName();
+#endif
+
+ // Initialize encryption using the appropriate source path
+ if (!SetEncryptionKey(source_path)) {
+ LOG(ERROR) << "ChromeImporter: Failed to set encryption key for passwords";
+ return;
+ }
+
+ // First try the main Login Data file
+ ImportPasswordsFromFile(base::FilePath(FILE_PATH_LITERAL("Login Data")));
+
+ // Then try the account-specific Login Data file if it exists
+ ImportPasswordsFromFile(base::FilePath(FILE_PATH_LITERAL("Login Data For Account")));
+
+ LOG(INFO) << "ChromeImporter: Passwords import complete";
+ // Password import is disabled - users should use CSV import from chrome://password-manager/passwords
+ LOG(INFO) << "ChromeImporter: Password import is disabled. "
+ << "Please use CSV import from chrome://password-manager/passwords";
+ return;
+}
+
+void ChromeImporter::ImportPasswordsFromFile(const base::FilePath& password_filename) {
+ base::FilePath passwords_path = source_path_.Append(password_filename);
+ if (!base::PathExists(passwords_path)) {
+ LOG(INFO) << "ChromeImporter: " << password_filename.value() << " file not found";
+ return;
+ }
+
+ // Create temporary directory for copying the database
+ base::FilePath temp_directory;
+ if (!base::CreateNewTempDirectory(base::FilePath::StringType(), &temp_directory)) {
+ LOG(ERROR) << "ChromeImporter: Failed to create temp directory for passwords";
+ return;
+ }
+
+ // Copy the database file to avoid lock issues
+ base::FilePath temp_passwords_path = temp_directory.Append(password_filename.BaseName());
+ if (!base::CopyFile(passwords_path, temp_passwords_path)) {
+ LOG(ERROR) << "ChromeImporter: Failed to copy " << password_filename.value() << " file";
+ base::DeletePathRecursively(temp_directory);
+ return;
+ }
+
+ // Open the database using password manager's login database
+ password_manager::LoginDatabase database(
+ temp_passwords_path, password_manager::IsAccountStore(false));
+
+ if (!database.Init(base::NullCallback(), nullptr)) {
+ LOG(ERROR) << "ChromeImporter: Failed to initialize login database";
+ base::DeletePathRecursively(temp_directory);
+ return;
+ }
+
+ // Process regular logins
+ std::vector<password_manager::PasswordForm> forms;
+ bool success = database.GetAutofillableLogins(&forms);
+ if (success) {
+ LOG(INFO) << "ChromeImporter: Found " << forms.size() << " passwords";
+ for (const auto& form : forms) {
+ importer::ImportedPasswordForm imported_form;
+ if (PasswordFormToImportedPasswordForm(form, imported_form)) {
+ bridge_->SetPasswordForm(imported_form);
+ }
+ }
+ }
+
+ // Process blocklisted logins
+ std::vector<password_manager::PasswordForm> blocklist;
+ success = database.GetBlocklistLogins(&blocklist);
+ if (success && !blocklist.empty()) {
+ LOG(INFO) << "ChromeImporter: Found " << blocklist.size() << " blocklisted passwords";
+ for (const auto& form : blocklist) {
+ importer::ImportedPasswordForm imported_form;
+ if (PasswordFormToImportedPasswordForm(form, imported_form)) {
+ bridge_->SetPasswordForm(imported_form);
+ }
+ }
+ }
+
+ // Clean up temporary files
+ base::DeletePathRecursively(temp_directory);
+}
+
+bool ChromeImporter::PasswordFormToImportedPasswordForm(
+ const password_manager::PasswordForm& form,
+ importer::ImportedPasswordForm& imported_form) {
+ // Skip forms with invalid schemes
+ if (form.scheme != password_manager::PasswordForm::Scheme::kHtml &&
+ form.scheme != password_manager::PasswordForm::Scheme::kBasic) {
+ return false;
+ }
+
+ // Set the scheme appropriately
+ imported_form.scheme = form.scheme == password_manager::PasswordForm::Scheme::kHtml
+ ? importer::ImportedPasswordForm::Scheme::kHtml
+ : importer::ImportedPasswordForm::Scheme::kBasic;
+
+ // Skip inconsistent blocked forms that have credentials
+ if (form.blocked_by_user &&
+ (!form.username_value.empty() || !form.password_value.empty())) {
+ return false;
+ }
+
+ // Copy over all the relevant form fields
+ imported_form.signon_realm = form.signon_realm;
+ imported_form.url = form.url;
+ imported_form.action = form.action;
+ imported_form.username_element = form.username_element;
+ imported_form.username_value = form.username_value;
+ imported_form.password_element = form.password_element;
+ imported_form.password_value = form.password_value;
+ imported_form.blocked_by_user = form.blocked_by_user;
+
+ return true;
+ // Password import is disabled - this function is kept as a no-op for compatibility
+ return;
+}
+
+void ChromeImporter::ImportAutofillFormData() {
@@ -1396,44 +1285,10 @@ index 0000000000000..9026dcc1ec6b1
+ LOG(INFO) << "ChromeImporter: Autofill form data import complete";
+}
+
+bool ChromeImporter::SetEncryptionKey(const base::FilePath& source_path) {
+#if BUILDFLAG(IS_LINUX)
+ // Set up crypt config for Linux
+ std::unique_ptr<os_crypt::Config> config(new os_crypt::Config());
+ config->product_name = l10n_util::GetStringUTF8(IDS_PRODUCT_NAME);
+ config->should_use_preference = false;
+ config->user_data_path = source_path;
+ OSCrypt::SetConfig(std::move(config));
+ return true;
+#elif BUILDFLAG(IS_WIN)
+ // On Windows, we need to obtain the encryption key from Local State
+ base::FilePath local_state_path = source_path.Append(FILE_PATH_LITERAL("Local State"));
+ if (!base::PathExists(local_state_path)) {
+ LOG(ERROR) << "ChromeImporter: Local State file not found";
+ return false;
+ }
+
+ std::string local_state_content;
+ if (!base::ReadFileToString(local_state_path, &local_state_content)) {
+ LOG(ERROR) << "ChromeImporter: Failed to read Local State file";
+ return false;
+ }
+
+ std::optional<base::Value::Dict> local_state =
+ base::JSONReader::ReadDict(local_state_content);
+ if (!local_state) {
+ LOG(ERROR) << "ChromeImporter: Failed to parse Local State JSON";
+ return false;
+ }
+
+ // For Mac and other platforms, we don't need to do anything special
+ // as keychain is used automatically
+ return true;
+#else
+ // For Mac, keychain is used automatically by OSCrypt
+ return true;
+#endif
+}
+// Encryption key setup is disabled since password import is disabled
+// bool ChromeImporter::SetEncryptionKey(const base::FilePath& source_path) {
+// return false;
+// }
+
+void ChromeImporter::ImportExtensions() {
+ LOG(INFO) << "ChromeImporter: Starting extensions import";
@@ -1538,13 +1393,12 @@ index 0000000000000..9026dcc1ec6b1
+
+ return extension_ids;
+}
\ No newline at end of file
diff --git a/chrome/utility/importer/chrome_importer.h b/chrome/utility/importer/chrome_importer.h
new file mode 100644
index 0000000000000..06317c522d5d0
index 0000000000000..25b49c7028e1c
--- /dev/null
+++ b/chrome/utility/importer/chrome_importer.h
@@ -0,0 +1,91 @@
@@ -0,0 +1,80 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
@@ -1572,13 +1426,6 @@ index 0000000000000..06317c522d5d0
+class Database;
+}
+
+namespace password_manager {
+struct PasswordForm;
+}
+
+namespace importer {
+struct ImportedPasswordForm;
+}
+
+class ChromeImporter : public Importer {
+ public:
@@ -1600,10 +1447,6 @@ index 0000000000000..06317c522d5d0
+ void ImportAutofillFormData();
+ void ImportExtensions();
+ void ImportPasswordsFromFile(const base::FilePath& password_filename);
+ bool PasswordFormToImportedPasswordForm(
+ const password_manager::PasswordForm& form,
+ importer::ImportedPasswordForm& imported_form);
+ bool SetEncryptionKey(const base::FilePath& source_path);
+
+ // Helper function to convert Chrome's time format to base::Time
+ base::Time ChromeTimeToBaseTime(int64_t time);
@@ -1636,7 +1479,6 @@ index 0000000000000..06317c522d5d0
+};
+
+#endif // CHROME_UTILITY_IMPORTER_CHROME_IMPORTER_H_
\ No newline at end of file
diff --git a/chrome/utility/importer/external_process_importer_bridge.cc b/chrome/utility/importer/external_process_importer_bridge.cc
index 0f98b3d1da6e7..9b169aab54fd9 100644
--- a/chrome/utility/importer/external_process_importer_bridge.cc

View File

@@ -0,0 +1,24 @@
From 6e1eb7912668735eea24920c83d12eba742dae35 Mon Sep 17 00:00:00 2001
From: Nikhil Sonti <nikhilsv92@gmail.com>
Date: Wed, 23 Jul 2025 09:26:47 -0700
Subject: [PATCH] patch: chrome version update
---
chrome/VERSION | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/chrome/VERSION b/chrome/VERSION
index cdbed925f47c1..37b80272989ff 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
MAJOR=137
MINOR=0
-BUILD=7151
-PATCH=69
+BUILD=7187
+PATCH=69
\ No newline at end of file
--
2.49.0

View File

@@ -1,7 +1,7 @@
From 80fc1ca1096e8cb2c0858d695d3a0c359d9681e5 Mon Sep 17 00:00:00 2001
From 8ff10fcbf445f98925ed17d8ba4339be50390b97 Mon Sep 17 00:00:00 2001
From: Nikhil Sonti <nikhilsv92@gmail.com>
Date: Fri, 11 Jul 2025 13:07:04 -0700
Subject: [PATCH] disable chromelabs pinned by default
Date: Tue, 22 Jul 2025 21:34:23 -0700
Subject: [PATCH] patch: disable-chrome-labs-pinning
---
.../pinned_toolbar/pinned_toolbar_actions_model.cc | 4 +++-
@@ -9,7 +9,7 @@ Subject: [PATCH] disable chromelabs pinned by default
2 files changed, 4 insertions(+), 9 deletions(-)
diff --git a/chrome/browser/ui/toolbar/pinned_toolbar/pinned_toolbar_actions_model.cc b/chrome/browser/ui/toolbar/pinned_toolbar/pinned_toolbar_actions_model.cc
index 3fd0ec6cd8da1..0b554e8cfe999 100644
index 613d124be1752..72c9f630c905c 100644
--- a/chrome/browser/ui/toolbar/pinned_toolbar/pinned_toolbar_actions_model.cc
+++ b/chrome/browser/ui/toolbar/pinned_toolbar/pinned_toolbar_actions_model.cc
@@ -236,8 +236,10 @@ void PinnedToolbarActionsModel::MaybeMigrateExistingPinnedStates() {
@@ -25,10 +25,10 @@ index 3fd0ec6cd8da1..0b554e8cfe999 100644
}
if (features::HasTabSearchToolbarButton() &&
diff --git a/chrome/browser/ui/toolbar/toolbar_pref_names.cc b/chrome/browser/ui/toolbar/toolbar_pref_names.cc
index 343376dd051fb..d2868cb83608f 100644
index 4dd749643041a..5d3da32f57f81 100644
--- a/chrome/browser/ui/toolbar/toolbar_pref_names.cc
+++ b/chrome/browser/ui/toolbar/toolbar_pref_names.cc
@@ -16,14 +16,7 @@ namespace toolbar {
@@ -14,14 +14,7 @@ namespace toolbar {
void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
base::Value::List default_pinned_actions;

View File

@@ -1,7 +1,7 @@
From 9bdb1b3292b46e2daf648661e848eacdb5d5f088 Mon Sep 17 00:00:00 2001
From 8ec0008662cd2597a5bf7d77efd1c49d3191f6a2 Mon Sep 17 00:00:00 2001
From: Nikhil Sonti <nikhilsv92@gmail.com>
Date: Tue, 24 Jun 2025 18:05:58 -0700
Subject: [PATCH] disable google key info bar
Date: Tue, 22 Jul 2025 21:34:11 -0700
Subject: [PATCH] patch: disable-google-key-info-bar
---
.../ui/startup/google_api_keys_infobar_delegate.cc | 9 ++++++---

View File

@@ -1,7 +1,7 @@
From 120a5231cb3df5dc698d4f0db3193050b9114638 Mon Sep 17 00:00:00 2001
From ffc2064316b9e38ad219bb5517de1855e8046540 Mon Sep 17 00:00:00 2001
From: Nikhil Sonti <nikhilsv92@gmail.com>
Date: Sun, 18 May 2025 11:12:33 +0100
Subject: [PATCH] Disable info bar in CDP
Date: Tue, 22 Jul 2025 21:33:59 -0700
Subject: [PATCH] patch: disable-info-bar-in-cdp
---
chrome/browser/extensions/api/debugger/debugger_api.cc | 2 +-

View File

@@ -1,7 +1,7 @@
From 30931e9d6a8aeb734ff25c0cf560bbd92e3da33f Mon Sep 17 00:00:00 2001
From 605dbbba266697c4fc290a0201681b9f5f8ef746 Mon Sep 17 00:00:00 2001
From: Nikhil Sonti <nikhilsv92@gmail.com>
Date: Fri, 18 Apr 2025 18:34:52 +0530
Subject: [PATCH] disable user-gesture restriction on sidepanel.open
Date: Tue, 22 Jul 2025 21:33:47 -0700
Subject: [PATCH] patch: disable-user-gesture-restriction-on-sidepanel
---
.../extensions/api/side_panel/side_panel_api.cc | 10 +++++-----

View File

@@ -1,7 +1,7 @@
From b31b7e7e822c757d7984dc1c490d283c35a7e8e3 Mon Sep 17 00:00:00 2001
From 372b58eafdcdcb6afc50855eb67e8bea1a52b94a Mon Sep 17 00:00:00 2001
From: Nikhil Sonti <nikhilsv92@gmail.com>
Date: Tue, 22 Jul 2025 21:36:10 -0700
Subject: [PATCH 14/20] patch(M): embed-third-party-llm-in-side-panel
Subject: [PATCH] patch(M): llm-chat
---
chrome/app/chrome_command_ids.h | 2 +

View File

@@ -1,7 +1,7 @@
From 0cce2c6f6213e7225d7136b19be82e79602d5753 Mon Sep 17 00:00:00 2001
From 0f11d4438b9a1723c188d23c55ff76d80b4b8ee2 Mon Sep 17 00:00:00 2001
From: Nikhil Sonti <nikhilsv92@gmail.com>
Date: Tue, 22 Jul 2025 21:36:34 -0700
Subject: [PATCH 15/20] patch(M): clash-of-gpts
Subject: [PATCH] patch(M): llm-hub
---
chrome/app/chrome_command_ids.h | 1 +

View File

@@ -1,7 +1,7 @@
From 8cb99ed9da476935d6750e2e20f04e1fde8a7a6d Mon Sep 17 00:00:00 2001
From 700edf9260afe9b76b8d274f355b60586d94eafd Mon Sep 17 00:00:00 2001
From: Nikhil Sonti <nikhilsv92@gmail.com>
Date: Mon, 16 Jun 2025 14:14:40 -0700
Subject: [PATCH 1/2] Nxtscape sparkler updater
Date: Tue, 22 Jul 2025 21:35:35 -0700
Subject: [PATCH] patch: nxtscape-updater-sparkle
---
chrome/BUILD.gn | 5 +
@@ -872,10 +872,10 @@ index 0000000000000..984f9ab75b1fa
+}
\ No newline at end of file
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 93096ad92c1a3..5accc0ef01f89 100644
index b14d64308080f..bf0e13928f08e 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -3435,6 +3435,8 @@ static_library("ui") {
@@ -3437,6 +3437,8 @@ static_library("ui") {
"views/frame/native_browser_frame_factory_mac.mm",
"views/tab_contents/chrome_web_contents_view_delegate_views_mac.h",
"views/tab_contents/chrome_web_contents_view_delegate_views_mac.mm",
@@ -884,7 +884,7 @@ index 93096ad92c1a3..5accc0ef01f89 100644
"webui/help/version_updater_mac.mm",
"webui/settings/mac_system_settings_handler.cc",
"webui/settings/mac_system_settings_handler.h",
@@ -3453,6 +3455,7 @@ static_library("ui") {
@@ -3455,6 +3457,7 @@ static_library("ui") {
allow_circular_includes_from += [ "//chrome/browser/apps/app_shim" ]
deps += [

View File

@@ -1,4 +1,4 @@
From e4b235350ad6edccaecf570f23b87a091576bfda Mon Sep 17 00:00:00 2001
From 81b5a06baee044d48b58f4cde27d9c6378612516 Mon Sep 17 00:00:00 2001
From: Nikhil Sonti <nikhilsv92@gmail.com>
Date: Tue, 22 Jul 2025 21:36:22 -0700
Subject: [PATCH] patch(M): pin browseros native panels

View File

@@ -1,4 +1,4 @@
From 0292293bff0997722faff60eaa29e5e7244fe781 Mon Sep 17 00:00:00 2001
From 4ed33cbac1f820cfa163c637f0e0a7ecc2d88c43 Mon Sep 17 00:00:00 2001
From: Nikhil Sonti <nikhilsv92@gmail.com>
Date: Thu, 31 Jul 2025 13:09:23 -0700
Subject: [PATCH] pin browseros extensions to extension toolbar

View File

@@ -1,7 +1,7 @@
From 41d77486e0399b493f577cc207750f13ccf24558 Mon Sep 17 00:00:00 2001
From 4539a8c2e1bd668d7f1f8d247d66855a86cf8428 Mon Sep 17 00:00:00 2001
From: Nikhil Sonti <nikhilsv92@gmail.com>
Date: Thu, 24 Jul 2025 16:14:27 -0700
Subject: [PATCH] BrowserOS settings page
Subject: [PATCH] patch: settings prefs page
---
.../api/settings_private/prefs_util.cc | 4 +
@@ -17,16 +17,16 @@ Subject: [PATCH] BrowserOS settings page
.../settings/settings_menu/settings_menu.html | 6 +
.../toolbar/pinned_action_toolbar_button.cc | 24 +-
.../toolbar/pinned_action_toolbar_button.h | 1 +
chrome/common/pref_names.h | 12 +
14 files changed, 652 insertions(+), 7 deletions(-)
chrome/common/pref_names.h | 4 +
14 files changed, 644 insertions(+), 7 deletions(-)
create mode 100644 chrome/browser/resources/settings/browseros_prefs_page/browseros_prefs_page.html
create mode 100644 chrome/browser/resources/settings/browseros_prefs_page/browseros_prefs_page.ts
diff --git a/chrome/browser/extensions/api/settings_private/prefs_util.cc b/chrome/browser/extensions/api/settings_private/prefs_util.cc
index 1869a54c5b4e4..0ffbb43806598 100644
index 200d72995460e..1bff654e3ac42 100644
--- a/chrome/browser/extensions/api/settings_private/prefs_util.cc
+++ b/chrome/browser/extensions/api/settings_private/prefs_util.cc
@@ -606,6 +606,10 @@ const PrefsUtil::TypedPrefMap& PrefsUtil::GetAllowlistedKeys() {
@@ -607,6 +607,10 @@ const PrefsUtil::TypedPrefMap& PrefsUtil::GetAllowlistedKeys() {
(*s_allowlist)["nxtscape.ollama_base_url"] = settings_api::PrefType::kString;
(*s_allowlist)["nxtscape.ollama_model"] = settings_api::PrefType::kString;
@@ -38,10 +38,10 @@ index 1869a54c5b4e4..0ffbb43806598 100644
// Accounts / Users / People.
(*s_allowlist)[ash::kAccountsPrefAllowGuest] =
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index 5a5b278252383..cf120aacb58d3 100644
index e6f03310af7ee..bfe1a9243a920 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -2349,6 +2349,12 @@ void RegisterNxtscapePrefs(user_prefs::PrefRegistrySyncable* registry) {
@@ -2357,6 +2357,12 @@ void RegisterNxtscapePrefs(user_prefs::PrefRegistrySyncable* registry) {
registry->RegisterStringPref("nxtscape.ollama_api_key", "");
registry->RegisterStringPref("nxtscape.ollama_base_url", "http://localhost:11434");
registry->RegisterStringPref("nxtscape.ollama_model", "");
@@ -839,25 +839,17 @@ index e1557abfda184..df7f5c078211a 100644
bool ShouldSkipExecutionForTesting() { return skip_execution_; }
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index 12f83b0cc1ab5..10c867a0660de 100644
index a453af343fed7..b06aec04ab52e 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -4273,6 +4273,18 @@ inline constexpr char kServiceWorkerToControlSrcdocIframeEnabled[] =
// is set as a SharedWorker script URL.
inline constexpr char kSharedWorkerBlobURLFixEnabled[] =
"worker.shared_worker_blob_url_fix_enabled";
+
+// *************** BROWSEROS PREFS ***************
+// These are BrowserOS-specific preferences
@@ -4288,6 +4288,10 @@ inline constexpr char kBrowserOSProviders[] = "browseros.providers";
// String containing the default provider ID for BrowserOS
inline constexpr char kBrowserOSDefaultProviderId[] =
"browseros.default_provider_id";
+
+// Boolean that controls whether toolbar labels are shown for BrowserOS actions
+inline constexpr char kBrowserOSShowToolbarLabels[] =
+ "browseros.show_toolbar_labels";
+
+// JSON string containing custom AI providers for BrowserOS
+inline constexpr char kBrowserOSCustomProviders[] =
+ "browseros.custom_providers";
+
} // namespace prefs
#endif // CHROME_COMMON_PREF_NAMES_H_

View File

@@ -1,14 +1,15 @@
From 0ae687a607db8b5945aa4d35588853fe9fc6a788 Mon Sep 17 00:00:00 2001
From 58cceea8003f85852f48c4b073b6c7e4444fc9ef Mon Sep 17 00:00:00 2001
From: Nikhil Sonti <nikhilsv92@gmail.com>
Date: Thu, 24 Jul 2025 13:48:38 -0700
Subject: [PATCH 19/20] Updates to third party llm and LLM hub
Subject: [PATCH] updates: llmchat and llmhub
---
.../browser/ui/browser_command_controller.cc | 14 +-
.../clash_of_gpts_coordinator.cc | 9 -
.../third_party_llm_panel_coordinator.cc | 226 +++++++++++++++++-
chrome/browser/ui/views/side_panel/BUILD.gn | 1 +
.../clash_of_gpts_coordinator.cc | 14 +-
.../third_party_llm_panel_coordinator.cc | 257 +++++++++++++++++-
.../third_party_llm_panel_coordinator.h | 39 ++-
4 files changed, 265 insertions(+), 23 deletions(-)
5 files changed, 302 insertions(+), 23 deletions(-)
diff --git a/chrome/browser/ui/browser_command_controller.cc b/chrome/browser/ui/browser_command_controller.cc
index b172b393c7b2b..52f78a5a46584 100644
@@ -39,11 +40,31 @@ index b172b393c7b2b..52f78a5a46584 100644
}
break;
case IDC_SHOW_APP_MENU:
diff --git a/chrome/browser/ui/views/side_panel/BUILD.gn b/chrome/browser/ui/views/side_panel/BUILD.gn
index a06f78dc7e4b6..56021613259dc 100644
--- a/chrome/browser/ui/views/side_panel/BUILD.gn
+++ b/chrome/browser/ui/views/side_panel/BUILD.gn
@@ -172,6 +172,7 @@ source_set("side_panel") {
"//components/keyed_service/core",
"//components/language/core/browser",
"//components/language/core/common",
+ "//components/metrics/browseros_metrics",
"//components/omnibox/browser:vector_icons",
"//components/optimization_guide/core:features",
"//components/performance_manager",
diff --git a/chrome/browser/ui/views/side_panel/clash_of_gpts/clash_of_gpts_coordinator.cc b/chrome/browser/ui/views/side_panel/clash_of_gpts/clash_of_gpts_coordinator.cc
index ce0ab7befb361..d206407c292a2 100644
index ce0ab7befb361..e6a8b8b97eada 100644
--- a/chrome/browser/ui/views/side_panel/clash_of_gpts/clash_of_gpts_coordinator.cc
+++ b/chrome/browser/ui/views/side_panel/clash_of_gpts/clash_of_gpts_coordinator.cc
@@ -61,19 +61,10 @@ ClashOfGptsCoordinator::~ClashOfGptsCoordinator() {
@@ -29,6 +29,7 @@
#include "ui/accessibility/ax_tree_update.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "third_party/blink/public/common/input/web_input_event.h"
+#include "components/metrics/browseros_metrics/browseros_metrics.h"
namespace {
@@ -61,19 +62,11 @@ ClashOfGptsCoordinator::~ClashOfGptsCoordinator() {
}
void ClashOfGptsCoordinator::Show() {
@@ -60,11 +81,22 @@ index ce0ab7befb361..d206407c292a2 100644
widget_->Activate();
- } else {
- LOG(ERROR) << "widget_ is null after CreateWindowIfNeeded!";
+ browseros_metrics::BrowserOSMetrics::Log("llmhub.shown");
}
}
@@ -221,6 +214,9 @@ void ClashOfGptsCoordinator::SetPaneCount(int count) {
current_pane_count_ = count;
SaveState();
+
+ browseros_metrics::BrowserOSMetrics::Log("llmhub.panecount.changed",
+ {{"count", base::Value(count)}});
// Update the view if it exists
if (view_) {
diff --git a/chrome/browser/ui/views/side_panel/third_party_llm/third_party_llm_panel_coordinator.cc b/chrome/browser/ui/views/side_panel/third_party_llm/third_party_llm_panel_coordinator.cc
index 21a1737b9bb83..5e396226413b7 100644
index 21a1737b9bb83..e0118e58a9990 100644
--- a/chrome/browser/ui/views/side_panel/third_party_llm/third_party_llm_panel_coordinator.cc
+++ b/chrome/browser/ui/views/side_panel/third_party_llm/third_party_llm_panel_coordinator.cc
@@ -8,6 +8,8 @@
@@ -84,7 +116,7 @@ index 21a1737b9bb83..5e396226413b7 100644
#include "components/prefs/pref_service.h"
#include "components/user_prefs/user_prefs.h"
#include "components/pref_registry/pref_registry_syncable.h"
@@ -48,10 +51,19 @@
@@ -48,10 +51,20 @@
#include "ui/base/clipboard/clipboard.h"
#include "ui/base/clipboard/scoped_clipboard_writer.h"
#include "chrome/browser/ui/browser_commands.h"
@@ -101,10 +133,11 @@ index 21a1737b9bb83..5e396226413b7 100644
+#include "chrome/browser/file_select_helper.h"
+#include "content/public/browser/file_select_listener.h"
+#include "content/public/browser/render_frame_host.h"
+#include "components/metrics/browseros_metrics/browseros_metrics.h"
namespace {
@@ -132,6 +144,7 @@ ThirdPartyLlmPanelCoordinator::CreateThirdPartyLlmWebView(
@@ -132,6 +145,7 @@ ThirdPartyLlmPanelCoordinator::CreateThirdPartyLlmWebView(
web_view_ = nullptr;
provider_selector_ = nullptr;
copy_feedback_label_ = nullptr;
@@ -112,7 +145,7 @@ index 21a1737b9bb83..5e396226413b7 100644
// Stop observing any previous views to prevent dangling observations.
view_observation_.RemoveAllObservations();
@@ -197,6 +210,34 @@ ThirdPartyLlmPanelCoordinator::CreateThirdPartyLlmWebView(
@@ -197,6 +211,34 @@ ThirdPartyLlmPanelCoordinator::CreateThirdPartyLlmWebView(
copy_button->SetImageHorizontalAlignment(views::ImageButton::ALIGN_CENTER);
copy_button->SetImageVerticalAlignment(views::ImageButton::ALIGN_MIDDLE);
@@ -147,7 +180,7 @@ index 21a1737b9bb83..5e396226413b7 100644
// Add open in new tab button
auto* open_button = header->AddChildView(
std::make_unique<views::ImageButton>(base::BindRepeating(
@@ -211,6 +252,23 @@ ThirdPartyLlmPanelCoordinator::CreateThirdPartyLlmWebView(
@@ -211,6 +253,23 @@ ThirdPartyLlmPanelCoordinator::CreateThirdPartyLlmWebView(
open_button->SetImageHorizontalAlignment(views::ImageButton::ALIGN_CENTER);
open_button->SetImageVerticalAlignment(views::ImageButton::ALIGN_MIDDLE);
@@ -171,7 +204,25 @@ index 21a1737b9bb83..5e396226413b7 100644
// Add separator
container->AddChildView(std::make_unique<views::Separator>());
@@ -365,6 +423,25 @@ std::u16string ThirdPartyLlmPanelCoordinator::GetProviderName(LlmProvider provid
@@ -286,6 +345,8 @@ ThirdPartyLlmPanelCoordinator::CreateThirdPartyLlmWebView(
shortcuts_label->SetFontList(
shortcuts_label->font_list().DeriveWithSizeDelta(-1));
+ browseros_metrics::BrowserOSMetrics::Log("llmchat.created");
+
return container;
}
@@ -306,6 +367,8 @@ void ThirdPartyLlmPanelCoordinator::DoProviderChange(LlmProvider new_provider) {
return;
provider_change_in_progress_ = true;
+
+ browseros_metrics::BrowserOSMetrics::Log("llmchat.provider.changed");
if (owned_web_contents_) {
GURL current_url = owned_web_contents_->GetURL();
@@ -365,6 +428,25 @@ std::u16string ThirdPartyLlmPanelCoordinator::GetProviderName(LlmProvider provid
}
}
@@ -197,7 +248,7 @@ index 21a1737b9bb83..5e396226413b7 100644
void ThirdPartyLlmPanelCoordinator::OnOpenInNewTab() {
if (!owned_web_contents_) {
return;
@@ -407,6 +484,80 @@ void ThirdPartyLlmPanelCoordinator::OnCopyContent() {
@@ -407,6 +489,82 @@ void ThirdPartyLlmPanelCoordinator::OnCopyContent() {
content::WebContents::AXTreeSnapshotPolicy::kSameOriginDirectDescendants);
}
@@ -259,6 +310,8 @@ index 21a1737b9bb83..5e396226413b7 100644
+ // Copy image to clipboard
+ ui::ScopedClipboardWriter clipboard_writer(ui::ClipboardBuffer::kCopyPaste);
+ clipboard_writer.WriteImage(image.AsBitmap());
+
+ browseros_metrics::BrowserOSMetrics::Log("llmchat.screenshot.captured");
+
+ // Show success feedback
+ if (copy_feedback_label_) {
@@ -278,7 +331,16 @@ index 21a1737b9bb83..5e396226413b7 100644
void ThirdPartyLlmPanelCoordinator::OnAccessibilityTreeReceived(
ui::AXTreeUpdate& update) {
// Build a map of node IDs to node data for easy lookup
@@ -494,6 +645,10 @@ void ThirdPartyLlmPanelCoordinator::OnViewIsDeleting(views::View* observed_view)
@@ -446,6 +604,8 @@ void ThirdPartyLlmPanelCoordinator::OnAccessibilityTreeReceived(
ui::ScopedClipboardWriter clipboard_writer(ui::ClipboardBuffer::kCopyPaste);
clipboard_writer.WriteText(formatted_output);
+ browseros_metrics::BrowserOSMetrics::Log("llmchat.content.copied");
+
// Show feedback message
if (copy_feedback_label_) {
copy_feedback_label_->SetText(u"Content copied to clipboard");
@@ -494,6 +654,10 @@ void ThirdPartyLlmPanelCoordinator::OnViewIsDeleting(views::View* observed_view)
web_view_ = nullptr;
}
@@ -289,7 +351,7 @@ index 21a1737b9bb83..5e396226413b7 100644
// Remove observation for this view.
view_observation_.RemoveObservation(observed_view);
}
@@ -627,6 +782,14 @@ content::WebContents* ThirdPartyLlmPanelCoordinator::AddNewContents(
@@ -627,6 +791,14 @@ content::WebContents* ThirdPartyLlmPanelCoordinator::AddNewContents(
return nullptr;
}
@@ -304,7 +366,7 @@ index 21a1737b9bb83..5e396226413b7 100644
void ThirdPartyLlmPanelCoordinator::CycleProvider() {
// If a provider change is already in flight, ignore additional toggle
// requests to prevent state races that could desynchronize the combobox and
@@ -814,10 +977,71 @@ void ThirdPartyLlmPanelCoordinator::OnProfileWillBeDestroyed(Profile* profile) {
@@ -814,10 +986,93 @@ void ThirdPartyLlmPanelCoordinator::OnProfileWillBeDestroyed(Profile* profile) {
}
}
@@ -350,6 +412,28 @@ index 21a1737b9bb83..5e396226413b7 100644
+
+void ThirdPartyLlmPanelCoordinator::ExecuteCommand(int command_id,
+ int event_flags) {
+ std::string event_name;
+ switch (command_id) {
+ case IDC_COPY_CONTENT:
+ event_name = "llmchat.menu.content.copied";
+ break;
+ case IDC_SCREENSHOT:
+ event_name = "llmchat.menu.screenshot.captured";
+ break;
+ case IDC_REFRESH:
+ event_name = "llmchat.menu.refresh";
+ break;
+ case IDC_OPEN_IN_NEW_TAB:
+ event_name = "llmchat.menu.newtab";
+ break;
+ case IDC_CLASH_OF_GPTS:
+ event_name = "llmchat.menu.hub";
+ break;
+ }
+ if (!event_name.empty()) {
+ browseros_metrics::BrowserOSMetrics::Log(event_name);
+ }
+
+ switch (command_id) {
+ case IDC_COPY_CONTENT:
+ OnCopyContent();

View File

@@ -1,314 +0,0 @@
From 6fe6dc59d30de967b26c6c912e38bff3bb6376c7 Mon Sep 17 00:00:00 2001
From: Nikhil Sonti <nikhilsv92@gmail.com>
Date: Tue, 5 Aug 2025 15:22:49 -0700
Subject: [PATCH 1/3] BrowserOS API for get/set prefs
---
.../api/browser_os/browser_os_api.cc | 163 ++++++++++++++++++
.../api/browser_os/browser_os_api.h | 40 +++++
chrome/common/extensions/api/browser_os.idl | 36 ++++
.../extension_function_histogram_value.h | 3 +
4 files changed, 242 insertions(+)
diff --git a/chrome/browser/extensions/api/browser_os/browser_os_api.cc b/chrome/browser/extensions/api/browser_os/browser_os_api.cc
index 31d54b9d0fb58..c2315276f6cd6 100644
--- a/chrome/browser/extensions/api/browser_os/browser_os_api.cc
+++ b/chrome/browser/extensions/api/browser_os/browser_os_api.cc
@@ -11,6 +11,8 @@
#include <vector>
#include "base/functional/bind.h"
+#include "chrome/browser/profiles/profile.h"
+#include "components/prefs/pref_service.h"
#include "base/json/json_writer.h"
#include "base/strings/utf_string_conversions.h"
#include "base/base64.h"
@@ -791,5 +793,166 @@ void BrowserOSGetSnapshotFunction::OnContentProcessed(
browser_os::GetSnapshot::Results::Create(result.snapshot)));
}
+// BrowserOSGetPrefFunction
+ExtensionFunction::ResponseAction BrowserOSGetPrefFunction::Run() {
+ std::optional<browser_os::GetPref::Params> params =
+ browser_os::GetPref::Params::Create(args());
+ EXTENSION_FUNCTION_VALIDATE(params);
+
+ // Allow reading any preferences - no restrictions for now
+ // This includes nxtscape.*, browseros.*, and any other preferences
+ // Note: Be careful with this in production as it exposes all Chrome preferences
+
+ Profile* profile = Profile::FromBrowserContext(browser_context());
+ PrefService* prefs = profile->GetPrefs();
+
+ if (!prefs->HasPrefPath(params->name)) {
+ return RespondNow(Error("Preference not found: " + params->name));
+ }
+
+ // Create PrefObject to return
+ browser_os::PrefObject pref_obj;
+ pref_obj.key = params->name;
+
+ // Get the preference value - user value if set, otherwise default
+ // GetDefaultPrefValue returns const base::Value* and is guaranteed
+ // to not be nullptr for registered preferences per Chromium API
+ const base::Value* value = prefs->GetUserPrefValue(params->name);
+ if (!value) {
+ value = prefs->GetDefaultPrefValue(params->name);
+ }
+
+ // Set type based on value type
+ switch (value->type()) {
+ case base::Value::Type::BOOLEAN:
+ pref_obj.type = "boolean";
+ break;
+ case base::Value::Type::INTEGER:
+ pref_obj.type = "number";
+ break;
+ case base::Value::Type::DOUBLE:
+ pref_obj.type = "number";
+ break;
+ case base::Value::Type::STRING:
+ pref_obj.type = "string";
+ break;
+ case base::Value::Type::LIST:
+ pref_obj.type = "list";
+ break;
+ case base::Value::Type::DICT:
+ pref_obj.type = "dictionary";
+ break;
+ default:
+ pref_obj.type = "unknown";
+ }
+
+ pref_obj.value = value->Clone();
+
+ return RespondNow(ArgumentList(
+ browser_os::GetPref::Results::Create(pref_obj)));
+}
+
+// BrowserOSSetPrefFunction
+ExtensionFunction::ResponseAction BrowserOSSetPrefFunction::Run() {
+ std::optional<browser_os::SetPref::Params> params =
+ browser_os::SetPref::Params::Create(args());
+ EXTENSION_FUNCTION_VALIDATE(params);
+
+ // Allow setting nxtscape.* and browseros.* prefs
+ // This provides access to AI provider configurations
+ if (!params->name.starts_with("nxtscape.") &&
+ !params->name.starts_with("browseros.")) {
+ return RespondNow(Error("Only nxtscape.* and browseros.* preferences can be modified"));
+ }
+
+ Profile* profile = Profile::FromBrowserContext(browser_context());
+ PrefService* prefs = profile->GetPrefs();
+
+ if (!prefs->HasPrefPath(params->name)) {
+ return RespondNow(Error("Preference not found: " + params->name));
+ }
+
+ // Set the preference value
+ prefs->Set(params->name, params->value);
+
+ return RespondNow(ArgumentList(
+ browser_os::SetPref::Results::Create(true)));
+}
+
+// BrowserOSGetAllPrefsFunction
+ExtensionFunction::ResponseAction BrowserOSGetAllPrefsFunction::Run() {
+ Profile* profile = Profile::FromBrowserContext(browser_context());
+ PrefService* prefs = profile->GetPrefs();
+
+ // List of all nxtscape and browseros prefs to return
+ const std::vector<std::string> nxtscape_prefs = {
+ // Legacy nxtscape prefs
+ "nxtscape.default_provider",
+ "nxtscape.nxtscape_model",
+ "nxtscape.openai_api_key",
+ "nxtscape.openai_model",
+ "nxtscape.openai_base_url",
+ "nxtscape.anthropic_api_key",
+ "nxtscape.anthropic_model",
+ "nxtscape.anthropic_base_url",
+ "nxtscape.gemini_api_key",
+ "nxtscape.gemini_model",
+ "nxtscape.gemini_base_url",
+ "nxtscape.ollama_api_key",
+ "nxtscape.ollama_model",
+ "nxtscape.ollama_base_url",
+ // New browseros prefs
+ "browseros.providers",
+ "browseros.default_provider_id",
+ "browseros.show_toolbar_labels",
+ "browseros.custom_providers"
+ };
+
+ std::vector<browser_os::PrefObject> pref_objects;
+
+ for (const auto& pref_name : nxtscape_prefs) {
+ if (prefs->HasPrefPath(pref_name)) {
+ browser_os::PrefObject pref_obj;
+ pref_obj.key = pref_name;
+
+ // Get the preference value - user value if set, otherwise default
+ const base::Value* value = prefs->GetUserPrefValue(pref_name);
+ if (!value) {
+ value = prefs->GetDefaultPrefValue(pref_name);
+ }
+
+ // Set type based on value type
+ switch (value->type()) {
+ case base::Value::Type::BOOLEAN:
+ pref_obj.type = "boolean";
+ break;
+ case base::Value::Type::INTEGER:
+ pref_obj.type = "number";
+ break;
+ case base::Value::Type::DOUBLE:
+ pref_obj.type = "number";
+ break;
+ case base::Value::Type::STRING:
+ pref_obj.type = "string";
+ break;
+ case base::Value::Type::LIST:
+ pref_obj.type = "list";
+ break;
+ case base::Value::Type::DICT:
+ pref_obj.type = "dictionary";
+ break;
+ default:
+ pref_obj.type = "unknown";
+ }
+
+ pref_obj.value = value->Clone();
+ pref_objects.push_back(std::move(pref_obj));
+ }
+ }
+
+ return RespondNow(ArgumentList(
+ browser_os::GetAllPrefs::Results::Create(pref_objects)));
+}
+
} // namespace api
} // namespace extensions
diff --git a/chrome/browser/extensions/api/browser_os/browser_os_api.h b/chrome/browser/extensions/api/browser_os/browser_os_api.h
index 6090d2fbeb6a4..597a09ed04765 100644
--- a/chrome/browser/extensions/api/browser_os/browser_os_api.h
+++ b/chrome/browser/extensions/api/browser_os/browser_os_api.h
@@ -209,6 +209,46 @@ class BrowserOSGetSnapshotFunction : public ExtensionFunction {
api::ContentProcessingResult result);
};
+// Settings API functions
+class BrowserOSGetPrefFunction : public ExtensionFunction {
+ public:
+ DECLARE_EXTENSION_FUNCTION("browserOS.getPref", BROWSER_OS_GETPREF)
+
+ BrowserOSGetPrefFunction() = default;
+
+ protected:
+ ~BrowserOSGetPrefFunction() override = default;
+
+ // ExtensionFunction:
+ ResponseAction Run() override;
+};
+
+class BrowserOSSetPrefFunction : public ExtensionFunction {
+ public:
+ DECLARE_EXTENSION_FUNCTION("browserOS.setPref", BROWSER_OS_SETPREF)
+
+ BrowserOSSetPrefFunction() = default;
+
+ protected:
+ ~BrowserOSSetPrefFunction() override = default;
+
+ // ExtensionFunction:
+ ResponseAction Run() override;
+};
+
+class BrowserOSGetAllPrefsFunction : public ExtensionFunction {
+ public:
+ DECLARE_EXTENSION_FUNCTION("browserOS.getAllPrefs", BROWSER_OS_GETALLPREFS)
+
+ BrowserOSGetAllPrefsFunction() = default;
+
+ protected:
+ ~BrowserOSGetAllPrefsFunction() override = default;
+
+ // ExtensionFunction:
+ ResponseAction Run() override;
+};
+
} // namespace api
} // namespace extensions
diff --git a/chrome/common/extensions/api/browser_os.idl b/chrome/common/extensions/api/browser_os.idl
index 6934ee144987d..1c47fb75b68d8 100644
--- a/chrome/common/extensions/api/browser_os.idl
+++ b/chrome/common/extensions/api/browser_os.idl
@@ -168,6 +168,18 @@ namespace browserOS {
callback GetSnapshotCallback = void(Snapshot snapshot);
+ // Settings-related types
+ dictionary PrefObject {
+ DOMString key;
+ DOMString type;
+ any value;
+ };
+
+ // Callback for settings functions
+ callback GetPrefCallback = void(PrefObject pref);
+ callback SetPrefCallback = void(boolean success);
+ callback GetAllPrefsCallback = void(PrefObject[] prefs);
+
interface Functions {
// Gets the full accessibility tree for a tab
// |tabId|: The tab to get the accessibility tree for. Defaults to active tab.
@@ -284,6 +296,30 @@ namespace browserOS {
SnapshotType type,
optional SnapshotOptions options,
GetSnapshotCallback callback);
+
+ // Settings API functions - compatible with chrome.settingsPrivate
+ // Gets a specific preference value
+ // |name|: The preference name (e.g., "nxtscape.default_provider").
+ // |callback|: Called with the preference object.
+ static void getPref(
+ DOMString name,
+ GetPrefCallback callback);
+
+ // Sets a specific preference value
+ // |name|: The preference name (e.g., "nxtscape.default_provider").
+ // |value|: The value to set.
+ // |pageId|: Optional page ID for settings tracking (can be empty string).
+ // |callback|: Called with success status.
+ static void setPref(
+ DOMString name,
+ any value,
+ optional DOMString pageId,
+ SetPrefCallback callback);
+
+ // Gets all preferences (filtered to nxtscape.* prefs)
+ // |callback|: Called with array of preference objects.
+ static void getAllPrefs(
+ GetAllPrefsCallback callback);
};
};
diff --git a/extensions/browser/extension_function_histogram_value.h b/extensions/browser/extension_function_histogram_value.h
index 965512eee1a46..979ccbdede568 100644
--- a/extensions/browser/extension_function_histogram_value.h
+++ b/extensions/browser/extension_function_histogram_value.h
@@ -2010,6 +2010,9 @@ enum HistogramValue {
BROWSER_OS_GETPAGESTRUCTURE = 1947,
BROWSER_OS_CAPTURESCREENSHOT = 1948,
BROWSER_OS_GETSNAPSHOT = 1949,
+ BROWSER_OS_GETPREF = 1950,
+ BROWSER_OS_SETPREF = 1951,
+ BROWSER_OS_GETALLPREFS = 1952,
// Last entry: Add new entries above, then run:
// tools/metrics/histograms/update_extension_histograms.py
ENUM_BOUNDARY
--
2.49.0

View File

@@ -1,25 +0,0 @@
From a8f1634380eecaa1805c20bd4e6c112a3bcce4ea Mon Sep 17 00:00:00 2001
From: Nikhil Sonti <nikhilsv92@gmail.com>
Date: Fri, 13 Jun 2025 15:49:17 -0700
Subject: [PATCH] [UI] updating About string
---
chrome/app/settings_chromium_strings.grdp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/chrome/app/settings_chromium_strings.grdp b/chrome/app/settings_chromium_strings.grdp
index 7d97fdc317d7f..6eefff3e0ea48 100644
--- a/chrome/app/settings_chromium_strings.grdp
+++ b/chrome/app/settings_chromium_strings.grdp
@@ -19,7 +19,7 @@
</then>
<else>
<message name="IDS_SETTINGS_ABOUT_PROGRAM" desc="Menu title for the About Chromium page.">
- About Chromium
+ About BrowserOS
</message>
<message name="IDS_SETTINGS_GET_HELP_USING_CHROME" desc="Text of the button which takes the user to the Chrome help page.">
Get help with Chromium
--
2.49.0

View File

@@ -1,114 +0,0 @@
From 63fe007641d93e054e7120d61a69804ffb9c0bb0 Mon Sep 17 00:00:00 2001
From: Nikhil Sonti <nikhilsv92@gmail.com>
Date: Thu, 12 Jun 2025 19:46:08 -0700
Subject: [PATCH] ai chat extension
---
chrome/browser/browser_resources.grd | 1 +
.../component_extensions_allowlist/allowlist.cc | 2 ++
chrome/browser/extensions/component_loader.cc | 3 +++
chrome/browser/resources/BUILD.gn | 1 +
.../resources/component_extension_resources.grd | 14 +++++++++++++-
chrome/common/extensions/extension_constants.h | 3 +++
6 files changed, 23 insertions(+), 1 deletion(-)
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index 533d97a0d7e02..80f296feed297 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -238,6 +238,7 @@
<include name="IDR_CERT_MANAGER_DIALOG_HTML" file="resources\certificate_manager\certificate_manager_dialog.html" type="BINDATA" />
<include name="IDR_CERT_MANAGER_DIALOG_V2_HTML" file="resources\certificate_manager\certificate_manager_dialog_v2.html" type="BINDATA" />
</if>
+ <include name="IDR_AI_SIDE_PANEL_MANIFEST" file="resources\ai_side_panel\manifest.json" type="BINDATA" />
</includes>
</release>
</grit>
diff --git a/chrome/browser/extensions/component_extensions_allowlist/allowlist.cc b/chrome/browser/extensions/component_extensions_allowlist/allowlist.cc
index b818225467c01..b2e9219008a54 100644
--- a/chrome/browser/extensions/component_extensions_allowlist/allowlist.cc
+++ b/chrome/browser/extensions/component_extensions_allowlist/allowlist.cc
@@ -31,6 +31,7 @@ bool IsComponentExtensionAllowlisted(const std::string& extension_id) {
constexpr auto kAllowed = base::MakeFixedFlatSet<std::string_view>({
extension_misc::kInAppPaymentsSupportAppId,
extension_misc::kPdfExtensionId,
+ extension_misc::kAISidePanelExtensionId,
#if BUILDFLAG(IS_CHROMEOS)
extension_misc::kAssessmentAssistantExtensionId,
extension_misc::kAccessibilityCommonExtensionId,
@@ -89,6 +90,7 @@ bool IsComponentExtensionAllowlisted(int manifest_resource_id) {
case IDR_TTS_ENGINE_MANIFEST:
#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC)
case IDR_WEBSTORE_MANIFEST:
+ case IDR_AI_SIDE_PANEL_MANIFEST: // AI Side Panel Extension
#if BUILDFLAG(IS_CHROMEOS)
// Separate ChromeOS list, as it is quite large.
diff --git a/chrome/browser/extensions/component_loader.cc b/chrome/browser/extensions/component_loader.cc
index 97868e0d32ffc..12ba5765f1cd3 100644
--- a/chrome/browser/extensions/component_loader.cc
+++ b/chrome/browser/extensions/component_loader.cc
@@ -543,6 +543,9 @@ void ComponentLoader::AddDefaultComponentExtensionsWithBackgroundPages(
command_line->HasSwitch(
::switches::kDisableComponentExtensionsWithBackgroundPages));
+ Add(IDR_AI_SIDE_PANEL_MANIFEST,
+ base::FilePath(FILE_PATH_LITERAL("ai_side_panel")));
+
#if BUILDFLAG(ENABLE_HANGOUT_SERVICES_EXTENSION)
const bool enable_hangout_services_extension_for_testing =
command_line->HasSwitch(::switches::kTestType) &&
diff --git a/chrome/browser/resources/BUILD.gn b/chrome/browser/resources/BUILD.gn
index ecc70941cd1f4..b479c135ceffe 100644
--- a/chrome/browser/resources/BUILD.gn
+++ b/chrome/browser/resources/BUILD.gn
@@ -19,6 +19,7 @@ group("resources") {
public_deps = [
"saved_tab_groups_unsupported:resources",
"segmentation_internals:resources",
+ "ai_side_panel:build",
]
if (!is_android) {
diff --git a/chrome/browser/resources/component_extension_resources.grd b/chrome/browser/resources/component_extension_resources.grd
index 2e355c8ce7c2f..d0d2bf499ee62 100644
--- a/chrome/browser/resources/component_extension_resources.grd
+++ b/chrome/browser/resources/component_extension_resources.grd
@@ -12,7 +12,19 @@
</outputs>
<release seq="1">
<includes>
- <include name="IDR_NETWORK_SPEECH_SYNTHESIS_JS" file="network_speech_synthesis/tts_extension.js" type="BINDATA" />
+ <!-- AI Side Panel Extension -->
+ <include name="IDR_AI_SIDE_PANEL_MANIFEST" file="ai_side_panel/manifest.json" type="BINDATA" />
+ <include name="IDR_AI_SIDE_PANEL_BACKGROUND_JS" file="ai_side_panel/background.js" type="BINDATA" />
+ <include name="IDR_AI_SIDE_PANEL_CONTENT_JS" file="ai_side_panel/content.js" type="BINDATA" />
+ <include name="IDR_AI_SIDE_PANEL_SIDEPANEL_HTML" file="ai_side_panel/sidepanel.html" type="BINDATA" />
+ <include name="IDR_AI_SIDE_PANEL_SIDEPANEL_JS" file="ai_side_panel/sidepanel.js" type="BINDATA" />
+ <include name="IDR_AI_SIDE_PANEL_READABILITY_JS" file="ai_side_panel/Readability.js" type="BINDATA" />
+ <include name="IDR_AI_SIDE_PANEL_BUILDDOMTREE_JS" file="ai_side_panel/buildDomTree.js" type="BINDATA" />
+ <include name="IDR_AI_SIDE_PANEL_ICON16" file="ai_side_panel/assets/icon16.png" type="BINDATA" />
+ <include name="IDR_AI_SIDE_PANEL_ICON48" file="ai_side_panel/assets/icon48.png" type="BINDATA" />
+ <include name="IDR_AI_SIDE_PANEL_ICON128" file="ai_side_panel/assets/icon128.png" type="BINDATA" />
+
+ <include name="IDR_NETWORK_SPEECH_SYNTHESIS_JS" file="network_speech_synthesis/tts_extension.js" type="BINDATA" />
<include name="IDR_NETWORK_SPEECH_SYNTHESIS_MV3_AUDIO_HTML" file="network_speech_synthesis/mv3/audio.html" type="BINDATA" />
<include name="IDR_NETWORK_SPEECH_SYNTHESIS_MV3_AUDIO_JS" file="network_speech_synthesis/mv3/audio.js" type="BINDATA" />
diff --git a/chrome/common/extensions/extension_constants.h b/chrome/common/extensions/extension_constants.h
index 7a46135d8fa99..b73ab6259a19d 100644
--- a/chrome/common/extensions/extension_constants.h
+++ b/chrome/common/extensions/extension_constants.h
@@ -27,6 +27,9 @@ inline constexpr char kLaunchSourceAppListInfoDialog[] =
} // namespace extension_urls
namespace extension_misc {
+// The extension id of the AI Side Panel extension.
+inline constexpr char kAISidePanelExtensionId[] =
+ "opocihnfjcgcjecjhjjgifkbkgeeoonh";
// The extension id of the Calendar application.
inline constexpr char kCalendarAppId[] = "ejjicmeblgpmajnghnpcppodonldlgfn";
--
2.49.0

View File

@@ -1,188 +0,0 @@
From 96ef816788c4e6f0cdc7a7360204da5c99696be3 Mon Sep 17 00:00:00 2001
From: Nikhil Sonti <nikhilsv92@gmail.com>
Date: Thu, 5 Jun 2025 08:22:04 -0700
Subject: [PATCH] branding
---
chrome/app/chromium_strings.grd | 10 +++----
chrome/app/theme/chromium/BRANDING | 16 +++++------
chrome/enterprise_companion/branding.gni | 32 ++++++++++-----------
chrome/updater/branding.gni | 36 ++++++++++++------------
4 files changed, 47 insertions(+), 47 deletions(-)
diff --git a/chrome/app/chromium_strings.grd b/chrome/app/chromium_strings.grd
index 2e5d2a8929ca8..c340e17579615 100644
--- a/chrome/app/chromium_strings.grd
+++ b/chrome/app/chromium_strings.grd
@@ -294,10 +294,10 @@ If you update this file, be sure also to update google_chrome_strings.grd. -->
</then>
<else>
<message name="IDS_PRODUCT_NAME" desc="The Chrome application name" translateable="false">
- Chromium
+ BrowserOS
</message>
<message name="IDS_SHORT_PRODUCT_NAME" desc="The Chrome application short name." translateable="false">
- Chromium
+ BrowserOS
</message>
</else>
</if>
@@ -312,12 +312,12 @@ If you update this file, be sure also to update google_chrome_strings.grd. -->
Chromium is a web browser that runs webpages and applications with lightning speed. It's fast, stable, and easy to use. Browse the web more safely with malware and phishing protection built into Chromium.
</message>
<message name="IDS_WELCOME_TO_CHROME" desc="Welcoming text announced via screen readers the first time Chrome is launched at the conclusion of installation.">
- Welcome to Chromium; new browser window opened
+ Welcome to BrowserOS; new browser window opened
</message>
</if>
<if expr="is_macosx or is_linux">
<message name="IDS_FIRST_RUN_DIALOG_WINDOW_TITLE" desc="Window title of First Run dialog on Mac and Linux, displayed in title bar">
- Welcome to Chromium
+ Welcome to BrowserOS
</message>
</if>
<if expr="is_chromeos">
@@ -447,7 +447,7 @@ If you update this file, be sure also to update google_chrome_strings.grd. -->
<if expr="_is_chrome_for_testing_branded">
<then>
<message name="IDS_ABOUT_VERSION_COMPANY_NAME" desc="Company name on the about pages">
- Google LLC
+ Felafax, Inc
</message>
<message name="IDS_ABOUT_VERSION_COPYRIGHT" desc="Copyright information on the about pages">
Copyright <ph name="YEAR">{0,date,y}<ex>2016</ex></ph> Google LLC. All rights reserved.
diff --git a/chrome/app/theme/chromium/BRANDING b/chrome/app/theme/chromium/BRANDING
index f8363d5b294fe..ad8baa62212ad 100644
--- a/chrome/app/theme/chromium/BRANDING
+++ b/chrome/app/theme/chromium/BRANDING
@@ -1,10 +1,10 @@
-COMPANY_FULLNAME=The Chromium Authors
-COMPANY_SHORTNAME=The Chromium Authors
-PRODUCT_FULLNAME=Chromium
-PRODUCT_SHORTNAME=Chromium
-PRODUCT_INSTALLER_FULLNAME=Chromium Installer
-PRODUCT_INSTALLER_SHORTNAME=Chromium Installer
-COPYRIGHT=Copyright @LASTCHANGE_YEAR@ The Chromium Authors. All rights reserved.
-MAC_BUNDLE_ID=org.chromium.Chromium
+COMPANY_FULLNAME=BrowserOS
+COMPANY_SHORTNAME=BrowserOS
+PRODUCT_FULLNAME=BrowserOS
+PRODUCT_SHORTNAME=BrowserOS
+PRODUCT_INSTALLER_FULLNAME=BrowserOS Installer
+PRODUCT_INSTALLER_SHORTNAME=BrowserOS Installer
+COPYRIGHT=Copyright 2025 BrowserOS. All rights reserved.
+MAC_BUNDLE_ID=org.browseros.BrowserOS
MAC_CREATOR_CODE=Cr24
MAC_TEAM_ID=
diff --git a/chrome/enterprise_companion/branding.gni b/chrome/enterprise_companion/branding.gni
index 6b4469870d693..5ff88b0bc1d3e 100644
--- a/chrome/enterprise_companion/branding.gni
+++ b/chrome/enterprise_companion/branding.gni
@@ -1,37 +1,37 @@
-# Copyright 2014 The Chromium Authors
+# Copyright 2014 The Nxtscape Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("//build/config/chrome_build.gni")
if (is_chrome_branded) {
- enterprise_companion_crash_product_name = "Chrome_Enterprise_Companion"
+ enterprise_companion_crash_product_name = "BrowserOS_Enterprise_Companion"
enterprise_companion_crash_upload_url =
"https://clients2.google.com/cr/report"
enterprise_companion_appid = "{85eedf37-756c-4972-9399-5a12a4bee148}"
- enterprise_companion_company_short_name = "Google"
- enterprise_companion_company_short_name_lowercase = "google"
- enterprise_companion_company_short_name_uppercase = "GOOGLE"
- enterprise_companion_product_full_name = "ChromeEnterpriseCompanion"
+ enterprise_companion_company_short_name = "BrowserOS"
+ enterprise_companion_company_short_name_lowercase = "browseros"
+ enterprise_companion_company_short_name_uppercase = "BROWSEROS"
+ enterprise_companion_product_full_name = "BrowserOSEnterpriseCompanion"
enterprise_companion_product_full_name_dashed_lowercase =
- "chrome-enterprise-companion"
- enterprise_companion_keystone_app_name = "GoogleSoftwareUpdate"
+ "browseros-enterprise-companion"
+ enterprise_companion_keystone_app_name = "BrowserOSSoftwareUpdate"
mac_enterprise_companion_bundle_identifier =
- "com.google.ChromeEnterpriseCompanion"
+ "com.browseros.BrowserOSEnterpriseCompanion"
} else {
- enterprise_companion_crash_product_name = "Chromium_Enterprise_Companion"
+ enterprise_companion_crash_product_name = "BrowserOS_Enterprise_Companion"
enterprise_companion_crash_upload_url =
"https://clients2.google.com/cr/staging_report"
enterprise_companion_appid = "{d6acc642-8982-441d-949b-312d5ccb559f}"
- enterprise_companion_company_short_name = "Chromium"
- enterprise_companion_company_short_name_lowercase = "chromium"
- enterprise_companion_company_short_name_uppercase = "CHROMIUM"
- enterprise_companion_product_full_name = "ChromiumEnterpriseCompanion"
+ enterprise_companion_company_short_name = "BrowserOS"
+ enterprise_companion_company_short_name_lowercase = "browseros"
+ enterprise_companion_company_short_name_uppercase = "BROWSEROS"
+ enterprise_companion_product_full_name = "BrowserOSEnterpriseCompanion"
enterprise_companion_product_full_name_dashed_lowercase =
"chromium-enterprise-companion"
- enterprise_companion_keystone_app_name = "ChromiumSoftwareUpdate"
+ enterprise_companion_keystone_app_name = "BrowserOSSoftwareUpdate"
mac_enterprise_companion_bundle_identifier =
- "org.chromium.ChromiumEnterpriseCompanion"
+ "org.browseros.BrowserOSEnterpriseCompanion"
}
enterprise_companion_device_management_server_url =
diff --git a/chrome/updater/branding.gni b/chrome/updater/branding.gni
index 1f9bf5847f642..03a2ec68526a5 100644
--- a/chrome/updater/branding.gni
+++ b/chrome/updater/branding.gni
@@ -7,28 +7,28 @@ import("//build/config/chrome_build.gni")
if (is_chrome_branded) {
import("//chrome/updater/internal/branding_google.gni")
} else {
- browser_name = "Chromium"
- browser_product_name = "Chromium"
- crash_product_name = "ChromiumUpdater"
+ browser_name = "BrowserOS"
+ browser_product_name = "BrowserOS"
+ crash_product_name = "BrowserOSUpdater"
crash_upload_url = "https://clients2.google.com/cr/staging_report"
help_center_url = "http://support.google.com/installer/"
app_logo_url = "https://dl.google.com/update2/installers/icons/"
- keystone_app_name = "ChromiumSoftwareUpdate"
- keystone_bundle_identifier = "org.chromium.Keystone"
- mac_browser_bundle_identifier = "org.chromium.Chromium"
- mac_updater_bundle_identifier = "org.chromium.ChromiumUpdater"
- privileged_helper_bundle_name = "ChromiumUpdaterPrivilegedHelper"
- privileged_helper_name = "org.chromium.Chromium.UpdaterPrivilegedHelper"
- updater_company_full_name = "Chromium Authors"
- updater_company_short_name = "Chromium"
- updater_company_short_name_lowercase = "chromium"
- updater_company_short_name_uppercase = "CHROMIUM"
+ keystone_app_name = "BrowserOSSoftwareUpdate"
+ keystone_bundle_identifier = "org.browseros.Keystone"
+ mac_browser_bundle_identifier = "org.browseros.BrowserOS"
+ mac_updater_bundle_identifier = "org.browseros.BrowserOSUpdater"
+ privileged_helper_bundle_name = "BrowserOSUpdaterPrivilegedHelper"
+ privileged_helper_name = "org.browseros.BrowserOS.UpdaterPrivilegedHelper"
+ updater_company_full_name = "BrowserOS Authors"
+ updater_company_short_name = "BrowserOS"
+ updater_company_short_name_lowercase = "browseros"
+ updater_company_short_name_uppercase = "BROWSEROS"
updater_copyright =
- "Copyright 2020 The Chromium Authors. All rights reserved."
- updater_product_full_name = "ChromiumUpdater"
- updater_product_full_name_dashed_lowercase = "chromium-updater"
- updater_product_full_display_name = "Chromium Updater"
- updater_metainstaller_name = "Chromium Installer"
+ "Copyright 2025 BrowserOS Authors. All rights reserved."
+ updater_product_full_name = "BrowserOSUpdater"
+ updater_product_full_name_dashed_lowercase = "browseros-updater"
+ updater_product_full_display_name = "BrowserOS Updater"
+ updater_metainstaller_name = "BrowserOS Installer"
mac_team_identifier = "PLACEHOLDER"
updater_appid = "{6e8ffa8f-e7e2-4000-9884-589283c27015}"
qualification_appid = "{43f3a046-04b3-4443-a770-d67dae90e440}"
--
2.49.0

View File

@@ -1,718 +0,0 @@
From b291917ed013e35b372ffe63cdf5dbc88aa11a17 Mon Sep 17 00:00:00 2001
From: Nikhil Sonti <nikhilsv92@gmail.com>
Date: Thu, 7 Aug 2025 09:22:55 -0700
Subject: [PATCH] browseros api: fix coordinate calculation for interactive
snapshot
---
.../api/browser_os/browser_os_api_helpers.cc | 246 ++++++++++++++++--
.../api/browser_os/browser_os_api_helpers.h | 23 ++
.../browser_os_snapshot_processor.cc | 195 ++++++--------
.../browser_os_snapshot_processor.h | 16 +-
4 files changed, 352 insertions(+), 128 deletions(-)
diff --git a/chrome/browser/extensions/api/browser_os/browser_os_api_helpers.cc b/chrome/browser/extensions/api/browser_os/browser_os_api_helpers.cc
index ff119a6b12134..716630689b088 100644
--- a/chrome/browser/extensions/api/browser_os/browser_os_api_helpers.cc
+++ b/chrome/browser/extensions/api/browser_os/browser_os_api_helpers.cc
@@ -14,11 +14,14 @@
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/public/browser/render_widget_host.h"
#include "content/public/browser/render_widget_host_view.h"
+#include "content/browser/renderer_host/render_widget_host_view_base.h"
+#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/web_contents.h"
#include "third_party/blink/public/common/input/web_input_event.h"
#include "third_party/blink/public/common/input/web_keyboard_event.h"
#include "third_party/blink/public/common/input/web_mouse_event.h"
#include "third_party/blink/public/common/input/web_mouse_wheel_event.h"
+#include "third_party/blink/public/common/page/page_zoom.h"
#include "ui/base/ime/ime_text_span.h"
#include "ui/events/base_event_utils.h"
#include "ui/events/keycodes/dom/dom_code.h"
@@ -30,6 +33,211 @@
namespace extensions {
namespace api {
+// Define PI for cross-platform compatibility
+// M_PI is not defined on Windows/MSVC by default
+constexpr float kPi = 3.14159265358979323846f;
+
+// Compute CSS->widget scale matching DevTools InputHandler::ScaleFactor.
+// We intentionally exclude device scale factor (DSF). Widget coordinates
+// used by input are in DIPs; DSF is handled by the compositor. We also set
+// PositionInScreen = PositionInWidget to avoid unit mixing on HiDPI.
+float CssToWidgetScale(content::WebContents* web_contents,
+ content::RenderWidgetHost* rwh) {
+ float zoom = 1.0f;
+ if (auto* rwhi = static_cast<content::RenderWidgetHostImpl*>(rwh)) {
+ if (auto* wci = static_cast<content::WebContentsImpl*>(web_contents)) {
+ zoom = blink::ZoomLevelToZoomFactor(wci->GetPendingZoomLevel(rwhi));
+ }
+ }
+
+ float css_zoom = 1.0f;
+ if (auto* view = rwh ? rwh->GetView() : nullptr) {
+ if (auto* view_base =
+ static_cast<content::RenderWidgetHostViewBase*>(view)) {
+ css_zoom = view_base->GetCSSZoomFactor();
+ }
+ }
+
+ float page_scale = 1.0f;
+ if (auto* wci = static_cast<content::WebContentsImpl*>(web_contents)) {
+ page_scale = wci->GetPrimaryPage().GetPageScaleFactor();
+ }
+
+ return zoom * css_zoom * page_scale;
+}
+
+// Helper function to get center point of a node's bounds in CSS pixels.
+// On HiDPI (e.g., macOS Retina), normalize physical pixels by DSF so the
+// returned point aligns with document CSS coordinates used for visualization.
+gfx::PointF GetNodeCenterPoint(content::WebContents* web_contents,
+ const NodeInfo& node_info) {
+ gfx::PointF center(node_info.bounds.x() + node_info.bounds.width() / 2.0f,
+ node_info.bounds.y() + node_info.bounds.height() / 2.0f);
+
+ if (!web_contents)
+ return center;
+
+ content::RenderFrameHost* rfh = web_contents->GetPrimaryMainFrame();
+ if (!rfh)
+ return center;
+ content::RenderWidgetHost* rwh = rfh->GetRenderWidgetHost();
+ if (!rwh)
+ return center;
+ if (auto* view_any = rwh->GetView()) {
+ if (auto* view_base =
+ static_cast<content::RenderWidgetHostViewBase*>(view_any)) {
+ const float dsf = view_base->GetDeviceScaleFactor();
+ if (dsf > 0.0f && dsf != 1.0f) {
+ center.set_x(center.x() / dsf);
+ center.set_y(center.y() / dsf);
+ }
+ }
+ }
+ return center;
+}
+
+// Helper function to visualize a human-like cursor click.
+// Shows an orange cursor triangle with ripple effect that moves to the target.
+// This uses CSS transitions/animations and cleans itself up automatically.
+void VisualizeInteractionPoint(content::WebContents* web_contents,
+ const gfx::PointF& point,
+ int duration_ms,
+ float offset_range) {
+ content::RenderFrameHost* rfh = web_contents->GetPrimaryMainFrame();
+ if (!rfh)
+ return;
+
+ // Create visualization with a cursor triangle and ripple.
+ // Randomize starting position within offset_range for more natural movement.
+ // Generate random angle and distance for starting position
+ float angle = (rand() % 360) * kPi / 180.0f; // Random angle in radians
+ float distance = offset_range * 0.5f + (rand() % (int)(offset_range * 0.5f)); // 50-100% of offset_range
+
+ const float start_x = point.x() - (cos(angle) * distance);
+ const float start_y = point.y() - (sin(angle) * distance);
+
+ // Build the JavaScript code using string concatenation to avoid format string issues
+ std::string js_code = absl::StrFormat(
+ R"(
+ (function() {
+ var COLOR = '#FC661A';
+ var LIGHT_COLOR = '#FFA366'; // Lighter shade for ripple
+ var TARGET_X = %f, TARGET_Y = %f;
+ var START_X = %f, START_Y = %f;
+ var DURATION = %d;
+
+ // Remove previous indicators
+ document.querySelectorAll('.browseros-indicator').forEach(e => e.remove());
+
+ // Styles (insert once)
+ if (!document.querySelector('#browseros-indicator-styles')) {
+ var style = document.createElement('style');
+ style.id = 'browseros-indicator-styles';
+ style.textContent = `
+ @keyframes browseros-ripple {
+ 0%% {
+ transform: translate(-50%%, -50%%) scale(0.3);
+ opacity: 0.6;
+ }
+ 100%% {
+ transform: translate(-50%%, -50%%) scale(2.5);
+ opacity: 0;
+ }
+ }
+ `;
+ document.head.appendChild(style);
+ }
+
+ // Container positioned via transform for smooth movement
+ var container = document.createElement('div');
+ container.className = 'browseros-indicator';
+ container.style.position = 'fixed';
+ container.style.left = '0';
+ container.style.top = '0';
+ container.style.transform = 'translate(' + START_X + 'px, ' + START_Y + 'px)';
+ container.style.transition = 'transform 220ms cubic-bezier(.2,.7,.2,1)';
+ container.style.zIndex = '999999';
+ container.style.pointerEvents = 'none';
+
+ // Regular triangle cursor
+ var cursor = document.createElement('div');
+ cursor.style.width = '0';
+ cursor.style.height = '0';
+ cursor.style.borderStyle = 'solid';
+ cursor.style.borderWidth = '0 8px 14px 8px'; // Regular triangle proportions
+ cursor.style.borderColor = 'transparent transparent ' + COLOR + ' transparent';
+ cursor.style.filter = 'drop-shadow(0 1px 2px rgba(0,0,0,.4)) drop-shadow(0 0 3px rgba(252,102,26,.3))';
+ cursor.style.transform = 'rotate(-45deg)';
+ cursor.style.position = 'absolute';
+ cursor.style.left = '-8px'; // Offset so tip is at 0,0
+ cursor.style.top = '-10px'; // Offset so tip is at 0,0
+ container.appendChild(cursor);
+
+ // Ripple container positioned exactly at cursor tip (0,0 of container)
+ var rippleContainer = document.createElement('div');
+ rippleContainer.style.position = 'absolute';
+ rippleContainer.style.left = '0'; // Tip is at origin
+ rippleContainer.style.top = '0';
+ rippleContainer.style.width = '0';
+ rippleContainer.style.height = '0';
+
+ // Ripple ring 1 (inner ripple) - centered on cursor tip
+ var ring1 = document.createElement('div');
+ ring1.style.position = 'absolute';
+ ring1.style.left = '50%%';
+ ring1.style.top = '50%%';
+ ring1.style.width = '16px';
+ ring1.style.height = '16px';
+ ring1.style.borderRadius = '50%%';
+ ring1.style.border = '2px solid ' + LIGHT_COLOR;
+ ring1.style.animation = 'browseros-ripple 600ms ease-out forwards';
+ rippleContainer.appendChild(ring1);
+
+ // Ripple ring 2 (outer ripple with slight delay) - centered on cursor tip
+ var ring2 = document.createElement('div');
+ ring2.style.position = 'absolute';
+ ring2.style.left = '50%%';
+ ring2.style.top = '50%%';
+ ring2.style.width = '16px';
+ ring2.style.height = '16px';
+ ring2.style.borderRadius = '50%%';
+ ring2.style.border = '1.5px solid ' + COLOR;
+ ring2.style.animation = 'browseros-ripple 800ms ease-out forwards';
+ ring2.style.animationDelay = '150ms';
+ rippleContainer.appendChild(ring2);
+
+ container.appendChild(rippleContainer);
+ document.body.appendChild(container);
+
+ // Kick off movement next frame
+ requestAnimationFrame(() => {
+ container.style.transform = 'translate(' + TARGET_X + 'px, ' + TARGET_Y + 'px)';
+ });
+
+ // Fade and remove after duration
+ setTimeout(() => {
+ container.style.transition = 'opacity 320ms ease, transform 200ms ease-out';
+ container.style.opacity = '0';
+ setTimeout(() => container.remove(), 360);
+ }, Math.max(300, DURATION));
+ })();
+ )",
+ point.x(), point.y(),
+ start_x, start_y,
+ duration_ms);
+
+ std::u16string js_visualizer = base::UTF8ToUTF16(js_code);
+
+ rfh->ExecuteJavaScriptForTests(
+ js_visualizer,
+ base::NullCallback(),
+ /*honor_js_content_settings=*/false);
+
+ // Small delay to ensure the indicator is visible
+ base::PlatformThread::Sleep(base::Milliseconds(30));
+}
+
+
// Helper to create and dispatch mouse events for clicking
void PointClick(content::WebContents* web_contents,
const gfx::PointF& point) {
@@ -45,12 +253,14 @@ void PointClick(content::WebContents* web_contents,
if (!rwhv)
return;
- // Get viewport bounds for screen position calculation
- gfx::Rect viewport_bounds = rwhv->GetViewBounds();
- gfx::PointF viewport_origin(viewport_bounds.x(), viewport_bounds.y());
-
- // The coordinates are already in widget space (CSS pixels)
- gfx::PointF widget_point = point;
+ // The incoming point is in CSS pixels (already normalized by DSF if needed).
+ // Convert CSS → widget DIPs using the same scale chain as DevTools.
+ gfx::PointF css_point = point;
+ const float scale = CssToWidgetScale(web_contents, rwh);
+ gfx::PointF widget_point(css_point.x() * scale, css_point.y() * scale);
+
+ // Visualize the actual target location on the page (CSS pixel coords).
+ VisualizeInteractionPoint(web_contents, css_point, 2000, 50.0f);
// Create mouse down event
blink::WebMouseEvent mouse_down;
@@ -58,8 +268,9 @@ void PointClick(content::WebContents* web_contents,
mouse_down.button = blink::WebPointerProperties::Button::kLeft;
mouse_down.click_count = 1;
mouse_down.SetPositionInWidget(widget_point.x(), widget_point.y());
- mouse_down.SetPositionInScreen(widget_point.x() + viewport_origin.x(),
- widget_point.y() + viewport_origin.y());
+ // Align with DevTools: screen position equals widget position to avoid
+ // unit-mixing on HiDPI. The compositor handles DSF.
+ mouse_down.SetPositionInScreen(widget_point.x(), widget_point.y());
mouse_down.SetTimeStamp(ui::EventTimeForNow());
mouse_down.SetModifiers(blink::WebInputEvent::kLeftButtonDown);
@@ -69,8 +280,7 @@ void PointClick(content::WebContents* web_contents,
mouse_up.button = blink::WebPointerProperties::Button::kLeft;
mouse_up.click_count = 1;
mouse_up.SetPositionInWidget(widget_point.x(), widget_point.y());
- mouse_up.SetPositionInScreen(widget_point.x() + viewport_origin.x(),
- widget_point.y() + viewport_origin.y());
+ mouse_up.SetPositionInScreen(widget_point.x(), widget_point.y());
mouse_up.SetTimeStamp(ui::EventTimeForNow());
// Send the events
@@ -495,9 +705,7 @@ void JavaScriptType(content::WebContents* web_contents,
bool ClickWithDetection(content::WebContents* web_contents,
const NodeInfo& node_info) {
// First try coordinate-based click with change detection
- gfx::PointF click_point(
- node_info.bounds.x() + node_info.bounds.width() / 2.0f,
- node_info.bounds.y() + node_info.bounds.height() / 2.0f);
+ gfx::PointF click_point = GetNodeCenterPoint(web_contents, node_info);
bool changed = BrowserOSChangeDetector::ExecuteWithDetection(
web_contents,
@@ -521,6 +729,9 @@ bool ClickWithDetection(content::WebContents* web_contents,
bool TypeWithDetection(content::WebContents* web_contents,
const NodeInfo& node_info,
const std::string& text) {
+ // Get center point for visualization and clicking
+ gfx::PointF click_point = GetNodeCenterPoint(web_contents, node_info);
+
// Try native typing first (more natural interaction)
bool changed = BrowserOSChangeDetector::ExecuteWithDetection(
web_contents,
@@ -528,9 +739,6 @@ bool TypeWithDetection(content::WebContents* web_contents,
// Focus the element first
HtmlFocus(web_contents, node_info);
// Click to ensure activation
- gfx::PointF click_point(
- node_info.bounds.x() + node_info.bounds.width() / 2.0f,
- node_info.bounds.y() + node_info.bounds.height() / 2.0f);
PointClick(web_contents, click_point);
// Then type using native IME
NativeType(web_contents, text);
@@ -553,6 +761,12 @@ bool TypeWithDetection(content::WebContents* web_contents,
// Helper to clear an input field with change detection
bool ClearWithDetection(content::WebContents* web_contents,
const NodeInfo& node_info) {
+ // Get center point for visualization
+ gfx::PointF clear_point = GetNodeCenterPoint(web_contents, node_info);
+
+ // Visualize where we're about to clear (orange for clear)
+ VisualizeInteractionPoint(web_contents, clear_point, 2000, 50.0f);
+
// Use change detection with JavaScript clear
bool changed = BrowserOSChangeDetector::ExecuteWithDetection(
web_contents,
diff --git a/chrome/browser/extensions/api/browser_os/browser_os_api_helpers.h b/chrome/browser/extensions/api/browser_os/browser_os_api_helpers.h
index 86c5fb811c64f..6bbf3d9fc33d0 100644
--- a/chrome/browser/extensions/api/browser_os/browser_os_api_helpers.h
+++ b/chrome/browser/extensions/api/browser_os/browser_os_api_helpers.h
@@ -12,6 +12,7 @@
namespace content {
class WebContents;
+class RenderWidgetHost;
} // namespace content
namespace extensions {
@@ -19,6 +20,19 @@ namespace api {
struct NodeInfo;
+// Returns the multiplicative factor that converts CSS pixels (frame
+// coordinates) to widget DIPs for input events. This matches DevTools'
+// InputHandler::ScaleFactor(): browser zoom × CSS zoom × page scale. The
+// device scale factor (DSF) is NOT included because compositor handles it and
+// input expects widget DIPs (we also set screen = widget).
+float CssToWidgetScale(content::WebContents* web_contents,
+ content::RenderWidgetHost* rwh);
+
+// Returns the center point of a node's bounds in CSS pixels, normalized by
+// device scale factor when necessary so it aligns with document coordinates.
+gfx::PointF GetNodeCenterPoint(content::WebContents* web_contents,
+ const NodeInfo& node_info);
+
// Helper to create and dispatch mouse events for clicking
void PointClick(content::WebContents* web_contents,
const gfx::PointF& point);
@@ -71,6 +85,15 @@ bool ClearWithDetection(content::WebContents* web_contents,
bool KeyPressWithDetection(content::WebContents* web_contents,
const std::string& key);
+// Visualizes a human-like cursor click at a CSS point with orange color,
+// ripple effect and randomized movement-in animation.
+// duration_ms: How long before auto fade-out and removal.
+// offset_range: Max distance for randomized starting position (default 50px).
+void VisualizeInteractionPoint(content::WebContents* web_contents,
+ const gfx::PointF& point,
+ int duration_ms = 3000,
+ float offset_range = 50.0f);
+
} // namespace api
} // namespace extensions
diff --git a/chrome/browser/extensions/api/browser_os/browser_os_snapshot_processor.cc b/chrome/browser/extensions/api/browser_os/browser_os_snapshot_processor.cc
index ee9da99ed9bc7..90fa3d17874fc 100644
--- a/chrome/browser/extensions/api/browser_os/browser_os_snapshot_processor.cc
+++ b/chrome/browser/extensions/api/browser_os/browser_os_snapshot_processor.cc
@@ -23,8 +23,13 @@
#include "base/task/thread_pool.h"
#include "base/time/time.h"
#include "chrome/browser/extensions/api/browser_os/browser_os_api_utils.h"
+#include "content/public/browser/browser_thread.h"
+#include "ui/accessibility/ax_clipping_behavior.h"
+#include "ui/accessibility/ax_coordinate_system.h"
#include "ui/accessibility/ax_enum_util.h"
+#include "ui/accessibility/ax_node.h"
#include "ui/accessibility/ax_node_data.h"
+#include "ui/accessibility/ax_tree.h"
#include "ui/accessibility/ax_tree_id.h"
#include "ui/accessibility/ax_tree_update.h"
#include "ui/gfx/geometry/rect.h"
@@ -35,77 +40,39 @@
namespace extensions {
namespace api {
-// Helper to compute absolute bounds from relative bounds by walking up the tree
-// If bounds_cache is provided, it will be used to cache computed bounds
-static gfx::RectF ComputeAbsoluteBoundsFromRelative(
- const ui::AXNodeData& node_data,
- const std::unordered_map<int32_t, ui::AXNodeData>& node_map,
- std::unordered_map<int32_t, gfx::RectF>* bounds_cache = nullptr) {
- // Check cache first if provided
- if (bounds_cache) {
- auto cache_it = bounds_cache->find(node_data.id);
- if (cache_it != bounds_cache->end()) {
- return cache_it->second;
- }
- }
- // Compute absolute bounds by walking up the tree
- gfx::RectF absolute_bounds = node_data.relative_bounds.bounds;
- gfx::Transform accumulated_transform;
-
- // Apply this node's transform if it has one
- if (node_data.relative_bounds.transform) {
- accumulated_transform = *node_data.relative_bounds.transform;
+// Static method to compute bounds for a node using AXTree
+// This implements the same logic as BrowserAccessibility::GetBoundsRect
+gfx::Rect SnapshotProcessor::GetNodeBounds(
+ ui::AXTree* tree,
+ const ui::AXNode* node,
+ const ui::AXCoordinateSystem coordinate_system,
+ const ui::AXClippingBehavior clipping_behavior) {
+ if (!tree || !node) {
+ return gfx::Rect();
}
- // Walk up the tree to compute absolute position
- int32_t current_container_id = node_data.relative_bounds.offset_container_id;
- int walk_depth = 0;
+ // Start with empty bounds (same as GetBoundsRect does)
+ gfx::RectF bounds;
- while (current_container_id >= 0 && walk_depth < 100) { // Prevent infinite loops
- auto container_it = node_map.find(current_container_id);
- if (container_it == node_map.end()) {
- break;
- }
-
- const ui::AXNodeData& container = container_it->second;
-
- // Offset by container's position
- absolute_bounds.Offset(container.relative_bounds.bounds.x(),
- container.relative_bounds.bounds.y());
-
- // Apply container's transform if any
- if (container.relative_bounds.transform) {
- gfx::Transform container_transform = *container.relative_bounds.transform;
- container_transform.PostConcat(accumulated_transform);
- accumulated_transform = container_transform;
- }
-
- // Account for scroll offset if container has it
- if (container.HasIntAttribute(ax::mojom::IntAttribute::kScrollX) ||
- container.HasIntAttribute(ax::mojom::IntAttribute::kScrollY)) {
- int scroll_x = container.GetIntAttribute(ax::mojom::IntAttribute::kScrollX);
- int scroll_y = container.GetIntAttribute(ax::mojom::IntAttribute::kScrollY);
- absolute_bounds.Offset(-scroll_x, -scroll_y);
- }
-
- // Move to next container
- current_container_id = container.relative_bounds.offset_container_id;
- walk_depth++;
- }
+ // Apply RelativeToTreeBounds to get absolute bounds
+ const bool clip_bounds = clipping_behavior == ui::AXClippingBehavior::kClipped;
+ bool offscreen = false;
+ bounds = tree->RelativeToTreeBounds(node, bounds, &offscreen, clip_bounds);
- // Apply accumulated transform
- if (!accumulated_transform.IsIdentity()) {
- absolute_bounds = accumulated_transform.MapRect(absolute_bounds);
+ // For frame coordinates, we're done
+ // We use kFrame since we want viewport-relative coordinates
+ if (coordinate_system == ui::AXCoordinateSystem::kFrame) {
+ return gfx::ToEnclosingRect(bounds);
}
- // Store in cache if provided
- if (bounds_cache) {
- (*bounds_cache)[node_data.id] = absolute_bounds;
- }
+ // For root frame or screen coordinates, additional transformations would be needed
+ // but for our use case (click coordinates), frame coordinates are what we need
+ // since ForwardMouseEvent expects viewport-relative coordinates
- return absolute_bounds;
+ return gfx::ToEnclosingRect(bounds);
}
+
// ProcessedNode implementation
SnapshotProcessor::ProcessedNode::ProcessedNode()
: node_data(nullptr), node_id(0) {}
@@ -234,13 +201,13 @@ struct SnapshotProcessor::ProcessingContext
std::unordered_map<int32_t, ui::AXNodeData> node_map;
std::unordered_map<int32_t, int32_t> parent_map; // child_id -> parent_id
std::unordered_map<int32_t, std::vector<int32_t>> children_map; // parent_id -> child_ids
+ std::unique_ptr<ui::AXTree> ax_tree; // AXTree for computing accurate bounds
int tab_id;
ui::AXTreeID tree_id; // Tree ID for change detection
base::TimeTicks start_time;
size_t total_nodes;
size_t processed_batches;
size_t total_batches;
- gfx::Rect viewport_bounds;
base::OnceCallback<void(SnapshotProcessingResult)> callback;
private:
@@ -414,15 +381,11 @@ void PopulateNodeAttributes(
std::vector<SnapshotProcessor::ProcessedNode> SnapshotProcessor::ProcessNodeBatch(
const std::vector<ui::AXNodeData>& nodes_to_process,
const std::unordered_map<int32_t, ui::AXNodeData>& node_map,
- uint32_t start_node_id,
- const gfx::Rect& doc_viewport_bounds) {
+ ui::AXTree* ax_tree,
+ uint32_t start_node_id) {
std::vector<ProcessedNode> results;
results.reserve(nodes_to_process.size());
- // Local caches for this batch
- std::unordered_map<int32_t, gfx::RectF> bounds_cache;
- std::unordered_map<int32_t, uint64_t> path_cache;
-
uint32_t current_node_id = start_node_id;
for (const auto& node_data : nodes_to_process) {
@@ -450,9 +413,32 @@ std::vector<SnapshotProcessor::ProcessedNode> SnapshotProcessor::ProcessNodeBatc
data.name = SanitizeStringForOutput(name);
}
- // Compute absolute bounds with caching
- data.absolute_bounds = ComputeAbsoluteBoundsFromRelative(
- node_data, node_map, &bounds_cache);
+ // Compute bounds using AXTree
+ if (ax_tree) {
+ ui::AXNode* ax_node = ax_tree->GetFromId(node_data.id);
+ if (ax_node) {
+ // Get bounds in frame coordinates (viewport-relative CSS pixels)
+ gfx::Rect bounds = GetNodeBounds(
+ ax_tree,
+ ax_node,
+ ui::AXCoordinateSystem::kFrame,
+ // Use clipped bounds so the center lies within the visible area of
+ // scrolled/clip containers. This matches how clicks should target
+ // on-screen rects.
+ ui::AXClippingBehavior::kClipped);
+ data.absolute_bounds = gfx::RectF(bounds);
+
+ VLOG(3) << "[browseros] Node " << node_data.id
+ << " computed bounds: " << bounds.ToString();
+ } else {
+ // Node not found in AXTree, skip bounds computation
+ VLOG(3) << "[browseros] Node " << node_data.id
+ << " not found in AXTree, skipping bounds";
+ }
+ } else {
+ // No AXTree available
+ LOG(WARNING) << "[browseros] No AXTree available for bounds computation";
+ }
// Populate all attributes using helper function
PopulateNodeAttributes(node_data, data.attributes);
@@ -473,15 +459,9 @@ std::vector<SnapshotProcessor::ProcessedNode> SnapshotProcessor::ProcessNodeBatc
}
data.attributes["depth"] = std::to_string(depth);
- // Check if node is in viewport
- // TODO: Fix this logic. still not accurate in terms of saying if in view port or not
- bool in_viewport = false;
- if (!doc_viewport_bounds.IsEmpty()) {
- // Convert absolute bounds to integer rect for intersection test
- gfx::Rect node_rect = gfx::ToEnclosingRect(data.absolute_bounds);
- in_viewport = doc_viewport_bounds.Intersects(node_rect);
- }
- data.attributes["in_viewport"] = in_viewport ? "true" : "false";
+ // TODO: Fix viewport detection logic
+ // For now, mark all nodes as potentially in viewport
+ data.attributes["in_viewport"] = "unknown";
results.push_back(std::move(data));
}
@@ -594,6 +574,24 @@ void SnapshotProcessor::ProcessAccessibilityTree(
}
}
+ // Clear previous mappings for this tab
+ GetNodeIdMappings()[tab_id].clear();
+
+ // Create an AXTree from the tree update for accurate bounds computation
+ std::unique_ptr<ui::AXTree> ax_tree = std::make_unique<ui::AXTree>(tree_update);
+
+ if (!ax_tree) {
+ LOG(ERROR) << "[browseros] Failed to create AXTree from update";
+ SnapshotProcessingResult result;
+ result.nodes_processed = 0;
+ result.processing_time_ms = 0;
+ std::move(callback).Run(std::move(result));
+ return;
+ }
+
+ LOG(INFO) << "[browseros] Created AXTree with " << tree_update.nodes.size()
+ << " nodes for bounds computation";
+
// Prepare processing context using RefCounted
auto context = base::MakeRefCounted<ProcessingContext>();
context->snapshot.snapshot_id = snapshot_id;
@@ -602,6 +600,7 @@ void SnapshotProcessor::ProcessAccessibilityTree(
context->node_map = std::move(node_map);
context->parent_map = std::move(parent_map);
context->children_map = std::move(children_map);
+ context->ax_tree = std::move(ax_tree); // Store AXTree for bounds computation
context->start_time = start_time;
// Store the tree ID for change detection
@@ -609,35 +608,11 @@ void SnapshotProcessor::ProcessAccessibilityTree(
context->tree_id = tree_update.tree_data.tree_id;
}
- // Convert viewport size to document viewport bounds
- // Find the root node and get its scroll offset
- gfx::Rect doc_viewport_bounds;
- if (!viewport_size.IsEmpty() && tree_update.has_tree_data && tree_update.root_id != 0) {
- auto root_it = node_map.find(tree_update.root_id);
- if (root_it != node_map.end()) {
- const ui::AXNodeData& root_node = root_it->second;
- int scroll_x = root_node.GetIntAttribute(ax::mojom::IntAttribute::kScrollX);
- int scroll_y = root_node.GetIntAttribute(ax::mojom::IntAttribute::kScrollY);
-
- // Create viewport in document coordinates
- // Position is based on scroll offset, size is the visible viewport size
- doc_viewport_bounds = gfx::Rect(scroll_x, scroll_y,
- viewport_size.width(),
- viewport_size.height());
-
- LOG(INFO) << "Viewport size: " << viewport_size.ToString();
- LOG(INFO) << "Root scroll offset: (" << scroll_x << ", " << scroll_y << ")";
- LOG(INFO) << "Document viewport bounds: " << doc_viewport_bounds.ToString();
- }
- }
-
- context->viewport_bounds = doc_viewport_bounds;
+ // Viewport size is passed in but not currently used for viewport bounds calculation
+ // TODO: Implement proper viewport detection if needed
context->callback = std::move(callback);
context->processed_batches = 0;
- // Clear previous mappings for this tab
- GetNodeIdMappings()[tab_id].clear();
-
// Collect all nodes to process and filter
std::vector<ui::AXNodeData> nodes_to_process;
for (const auto& node : tree_update.nodes) {
@@ -681,9 +656,9 @@ void SnapshotProcessor::ProcessAccessibilityTree(
{base::TaskPriority::USER_VISIBLE},
base::BindOnce(&SnapshotProcessor::ProcessNodeBatch,
std::move(batch),
- context->node_map,
- start_node_id,
- context->viewport_bounds),
+ context->node_map,
+ context->ax_tree.get(), // Pass AXTree pointer for bounds computation
+ start_node_id),
base::BindOnce(&SnapshotProcessor::OnBatchProcessed,
context));
}
diff --git a/chrome/browser/extensions/api/browser_os/browser_os_snapshot_processor.h b/chrome/browser/extensions/api/browser_os/browser_os_snapshot_processor.h
index 5e1114c40fe89..c78655b6ae515 100644
--- a/chrome/browser/extensions/api/browser_os/browser_os_snapshot_processor.h
+++ b/chrome/browser/extensions/api/browser_os/browser_os_snapshot_processor.h
@@ -16,8 +16,12 @@
#include "ui/gfx/geometry/rect_f.h"
namespace ui {
+class AXNode;
+class AXTree;
struct AXNodeData;
struct AXTreeUpdate;
+enum class AXCoordinateSystem;
+enum class AXClippingBehavior;
} // namespace ui
namespace extensions {
@@ -65,16 +69,24 @@ class SnapshotProcessor {
base::OnceCallback<void(SnapshotProcessingResult)> callback);
// Process a batch of nodes (exposed for testing)
+ // The ax_tree is used to compute accurate bounds for each node
static std::vector<ProcessedNode> ProcessNodeBatch(
const std::vector<ui::AXNodeData>& nodes_to_process,
const std::unordered_map<int32_t, ui::AXNodeData>& node_map,
- uint32_t start_node_id,
- const gfx::Rect& doc_viewport_bounds);
+ ui::AXTree* ax_tree,
+ uint32_t start_node_id);
private:
// Internal processing context
struct ProcessingContext;
+ // Compute absolute bounds for a node using AXTree
+ // This implements the same logic as BrowserAccessibility::GetBoundsRect
+ static gfx::Rect GetNodeBounds(ui::AXTree* tree,
+ const ui::AXNode* node,
+ const ui::AXCoordinateSystem coordinate_system,
+ const ui::AXClippingBehavior clipping_behavior);
+
// Batch processing callback
static void OnBatchProcessed(scoped_refptr<ProcessingContext> context,
std::vector<ProcessedNode> batch_results);
--
2.49.0

File diff suppressed because it is too large Load Diff

View File

@@ -1,111 +0,0 @@
From 7b588a5687a2a871378d80c13e80edb318b4c3be Mon Sep 17 00:00:00 2001
From: Nikhil Sonti <nikhilsv92@gmail.com>
Date: Tue, 1 Jul 2025 18:10:00 -0700
Subject: [PATCH] bug reporter extension
---
chrome/browser/browser_resources.grd | 1 +
.../component_extensions_allowlist/allowlist.cc | 2 ++
chrome/browser/extensions/component_loader.cc | 3 +++
chrome/browser/resources/BUILD.gn | 1 +
.../resources/component_extension_resources.grd | 10 ++++++++++
chrome/common/extensions/extension_constants.h | 4 ++++
6 files changed, 21 insertions(+)
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index 80f296feed297..80eb79f78d743 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -239,6 +239,7 @@
<include name="IDR_CERT_MANAGER_DIALOG_V2_HTML" file="resources\certificate_manager\certificate_manager_dialog_v2.html" type="BINDATA" />
</if>
<include name="IDR_AI_SIDE_PANEL_MANIFEST" file="resources\ai_side_panel\manifest.json" type="BINDATA" />
+ <include name="IDR_BUG_REPORTER_MANIFEST" file="resources\bug_reporter\manifest.json" type="BINDATA" />
</includes>
</release>
</grit>
diff --git a/chrome/browser/extensions/component_extensions_allowlist/allowlist.cc b/chrome/browser/extensions/component_extensions_allowlist/allowlist.cc
index b2e9219008a54..c3831b5b78f7a 100644
--- a/chrome/browser/extensions/component_extensions_allowlist/allowlist.cc
+++ b/chrome/browser/extensions/component_extensions_allowlist/allowlist.cc
@@ -32,6 +32,7 @@ bool IsComponentExtensionAllowlisted(const std::string& extension_id) {
extension_misc::kInAppPaymentsSupportAppId,
extension_misc::kPdfExtensionId,
extension_misc::kAISidePanelExtensionId,
+ extension_misc::kBugReporterExtensionId,
#if BUILDFLAG(IS_CHROMEOS)
extension_misc::kAssessmentAssistantExtensionId,
extension_misc::kAccessibilityCommonExtensionId,
@@ -91,6 +92,7 @@ bool IsComponentExtensionAllowlisted(int manifest_resource_id) {
#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC)
case IDR_WEBSTORE_MANIFEST:
case IDR_AI_SIDE_PANEL_MANIFEST: // AI Side Panel Extension
+ case IDR_BUG_REPORTER_MANIFEST: // Bug Reporter Extension
#if BUILDFLAG(IS_CHROMEOS)
// Separate ChromeOS list, as it is quite large.
diff --git a/chrome/browser/extensions/component_loader.cc b/chrome/browser/extensions/component_loader.cc
index 12ba5765f1cd3..732ba2586334e 100644
--- a/chrome/browser/extensions/component_loader.cc
+++ b/chrome/browser/extensions/component_loader.cc
@@ -546,6 +546,9 @@ void ComponentLoader::AddDefaultComponentExtensionsWithBackgroundPages(
Add(IDR_AI_SIDE_PANEL_MANIFEST,
base::FilePath(FILE_PATH_LITERAL("ai_side_panel")));
+ Add(IDR_BUG_REPORTER_MANIFEST,
+ base::FilePath(FILE_PATH_LITERAL("bug_reporter")));
+
#if BUILDFLAG(ENABLE_HANGOUT_SERVICES_EXTENSION)
const bool enable_hangout_services_extension_for_testing =
command_line->HasSwitch(::switches::kTestType) &&
diff --git a/chrome/browser/resources/BUILD.gn b/chrome/browser/resources/BUILD.gn
index b479c135ceffe..31fbc653ac5c5 100644
--- a/chrome/browser/resources/BUILD.gn
+++ b/chrome/browser/resources/BUILD.gn
@@ -20,6 +20,7 @@ group("resources") {
"saved_tab_groups_unsupported:resources",
"segmentation_internals:resources",
"ai_side_panel:build",
+ "bug_reporter:build",
]
if (!is_android) {
diff --git a/chrome/browser/resources/component_extension_resources.grd b/chrome/browser/resources/component_extension_resources.grd
index d0d2bf499ee62..18f612b1ea959 100644
--- a/chrome/browser/resources/component_extension_resources.grd
+++ b/chrome/browser/resources/component_extension_resources.grd
@@ -24,6 +24,16 @@
<include name="IDR_AI_SIDE_PANEL_ICON48" file="ai_side_panel/assets/icon48.png" type="BINDATA" />
<include name="IDR_AI_SIDE_PANEL_ICON128" file="ai_side_panel/assets/icon128.png" type="BINDATA" />
+ <!-- Bug Reporter Extension -->
+ <include name="IDR_BUG_REPORTER_MANIFEST" file="bug_reporter/manifest.json" type="BINDATA" />
+ <include name="IDR_BUG_REPORTER_BACKGROUND_JS" file="bug_reporter/background.js" type="BINDATA" />
+ <include name="IDR_BUG_REPORTER_CONTENT_JS" file="bug_reporter/content.js" type="BINDATA" />
+ <include name="IDR_BUG_REPORTER_POPUP_HTML" file="bug_reporter/popup.html" type="BINDATA" />
+ <include name="IDR_BUG_REPORTER_POPUP_JS" file="bug_reporter/popup.js" type="BINDATA" />
+ <include name="IDR_BUG_REPORTER_ICON16" file="bug_reporter/assets/icon16.png" type="BINDATA" />
+ <include name="IDR_BUG_REPORTER_ICON48" file="bug_reporter/assets/icon48.png" type="BINDATA" />
+ <include name="IDR_BUG_REPORTER_ICON128" file="bug_reporter/assets/icon128.png" type="BINDATA" />
+
<include name="IDR_NETWORK_SPEECH_SYNTHESIS_JS" file="network_speech_synthesis/tts_extension.js" type="BINDATA" />
<include name="IDR_NETWORK_SPEECH_SYNTHESIS_MV3_AUDIO_HTML" file="network_speech_synthesis/mv3/audio.html" type="BINDATA" />
diff --git a/chrome/common/extensions/extension_constants.h b/chrome/common/extensions/extension_constants.h
index b73ab6259a19d..c650b045144bb 100644
--- a/chrome/common/extensions/extension_constants.h
+++ b/chrome/common/extensions/extension_constants.h
@@ -31,6 +31,10 @@ namespace extension_misc {
inline constexpr char kAISidePanelExtensionId[] =
"opocihnfjcgcjecjhjjgifkbkgeeoonh";
+// The extension id of the Bug Reporter extension.
+inline constexpr char kBugReporterExtensionId[] =
+ "jpajdgphofjhblkgpbemoelbnbinnpje";
+
// The extension id of the Calendar application.
inline constexpr char kCalendarAppId[] = "ejjicmeblgpmajnghnpcppodonldlgfn";
--
2.49.0

View File

@@ -1,261 +0,0 @@
From dd5b88d7b8c87c73f9036d4c0efdc32dfa2cb71b Mon Sep 17 00:00:00 2001
From: Nikhil Sonti <nikhilsv92@gmail.com>
Date: Wed, 2 Jul 2025 10:58:56 -0700
Subject: [PATCH] first run
---
chrome/browser/chrome_browser_main.cc | 2 +
.../browser/ui/webui/chrome_web_ui_configs.cc | 2 +
chrome/browser/ui/webui/nxtscape_first_run.h | 194 ++++++++++++++++++
chrome/common/webui_url_constants.cc | 1 +
4 files changed, 199 insertions(+)
create mode 100644 chrome/browser/ui/webui/nxtscape_first_run.h
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc
index 681fd3282078c..c1c03ff72af7e 100644
--- a/chrome/browser/chrome_browser_main.cc
+++ b/chrome/browser/chrome_browser_main.cc
@@ -1018,6 +1018,8 @@ int ChromeBrowserMainParts::PreCreateThreadsImpl() {
if (first_run::IsChromeFirstRun()) {
if (!base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kApp) &&
!base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kAppId)) {
+ browser_creator_->AddFirstRunTabs({GURL("chrome://browseros-first-run")});
+ browser_creator_->AddFirstRunTabs({GURL("https://bit.ly/BrowserOS-setup")});
browser_creator_->AddFirstRunTabs(master_prefs_->new_tabs);
}
diff --git a/chrome/browser/ui/webui/chrome_web_ui_configs.cc b/chrome/browser/ui/webui/chrome_web_ui_configs.cc
index cbcdde4afa71b..0b1381fe9813c 100644
--- a/chrome/browser/ui/webui/chrome_web_ui_configs.cc
+++ b/chrome/browser/ui/webui/chrome_web_ui_configs.cc
@@ -44,6 +44,7 @@
#include "chrome/browser/ui/webui/signin_internals_ui.h"
#include "chrome/browser/ui/webui/sync_internals/sync_internals_ui.h"
#include "chrome/browser/ui/webui/translate_internals/translate_internals_ui.h"
+#include "chrome/browser/ui/webui/nxtscape_first_run.h"
#include "chrome/browser/ui/webui/usb_internals/usb_internals_ui.h"
#include "chrome/browser/ui/webui/user_actions/user_actions_ui.h"
#include "chrome/browser/ui/webui/version/version_ui.h"
@@ -253,6 +254,7 @@ void RegisterChromeWebUIConfigs() {
map.AddWebUIConfig(std::make_unique<SiteEngagementUIConfig>());
map.AddWebUIConfig(std::make_unique<SyncInternalsUIConfig>());
map.AddWebUIConfig(std::make_unique<TranslateInternalsUIConfig>());
+ map.AddWebUIConfig(std::make_unique<NxtscapeFirstRunUIConfig>());
map.AddWebUIConfig(std::make_unique<UsbInternalsUIConfig>());
map.AddWebUIConfig(std::make_unique<UserActionsUIConfig>());
map.AddWebUIConfig(std::make_unique<VersionUIConfig>());
diff --git a/chrome/browser/ui/webui/nxtscape_first_run.h b/chrome/browser/ui/webui/nxtscape_first_run.h
new file mode 100644
index 0000000000000..3c2a0cbaffed5
--- /dev/null
+++ b/chrome/browser/ui/webui/nxtscape_first_run.h
@@ -0,0 +1,194 @@
+#ifndef CHROME_BROWSER_UI_WEBUI_NXTSCAPE_FIRST_RUN_H_
+#define CHROME_BROWSER_UI_WEBUI_NXTSCAPE_FIRST_RUN_H_
+
+#include "base/memory/ref_counted_memory.h"
+#include "chrome/browser/profiles/profile.h"
+#include "content/public/browser/url_data_source.h"
+#include "content/public/browser/web_ui.h"
+#include "content/public/browser/web_ui_controller.h"
+#include "content/public/browser/webui_config.h"
+#include "services/network/public/mojom/content_security_policy.mojom.h"
+
+class UFRDataSource : public content::URLDataSource {
+ public:
+ UFRDataSource() {}
+ UFRDataSource(const UFRDataSource&) = delete;
+ UFRDataSource& operator=(const UFRDataSource&) = delete;
+
+ // URLDataSource implementation:
+ std::string GetSource() override;
+ std::string GetMimeType(const GURL& url) override;
+ std::string GetContentSecurityPolicy(network::mojom::CSPDirectiveName directive) override;
+ void StartDataRequest(const GURL& url,
+ const content::WebContents::Getter& wc_getter,
+ GotDataCallback callback) override;
+};
+
+// Implementation of UFRDataSource
+std::string UFRDataSource::GetSource() {
+ return "browseros-first-run";
+}
+
+std::string UFRDataSource::GetMimeType(const GURL& url) {
+ return "text/html";
+}
+
+std::string UFRDataSource::GetContentSecurityPolicy(network::mojom::CSPDirectiveName directive) {
+ if (directive == network::mojom::CSPDirectiveName::ScriptSrc)
+ return "script-src 'unsafe-inline'";
+ return std::string();
+}
+
+void UFRDataSource::StartDataRequest(const GURL& url,
+ const content::WebContents::Getter& wc_getter,
+ GotDataCallback callback) {
+ std::string source = R"(<!DOCTYPE html>
+<html lang="en">
+<head>
+<title>BrowserOS First Run</title>
+<meta charset="UTF-8">
+<meta name="color-scheme" content="light dark">
+<style>
+ @import url(chrome://resources/css/text_defaults_md.css);
+ html{color:#202124; background:white; line-height:1.2em; font-family: sans-serif; font-size: 1.1em;}
+ a{color:#1967d2; text-decoration: none;}
+ a:hover{text-decoration: underline;}
+ h2{margin:0; padding:0.8em 1.33em; font-size: 1.5em;}
+ p,details{border-top:.063em solid #f0f0f0; margin:0; padding:1.2em 2em;}
+ ul,ol{padding-left:2.5em; margin-top: 0.5em; margin-bottom: 0.5em;}
+ code{background:rgba(128 128 128 / .2); padding:0.2em 0.5em; border-radius:0.25em; font-size: 0.9em;}
+ summary{cursor:pointer; font-weight: bold; padding: 0.5em 0;}
+ section{width:60em; max-width: 90%; margin:3.5em auto; padding:2em 2.5em; border-radius:.75em;
+ background:white; box-shadow:0 .1em .2em 0 rgba(0,0,0,0.1), 0 .2em .5em 0 rgba(0,0,0,0.1);}
+ .hero {text-align: center; padding-bottom: 1em;}
+ .hero h1 {font-size: 2.5em; margin-bottom: 0.2em; color: #333;}
+ .hero p {font-size: 1.1em; color: #555; border-top: none; padding-top: 0;}
+ .section-title { font-size: 1.8em; margin-bottom: 0.5em; color: #444;}
+ .feature-list li { margin-bottom: 0.5em; }
+ .community-links a { display: inline-block; margin: 0.5em; padding: 0.5em 1em; background-color: #f0f0f0; border-radius: 0.3em; color: #333; }
+ .community-links a:hover { background-color: #e0e0e0; }
+ .sub-headline {
+ display: block;
+ margin-top: 1.0em;
+ }
+
+ @media(prefers-color-scheme:dark){
+ html{color:#e8eaed; background:#202124}
+ a{color:#8ab4f8}
+ p,details{border-top:.063em solid #3f4042}
+ section{background:#292a2d; box-shadow:0 .1em .2em 0 rgba(0,0,0,0.3), 0 .2em .5em 0 rgba(0,0,0,0.3);}
+ .hero h1 {color: #f1f1f1;}
+ .hero p {color: #ccc;}
+ .section-title { color: #ddd;}
+ .community-links a { background-color: #3a3b3d; color: #e8eaed; }
+ .community-links a:hover { background-color: #4a4b4d; }
+ }
+</style>
+<base target="_blank">
+</head>
+<body>
+<section class="hero">
+ <h1>The Open-Source Agentic Browser 🦊</h1>
+ <p class="sub-headline">Your Browser, Reimagined. ✨</p>
+ <p>We believe browsers must be open source, not owned by search or ad companies. And the future is AI agents automating your work locally and securely. We're building the best browser for that future. 🚀</p>
+ <p style="font-size:0.9em; color: #777;">This page can always be accessed again at <a href="chrome://browseros-first-run"><code>chrome://browseros-first-run</code></a></p>
+</section>
+
+<section>
+ <h2 class="section-title">🚀 Getting Started</h2>
+ <p style="text-align: center; margin: 1em 0; padding: 0.8em; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); border-radius: 0.5em;">
+ <a href="https://bit.ly/BrowserOS-setup" target="_blank" style="color: white; font-weight: bold; font-size: 1.1em;">
+ 📖 Quick Start Guide - bit.ly/BrowserOS-setup
+ </a>
+ </p>
+ <details open>
+ <summary><b>📥 Import your data from Chrome</b></summary>
+ <ol>
+ <li>Navigate to <a href="chrome://settings/importData"><code>chrome://settings/importData</code></a></li>
+ <li>Click "Import"</li>
+ <li>Follow the on-screen prompts and click "Always allow" when prompted to import all your data at once</li>
+ </ol>
+ </details>
+ <details>
+ <summary><b>🔑 BYOK (Bring Your Own Keys)</b></summary>
+ <p style="padding: 1em 2em;">
+ You have full control over your AI models! Navigate to <a href="chrome://settings/browseros"><code>chrome://settings/browseros</code></a> to configure your own API keys for various providers.
+ </p>
+ <p style="padding: 0.5em 2em 1em 2em;">
+ <strong>Note:</strong> You can even run everything locally using <a href="https://ollama.com">Ollama</a>! 🔒
+ </p>
+ </details>
+ <details>
+ <summary><b>⌨️ Keyboard Shortcuts</b></summary>
+ <p style="padding: 1em 2em;">
+ <strong>Toggle AI Agent:</strong> Press <code>Cmd+E</code> to quickly open or close the AI agent sidebar. 🤖
+ </p>
+ </details>
+</section>
+
+<section>
+ <h2 class="section-title">✨ Key Features</h2>
+ <ul class="feature-list">
+ <li>🤖 <strong>BrowserOS Agent:</strong> Your productivity agent that can manage your tabs and browsing sessions. For example:
+ <ul>
+ <li>"list tabs I have open"</li>
+ <li>"close duplicate tabs"</li>
+ <li>"group tabs by topic"</li>
+ <li>"switch to Bookface tab"</li>
+ <li>"save my current browsing session as XYZ-Research"</li>
+ <li>"resume XYZ-Research browsing session"</li>
+ <li>"search my browser history for all github pages I visited"</li>
+ <li>"organize my entire bookmark collection"</li>
+ </ul>
+ </li>
+ <li>🧭 <strong>BrowserOS Navigator:</strong> Performs agentic tasks for you on web pages. For example:
+ <ul>
+ <li>Go to amazon.com and search for "hard disk"</li>
+ <li>Navigate to specific pages and interact with content</li>
+ <li>Automate repetitive browsing tasks</li>
+ </ul>
+ </li>
+ </ul>
+</section>
+
+<section>
+ <h2 class="section-title">🤝 Join Our Community & Explore</h2>
+ <p class="community-links">
+ <a href="https://discord.gg/YKwjt5vuKr">💬 Discord</a>
+ <a href="https://github.com/browseros-ai/BrowserOS">💻 GitHub</a>
+ <a href="https://x.com/browseros_ai">🐦 X (Twitter)</a>
+ </p>
+ <p style="font-size:0.9em; text-align:center;">Have questions or want to contribute? We'd love to hear from you!</p>
+</section>
+
+<script>
+ document.getElementById("bdic").onchange = function(e){
+ var f = new FileReader;
+ f.onload = function(){
+ var a = document.createElement("a");
+ a.setAttribute("href", "data:application/octet-stream;base64, " + f.result);
+ a.setAttribute("download", e.target.files[0].name.replace(/\.[^/.]+$/, ".bdic"));
+ a.click()
+ }, f.readAsText(this.files[0])};
+</script>
+</body>
+</html>)";
+ std::move(callback).Run(base::MakeRefCounted<base::RefCountedString>(std::move(source)));
+}
+
+class NxtscapeFirstRun;
+class NxtscapeFirstRunUIConfig : public content::DefaultWebUIConfig<NxtscapeFirstRun> {
+ public:
+ NxtscapeFirstRunUIConfig() : DefaultWebUIConfig("chrome", "browseros-first-run") {}
+};
+
+class NxtscapeFirstRun : public content::WebUIController {
+ public:
+ NxtscapeFirstRun(content::WebUI* web_ui) : content::WebUIController(web_ui) {
+ content::URLDataSource::Add(Profile::FromWebUI(web_ui), std::make_unique<UFRDataSource>());
+ }
+ NxtscapeFirstRun(const NxtscapeFirstRun&) = delete;
+ NxtscapeFirstRun& operator=(const NxtscapeFirstRun&) = delete;
+};
+
+#endif // CHROME_BROWSER_UI_WEBUI_NXTSCAPE_FIRST_RUN_H_
diff --git a/chrome/common/webui_url_constants.cc b/chrome/common/webui_url_constants.cc
index e5e724a22d015..3627df513cd04 100644
--- a/chrome/common/webui_url_constants.cc
+++ b/chrome/common/webui_url_constants.cc
@@ -72,6 +72,7 @@ bool IsSystemWebUIHost(std::string_view host) {
// These hosts will also be suggested by BuiltinProvider.
base::span<const base::cstring_view> ChromeURLHosts() {
static constexpr auto kChromeURLHosts = std::to_array<base::cstring_view>({
+ "browseros-first-run",
kChromeUIAboutHost,
kChromeUIAccessibilityHost,
#if !BUILDFLAG(IS_ANDROID)
--
2.49.0

View File

@@ -1,249 +0,0 @@
From 854e49826e860826723c15c539d72d8c2a7e1b8a Mon Sep 17 00:00:00 2001
From: Nikhil Sonti <nikhilsv92@gmail.com>
Date: Mon, 28 Jul 2025 12:01:51 -0700
Subject: [PATCH] remove keychain request
---
chrome/utility/importer/chrome_importer.cc | 167 ++-------------------
chrome/utility/importer/chrome_importer.h | 13 +-
2 files changed, 12 insertions(+), 168 deletions(-)
diff --git a/chrome/utility/importer/chrome_importer.cc b/chrome/utility/importer/chrome_importer.cc
index 9026dcc1ec6b1..5a7c392fd775a 100644
--- a/chrome/utility/importer/chrome_importer.cc
+++ b/chrome/utility/importer/chrome_importer.cc
@@ -20,9 +20,6 @@
#include "chrome/common/importer/importer_url_row.h"
#include "chrome/grit/generated_resources.h"
#include "chrome/utility/importer/favicon_reencode.h"
-#include "components/os_crypt/sync/os_crypt.h"
-#include "components/password_manager/core/browser/password_form.h"
-#include "components/password_manager/core/browser/password_store/login_database.h"
#include "sql/database.h"
#include "sql/statement.h"
#include "ui/base/l10n/l10n_util.h"
@@ -406,123 +403,15 @@ base::Time ChromeImporter::ChromeTimeToBaseTime(int64_t time) {
}
void ChromeImporter::ImportPasswords() {
- LOG(INFO) << "ChromeImporter: Starting passwords import";
-
- // Set up encryption keys for decrypting passwords
- base::FilePath source_path = source_path_;
-#if BUILDFLAG(IS_WIN)
- // On Windows, the path is different
- source_path = source_path_.DirName();
-#endif
-
- // Initialize encryption using the appropriate source path
- if (!SetEncryptionKey(source_path)) {
- LOG(ERROR) << "ChromeImporter: Failed to set encryption key for passwords";
- return;
- }
-
- // First try the main Login Data file
- ImportPasswordsFromFile(base::FilePath(FILE_PATH_LITERAL("Login Data")));
-
- // Then try the account-specific Login Data file if it exists
- ImportPasswordsFromFile(base::FilePath(FILE_PATH_LITERAL("Login Data For Account")));
-
- LOG(INFO) << "ChromeImporter: Passwords import complete";
+ // Password import is disabled - users should use CSV import from chrome://password-manager/passwords
+ LOG(INFO) << "ChromeImporter: Password import is disabled. "
+ << "Please use CSV import from chrome://password-manager/passwords";
+ return;
}
void ChromeImporter::ImportPasswordsFromFile(const base::FilePath& password_filename) {
- base::FilePath passwords_path = source_path_.Append(password_filename);
- if (!base::PathExists(passwords_path)) {
- LOG(INFO) << "ChromeImporter: " << password_filename.value() << " file not found";
- return;
- }
-
- // Create temporary directory for copying the database
- base::FilePath temp_directory;
- if (!base::CreateNewTempDirectory(base::FilePath::StringType(), &temp_directory)) {
- LOG(ERROR) << "ChromeImporter: Failed to create temp directory for passwords";
- return;
- }
-
- // Copy the database file to avoid lock issues
- base::FilePath temp_passwords_path = temp_directory.Append(password_filename.BaseName());
- if (!base::CopyFile(passwords_path, temp_passwords_path)) {
- LOG(ERROR) << "ChromeImporter: Failed to copy " << password_filename.value() << " file";
- base::DeletePathRecursively(temp_directory);
- return;
- }
-
- // Open the database using password manager's login database
- password_manager::LoginDatabase database(
- temp_passwords_path, password_manager::IsAccountStore(false));
-
- if (!database.Init(base::NullCallback(), nullptr)) {
- LOG(ERROR) << "ChromeImporter: Failed to initialize login database";
- base::DeletePathRecursively(temp_directory);
- return;
- }
-
- // Process regular logins
- std::vector<password_manager::PasswordForm> forms;
- bool success = database.GetAutofillableLogins(&forms);
- if (success) {
- LOG(INFO) << "ChromeImporter: Found " << forms.size() << " passwords";
- for (const auto& form : forms) {
- importer::ImportedPasswordForm imported_form;
- if (PasswordFormToImportedPasswordForm(form, imported_form)) {
- bridge_->SetPasswordForm(imported_form);
- }
- }
- }
-
- // Process blocklisted logins
- std::vector<password_manager::PasswordForm> blocklist;
- success = database.GetBlocklistLogins(&blocklist);
- if (success && !blocklist.empty()) {
- LOG(INFO) << "ChromeImporter: Found " << blocklist.size() << " blocklisted passwords";
- for (const auto& form : blocklist) {
- importer::ImportedPasswordForm imported_form;
- if (PasswordFormToImportedPasswordForm(form, imported_form)) {
- bridge_->SetPasswordForm(imported_form);
- }
- }
- }
-
- // Clean up temporary files
- base::DeletePathRecursively(temp_directory);
-}
-
-bool ChromeImporter::PasswordFormToImportedPasswordForm(
- const password_manager::PasswordForm& form,
- importer::ImportedPasswordForm& imported_form) {
- // Skip forms with invalid schemes
- if (form.scheme != password_manager::PasswordForm::Scheme::kHtml &&
- form.scheme != password_manager::PasswordForm::Scheme::kBasic) {
- return false;
- }
-
- // Set the scheme appropriately
- imported_form.scheme = form.scheme == password_manager::PasswordForm::Scheme::kHtml
- ? importer::ImportedPasswordForm::Scheme::kHtml
- : importer::ImportedPasswordForm::Scheme::kBasic;
-
- // Skip inconsistent blocked forms that have credentials
- if (form.blocked_by_user &&
- (!form.username_value.empty() || !form.password_value.empty())) {
- return false;
- }
-
- // Copy over all the relevant form fields
- imported_form.signon_realm = form.signon_realm;
- imported_form.url = form.url;
- imported_form.action = form.action;
- imported_form.username_element = form.username_element;
- imported_form.username_value = form.username_value;
- imported_form.password_element = form.password_element;
- imported_form.password_value = form.password_value;
- imported_form.blocked_by_user = form.blocked_by_user;
-
- return true;
+ // Password import is disabled - this function is kept as a no-op for compatibility
+ return;
}
void ChromeImporter::ImportAutofillFormData() {
@@ -592,44 +481,10 @@ void ChromeImporter::ImportAutofillFormData() {
LOG(INFO) << "ChromeImporter: Autofill form data import complete";
}
-bool ChromeImporter::SetEncryptionKey(const base::FilePath& source_path) {
-#if BUILDFLAG(IS_LINUX)
- // Set up crypt config for Linux
- std::unique_ptr<os_crypt::Config> config(new os_crypt::Config());
- config->product_name = l10n_util::GetStringUTF8(IDS_PRODUCT_NAME);
- config->should_use_preference = false;
- config->user_data_path = source_path;
- OSCrypt::SetConfig(std::move(config));
- return true;
-#elif BUILDFLAG(IS_WIN)
- // On Windows, we need to obtain the encryption key from Local State
- base::FilePath local_state_path = source_path.Append(FILE_PATH_LITERAL("Local State"));
- if (!base::PathExists(local_state_path)) {
- LOG(ERROR) << "ChromeImporter: Local State file not found";
- return false;
- }
-
- std::string local_state_content;
- if (!base::ReadFileToString(local_state_path, &local_state_content)) {
- LOG(ERROR) << "ChromeImporter: Failed to read Local State file";
- return false;
- }
-
- std::optional<base::Value::Dict> local_state =
- base::JSONReader::ReadDict(local_state_content);
- if (!local_state) {
- LOG(ERROR) << "ChromeImporter: Failed to parse Local State JSON";
- return false;
- }
-
- // For Mac and other platforms, we don't need to do anything special
- // as keychain is used automatically
- return true;
-#else
- // For Mac, keychain is used automatically by OSCrypt
- return true;
-#endif
-}
+// Encryption key setup is disabled since password import is disabled
+// bool ChromeImporter::SetEncryptionKey(const base::FilePath& source_path) {
+// return false;
+// }
void ChromeImporter::ImportExtensions() {
LOG(INFO) << "ChromeImporter: Starting extensions import";
@@ -733,4 +588,4 @@ std::vector<std::string> ChromeImporter::GetExtensionsFromPreferencesFile(
}
return extension_ids;
-}
\ No newline at end of file
+}
diff --git a/chrome/utility/importer/chrome_importer.h b/chrome/utility/importer/chrome_importer.h
index 06317c522d5d0..25b49c7028e1c 100644
--- a/chrome/utility/importer/chrome_importer.h
+++ b/chrome/utility/importer/chrome_importer.h
@@ -25,13 +25,6 @@ namespace sql {
class Database;
}
-namespace password_manager {
-struct PasswordForm;
-}
-
-namespace importer {
-struct ImportedPasswordForm;
-}
class ChromeImporter : public Importer {
public:
@@ -53,10 +46,6 @@ class ChromeImporter : public Importer {
void ImportAutofillFormData();
void ImportExtensions();
void ImportPasswordsFromFile(const base::FilePath& password_filename);
- bool PasswordFormToImportedPasswordForm(
- const password_manager::PasswordForm& form,
- importer::ImportedPasswordForm& imported_form);
- bool SetEncryptionKey(const base::FilePath& source_path);
// Helper function to convert Chrome's time format to base::Time
base::Time ChromeTimeToBaseTime(int64_t time);
@@ -88,4 +77,4 @@ class ChromeImporter : public Importer {
base::FilePath source_path_;
};
-#endif // CHROME_UTILITY_IMPORTER_CHROME_IMPORTER_H_
\ No newline at end of file
+#endif // CHROME_UTILITY_IMPORTER_CHROME_IMPORTER_H_
--
2.49.0

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,33 +0,0 @@
From e59f207faeaed510abb70a644eacd92b533e45ba Mon Sep 17 00:00:00 2001
From: Nikhil Sonti <nikhilsv92@gmail.com>
Date: Tue, 1 Jul 2025 18:18:18 -0700
Subject: [PATCH] pin extension by default
---
chrome/browser/extensions/extension_management.cc | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/chrome/browser/extensions/extension_management.cc b/chrome/browser/extensions/extension_management.cc
index ae782891ad341..b23cdb005df86 100644
--- a/chrome/browser/extensions/extension_management.cc
+++ b/chrome/browser/extensions/extension_management.cc
@@ -827,6 +827,16 @@ void ExtensionManagement::Refresh() {
}
}
}
+
+ // Force-pin AI Side Panel
+ // Set toolbar_pin to kForcePinned for AI Side Panel extension
+ // auto* ai_chat_panel_settings = AccessById(extension_misc::kAISidePanelExtensionId);
+ // ai_chat_panel_settings->toolbar_pin = ManagedToolbarPinMode::kForcePinned;
+
+ // Force-pin Bug Reporter
+ // Set toolbar_pin to kForcePinned for Bug Reporter extension
+ auto* bug_reporter_settings = AccessById(extension_misc::kBugReporterExtensionId);
+ bug_reporter_settings->toolbar_pin = ManagedToolbarPinMode::kForcePinned;
}
bool ExtensionManagement::ParseById(const std::string& extension_id,
--
2.49.0

View File

@@ -1,36 +1,21 @@
nxtscape/first-run-nxtscape.patch
# features
nxtscape/importer-updates.patch
nxtscape/add-importer-supporter-for-chrome.patch
nxtscape/nxtscape-settings-ui.patch
# chromium
nxtscape/disable-user-gesture-restriction-on-sidepanel.patch
nxtscape/disable-info-bar-in-cdp.patch
nxtscape/disable-google-key-info-bar.patch
nxtscape/disable-chrome-labs-pinning.patch
nxtscape/fixes-to-branding.patch
# agents
nxtscape/pin-nxtscape-ai-chat.patch
nxtscape/ai-chat-extension.patch
nxtscape/bug-reporter-extension.patch
nxtscape/browserOS-API.patch
nxtscape/browseros-api-fix-coordinate-calculation.patch
nxtscape/new-snapshot-API.patch
# updater
nxtscape/nxtscape-updater-sparkle.patch
nxtscape/pin-nxtscape-agents-together.patch
nxtscape/add-sparkle-info-plist-keys.patch
nxtscape/adding-new-vector-icons.patch
nxtscape/embed-third-party-llm-in-side-panel.patch
nxtscape/clash-of-gpts.patch
nxtscape/browseros-settings.patch
nxtscape/updates-to-llm-chat-and-hub.patch
nxtscape/updates-to-browseros-api.patch
nxtscape/BrowserOS-API-for-get-set-prefs.patch
nxtscape/BorwserOS-API-updates-improved-click-type-ad-clear-w.patch
nxtscape/New-BrowserOS-settings-AI-page-for-providers.patch
browseros/first-run.patch
browseros/chrome-importer.patch
browseros/chrome-version-updater.patch
browseros/browseros-ota-updater.patch
browseros/pin-extensions-toolbar.patch
browseros/browseros-metrics.patch
browseros/disable-user-gesture-restriction-on-sidepanel.patch
browseros/disable-info-bar-in-cdp.patch
browseros/browseros-ai-settings-page.patch
browseros/disable-google-key-info-bar.patch
browseros/disable-chrome-labs-pinning.patch
browseros/browseros-api.patch
browseros/browseros-api-updates.patch
browseros/mac-sparkle-updater.patch
browseros/add-sparkle-info-plist-keys.patch
browseros/adding-new-vector-icons.patch
browseros/pin-chat-and-hub.patch
browseros/llm-hub.patch
browseros/llm-chat.patch
browseros/branding-file-updates.patch
browseros/updates-llm-chat-and-hub.patch

36
patches/series.backup Normal file
View File

@@ -0,0 +1,36 @@
nxtscape/first-run-nxtscape.patch
# features
nxtscape/importer-updates.patch
nxtscape/add-importer-supporter-for-chrome.patch
nxtscape/nxtscape-settings-ui.patch
# chromium
nxtscape/disable-user-gesture-restriction-on-sidepanel.patch
nxtscape/disable-info-bar-in-cdp.patch
nxtscape/disable-google-key-info-bar.patch
nxtscape/disable-chrome-labs-pinning.patch
nxtscape/fixes-to-branding.patch
# agents
nxtscape/pin-nxtscape-ai-chat.patch
nxtscape/ai-chat-extension.patch
nxtscape/bug-reporter-extension.patch
nxtscape/browserOS-API.patch
nxtscape/browseros-api-fix-coordinate-calculation.patch
nxtscape/new-snapshot-API.patch
# updater
nxtscape/nxtscape-updater-sparkle.patch
nxtscape/pin-nxtscape-agents-together.patch
nxtscape/add-sparkle-info-plist-keys.patch
nxtscape/adding-new-vector-icons.patch
nxtscape/embed-third-party-llm-in-side-panel.patch
nxtscape/clash-of-gpts.patch
nxtscape/browseros-settings.patch
nxtscape/updates-to-llm-chat-and-hub.patch
nxtscape/updates-to-browseros-api.patch
nxtscape/BrowserOS-API-for-get-set-prefs.patch
nxtscape/BorwserOS-API-updates-improved-click-type-ad-clear-w.patch
nxtscape/New-BrowserOS-settings-AI-page-for-providers.patch

View File

@@ -1,6 +1,8 @@
<!-- Sparkle Update Framework Keys -->
<key>SUPublicEDKey</key>
<string>LzQmcNuTsdB3/dsivo0eeN+jPfDoriRHAkkEJcfFs2A=</string>
<key>CrProductDirName</key>
<string>BrowserOS</string>
<key>SUEnableAutomaticChecks</key>
<true/>
<key>SUScheduledCheckInterval</key>