From 473d4901b2cbf1b2a33faf2819622fe56c160036 Mon Sep 17 00:00:00 2001 From: vp275 <41702642+vp275@users.noreply.github.com> Date: Sat, 4 Jul 2026 21:33:22 +0530 Subject: [PATCH 1/2] fix: match Helium with chrome web watcher bucket --- src/queries.ts | 3 ++- test/unit/queries.test.node.ts | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/queries.ts b/src/queries.ts index 406a3431..fa364c3a 100644 --- a/src/queries.ts +++ b/src/queries.ts @@ -263,7 +263,8 @@ function browsersWithBuckets(browserbuckets: string[]): [string, string][] { // The full set of historical app names these patterns replace is documented in the unit tests. // See: test/unit/queries.test.node.ts, https://github.com/ActivityWatch/aw-webui/issues/749 export const browser_appname_regex: Record = { - chrome: '(?i)^(google[-_ ]?chrome|chrome|chromium)', + // Helium can use the Chrome Web Store extension, which emits aw-watcher-web-chrome buckets. + chrome: '(?i)^(google[-_ ]?chrome|chrome|chromium|helium)', firefox: '(?i)(firefox|librewolf|waterfox|nightly)', opera: '(?i)(opera)', brave: '(?i)(brave)', diff --git a/test/unit/queries.test.node.ts b/test/unit/queries.test.node.ts index 19dab25f..a11b945d 100644 --- a/test/unit/queries.test.node.ts +++ b/test/unit/queries.test.node.ts @@ -11,7 +11,7 @@ * Chrome: 'Google Chrome', 'Google-chrome', 'Chrome.exe', 'chrome.exe', * 'google-chrome-stable', 'Chromium', 'Chromium-browser', 'chromium-browser', * 'Chromium-browser-chromium', 'Chromium.exe', 'chromium.exe', - * 'Google-chrome-beta', 'Google-chrome-unstable' + * 'Google-chrome-beta', 'Google-chrome-unstable', 'Helium' * (Flatpak app IDs retained as exact: 'com.google.Chrome', 'com.google.ChromeDev', * 'org.chromium.Chromium') * @@ -81,6 +81,7 @@ describe('browser_appname_regex', () => { 'chromium.exe', 'Google-chrome-beta', 'Google-chrome-unstable', + 'Helium', ]; for (const name of knownNames) { expect(re.test(name)).toBe(true); From fb746412f2ce38688c4850b98fbe00b93fda8c5f Mon Sep 17 00:00:00 2001 From: vp275 <41702642+vp275@users.noreply.github.com> Date: Sat, 4 Jul 2026 21:47:51 +0530 Subject: [PATCH 2/2] fix: avoid double-counting Helium buckets --- src/queries.ts | 29 ++++++++++++++++++++---- test/unit/queries.test.node.ts | 40 +++++++++++++++++++++++++++++++--- 2 files changed, 62 insertions(+), 7 deletions(-) diff --git a/src/queries.ts b/src/queries.ts index fa364c3a..f95c780e 100644 --- a/src/queries.ts +++ b/src/queries.ts @@ -245,11 +245,21 @@ const browser_appnames: Record = { }; // Returns a list of (browserName, bucketId) pairs for found browser buckets +function browserBucketMatches(bucketId: string, browserName: string): boolean { + return _.includes(bucketId, browserName); +} + +function browserBucketExists(browserbuckets: string[], browserName: string): boolean { + return _.some(browserbuckets, bucket_id => browserBucketMatches(bucket_id, browserName)); +} + function browsersWithBuckets(browserbuckets: string[]): [string, string][] { const browsername_to_bucketid: [string, string | undefined][] = _.map( Object.keys(browser_appnames), browserName => { - const bucketId = _.find(browserbuckets, bucket_id => _.includes(bucket_id, browserName)); + const bucketId = _.find(browserbuckets, bucket_id => + browserBucketMatches(bucket_id, browserName) + ); return [browserName, bucketId]; } ); @@ -262,9 +272,11 @@ function browsersWithBuckets(browserbuckets: string[]): [string, string][] { // Used with filter_keyvals_regex in addition to the exact names in browser_appnames. // The full set of historical app names these patterns replace is documented in the unit tests. // See: test/unit/queries.test.node.ts, https://github.com/ActivityWatch/aw-webui/issues/749 +const chrome_appname_regex = '(?i)^(google[-_ ]?chrome|chrome|chromium)'; +const chrome_appname_regex_with_helium = '(?i)^(google[-_ ]?chrome|chrome|chromium|helium)'; + export const browser_appname_regex: Record = { - // Helium can use the Chrome Web Store extension, which emits aw-watcher-web-chrome buckets. - chrome: '(?i)^(google[-_ ]?chrome|chrome|chromium|helium)', + chrome: chrome_appname_regex, firefox: '(?i)(firefox|librewolf|waterfox|nightly)', opera: '(?i)(opera)', brave: '(?i)(brave)', @@ -278,6 +290,15 @@ export const browser_appname_regex: Record = { helium: '(?i)(helium)', }; +function browserAppnameRegex(browserName: string, browserbuckets: string[]): string | undefined { + // Helium can use the Chrome Web Store extension, which emits aw-watcher-web-chrome buckets. + // Only match Helium there when no dedicated Helium bucket exists, to avoid double-counting. + if (browserName === 'chrome' && !browserBucketExists(browserbuckets, 'helium')) { + return chrome_appname_regex_with_helium; + } + return browser_appname_regex[browserName]; +} + // Returns a list of active browser events (where the browser was the active window) from all browser buckets function browserEvents(params: DesktopQueryParams): string { let code = ` @@ -290,7 +311,7 @@ function browserEvents(params: DesktopQueryParams): string { window_${browserName} = filter_keyvals(events, "app", ${browser_appnames_str});`; // Add regex-based matching to cover case/spacing/versioning variants (e.g., Firefox.exe, firefox-esr-esr140) - const pattern = browser_appname_regex[browserName]; + const pattern = browserAppnameRegex(browserName, params.bid_browsers); if (pattern) { code += ` window_${browserName}_re = filter_keyvals_regex(events, "app", ${JSON.stringify(pattern)}); diff --git a/test/unit/queries.test.node.ts b/test/unit/queries.test.node.ts index a11b945d..722aca7c 100644 --- a/test/unit/queries.test.node.ts +++ b/test/unit/queries.test.node.ts @@ -11,7 +11,7 @@ * Chrome: 'Google Chrome', 'Google-chrome', 'Chrome.exe', 'chrome.exe', * 'google-chrome-stable', 'Chromium', 'Chromium-browser', 'chromium-browser', * 'Chromium-browser-chromium', 'Chromium.exe', 'chromium.exe', - * 'Google-chrome-beta', 'Google-chrome-unstable', 'Helium' + * 'Google-chrome-beta', 'Google-chrome-unstable' * (Flatpak app IDs retained as exact: 'com.google.Chrome', 'com.google.ChromeDev', * 'org.chromium.Chromium') * @@ -53,7 +53,7 @@ * (Flatpak app ID retained: 'one.ablaze.floorp') */ -import { browser_appname_regex } from '~/queries'; +import { browser_appname_regex, fullDesktopQuery } from '~/queries'; // Convert ActivityWatch (?i) patterns to JS RegExp with i flag for testing. // AW server uses Python-style (?i) inline flag; JS uses RegExp 'i' flag instead. @@ -62,6 +62,18 @@ function toRegex(pattern: string): RegExp { return new RegExp(stripped, 'i'); } +function browserQueryForBuckets(bid_browsers: string[]): string { + return fullDesktopQuery({ + bid_window: 'aw-watcher-window_testhost', + bid_afk: 'aw-watcher-afk_testhost', + bid_browsers, + filter_afk: true, + categories: [], + filter_categories: [], + include_audible: false, + }).join('\n'); +} + describe('browser_appname_regex', () => { test('chrome pattern matches all known Chrome/Chromium app names', () => { const re = toRegex(browser_appname_regex.chrome); @@ -81,7 +93,6 @@ describe('browser_appname_regex', () => { 'chromium.exe', 'Google-chrome-beta', 'Google-chrome-unstable', - 'Helium', ]; for (const name of knownNames) { expect(re.test(name)).toBe(true); @@ -96,6 +107,29 @@ describe('browser_appname_regex', () => { expect(re.test('Electron')).toBe(false); }); + test('chrome web watcher bucket matches Helium when there is no Helium bucket', () => { + const query = browserQueryForBuckets(['aw-watcher-web-chrome_testhost']); + expect(query).toContain( + 'window_chrome_re = filter_keyvals_regex(events, "app", "(?i)^(google[-_ ]?chrome|chrome|chromium|helium)")' + ); + }); + + test('chrome web watcher bucket does not match Helium when a Helium bucket exists', () => { + const query = browserQueryForBuckets([ + 'aw-watcher-web-chrome_testhost', + 'aw-watcher-web-helium_testhost', + ]); + expect(query).toContain( + 'window_chrome_re = filter_keyvals_regex(events, "app", "(?i)^(google[-_ ]?chrome|chrome|chromium)")' + ); + expect(query).toContain( + 'window_helium_re = filter_keyvals_regex(events, "app", "(?i)(helium)")' + ); + expect(query).not.toContain( + 'window_chrome_re = filter_keyvals_regex(events, "app", "(?i)^(google[-_ ]?chrome|chrome|chromium|helium)")' + ); + }); + test('firefox pattern matches all known Firefox/LibreWolf/Waterfox app names', () => { const re = toRegex(browser_appname_regex.firefox); // Every entry from the old exact-match list