From a481ed0eef2bb457c4fbbb4d72ad86df4ece6e8f Mon Sep 17 00:00:00 2001 From: Bartosz Tomczyk Date: Mon, 5 Oct 2026 16:30:50 +0200 Subject: [PATCH 1/2] fix(options): do not save prefix-only mode when inline suggestions turn on The options page wrote prefixOnlyMode=true when inline suggestions were on. ConfigAssembler already forces prefix-only mode while inline suggestions are on, so this write was not necessary. After the user turned inline suggestions off, the saved value kept prefix-only mode on, and predictions that use the text after the caret returned nothing. Now the page shows the checkbox as on without a write, and shows the user's value again when inline suggestions turn off. Co-Authored-By: Claude Opus 5.5 --- src/ui/options/settings.ts | 14 +++++++++++++- tests/options.page.test.ts | 20 ++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/ui/options/settings.ts b/src/ui/options/settings.ts index 58568ad11..617829950 100644 --- a/src/ui/options/settings.ts +++ b/src/ui/options/settings.ts @@ -154,17 +154,29 @@ function wireImportExportHandlers(registry: SettingsRegistry): void { }); } +// The stored prefix-only value of each control while inline mode shows it as on. +const prefixOnlyBeforeInline = new WeakMap(); + function applyInlineSuggestionLocks(registry: SettingsRegistry, enabled: boolean): void { + const prefixOnly = registry[KEY_PREFIX_ONLY_MODE]; if (enabled) { const locks: Array<[string, unknown]> = [ [KEY_AUTOCOMPLETE_ON_TAB, true], [KEY_NUM_SUGGESTIONS, 10], - [KEY_PREFIX_ONLY_MODE, true], ]; for (const [key, value] of locks) { // A select control gives its value as a string. if (String(registry[key].get()) !== String(value)) registry[key].set(value); } + // ConfigAssembler forces prefix-only mode while inline mode is on. Thus show it without a write, + // so that the user's value comes back when inline mode goes off. + if (prefixOnly.get() !== true) { + prefixOnlyBeforeInline.set(prefixOnly, prefixOnly.get()); + prefixOnly.set(true, true); + } + } else if (prefixOnlyBeforeInline.has(prefixOnly)) { + prefixOnly.set(prefixOnlyBeforeInline.get(prefixOnly), true); + prefixOnlyBeforeInline.delete(prefixOnly); } registry[KEY_AUTOCOMPLETE_ON_TAB].setDisabled(enabled); registry[KEY_PREFIX_ONLY_MODE].setDisabled(enabled); diff --git a/tests/options.page.test.ts b/tests/options.page.test.ts index a353ba8f4..33a9ad794 100644 --- a/tests/options.page.test.ts +++ b/tests/options.page.test.ts @@ -197,6 +197,26 @@ describe("options page settings handlers", () => { expect(writes).toEqual([...expected]); }, ); + + test("inline mode shows prefix-only mode as on but keeps the stored value", () => { + stubConfigChangeSender(); + const registry = fakeRegistry({ + [KEY_INLINE_SUGGESTION]: false, + [KEY_AUTOCOMPLETE_ON_TAB]: true, + [KEY_NUM_SUGGESTIONS]: "10", + [KEY_PREFIX_ONLY_MODE]: false, + }); + wireRuntimeSettingsHandlers(registry); + const prefixOnly = registry[KEY_PREFIX_ONLY_MODE]; + + registry[KEY_INLINE_SUGGESTION].set(true); + expect(prefixOnly.get()).toBe(true); + + registry[KEY_INLINE_SUGGESTION].set(false); + expect(prefixOnly.get()).toBe(false); + // ConfigAssembler forces prefix-only mode while inline mode is on, so no write is needed. + expect(prefixOnly.calls.every((call) => call.silent)).toBe(true); + }); }); async function flushPage(rounds = 30): Promise { From c3a1b7a388ae03397444c2189cf96f474ffe7fea Mon Sep 17 00:00:00 2001 From: Bartosz Tomczyk Date: Mon, 5 Oct 2026 16:40:27 +0200 Subject: [PATCH 2/2] test(e2e): retry the background worker probe after a first timeout getBackgroundContext waits 1000 ms for the Chrome service worker. If the worker starts slowly, Puppeteer throws "Timed out after waiting 1000ms". isRetriableBackgroundContextError did not match this message, so the wake-and-retry path did not run and the suite failed in beforeAll (local-ai.e2e, E2E Full chrome 1/2 on PR #475). Co-Authored-By: Claude Opus 5.5 --- tests/e2e/e2e-helpers.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/e2e/e2e-helpers.ts b/tests/e2e/e2e-helpers.ts index 0d7091c80..23c1ac75b 100644 --- a/tests/e2e/e2e-helpers.ts +++ b/tests/e2e/e2e-helpers.ts @@ -129,7 +129,7 @@ function cacheChromeExtensionHost(candidate: string | null | undefined): void { function isRetriableBackgroundContextError(error: unknown): boolean { const message = error instanceof Error ? error.message : String(error); - return /Execution context was destroyed|Execution context is not available in detached frame or worker|Cannot find context with specified id|Session closed|Target closed|Connection closed|background worker is unavailable|Waiting failed|NoSuchFrameError|Browsing Context with id .* not found/i.test( + return /Execution context was destroyed|Execution context is not available in detached frame or worker|Cannot find context with specified id|Session closed|Target closed|Connection closed|background worker is unavailable|Waiting failed|Timed out after waiting \d+ms|NoSuchFrameError|Browsing Context with id .* not found/i.test( message, ); }