diff --git a/scripts/patch-linux-window-ui.test.js b/scripts/patch-linux-window-ui.test.js index d475e80ff..6d0f800c7 100644 --- a/scripts/patch-linux-window-ui.test.js +++ b/scripts/patch-linux-window-ui.test.js @@ -31,7 +31,6 @@ const { COMPUTER_USE_UI_ENV_VAR, COMPUTER_USE_UI_SETTINGS_KEY, applyLinuxComputerUseFeaturePatch, - applyLinuxComputerUseInstallFlowPatch, applyLinuxNativeDesktopAppsHandlerPatch, applyLinuxComputerUsePluginGatePatch, applyLinuxComputerUseRendererAvailabilityPatch, @@ -1032,23 +1031,6 @@ test("default core patch descriptors are grouped and unique", () => { descriptors.find((descriptor) => descriptor.id === "linux-computer-use-native-desktop-apps")?.ciPolicy, "opt-in", ); - const computerUseInstallFlow = descriptors.find((descriptor) => descriptor.id === "linux-computer-use-install-flow"); - assert.equal( - computerUseInstallFlow.pattern.test( - "app-initial~app-main~onboarding-page~hotkey-window-thread-page~quick-chat-window-page~chatg~gwqc41kz-current.js", - ), - true, - ); - for (const legacyName of [ - "app-initial~app-main~pull-request-code-review~onboarding-page~hotkey-window-thread-page~cha~b76hmflu-current.js", - "app-initial~app-main~remote-conversation-page~new-thread-panel-page~onboarding-page~appgen-~current.js", - "plugins-availability-current.js", - "use-plugin-install-flow-current.js", - "app-initial~app-main~remote-conversation-page~plugin-detail-page~new-thread-panel-page~current.js", - "app-initial~app-main~remote-conversation-page~pull-requests-page~plug~current.js", - ]) { - assert.equal(computerUseInstallFlow.pattern.test(legacyName), false, legacyName); - } assert.equal( descriptors.find((descriptor) => descriptor.id === "linux-terminal-user-path")?.ciPolicy, "optional", @@ -8687,13 +8669,54 @@ test("keeps object-helper Computer Use host compatibility on Linux when platform ); }); -test("Computer Use availability descriptor matches the current settings bundle name", () => { - const [descriptor] = require("./patches/core/all-linux/webview/computer-use-ui/patch.js"); +test("Computer Use availability descriptors independently match current settings and install-flow bundles", () => { + const [settingsDescriptor, installFlowDescriptor] = require( + "./patches/core/all-linux/webview/computer-use-ui/patch.js" + ); + + assert.match("computer-use-settings-B1QCeMSP.js", settingsDescriptor.pattern); + assert.doesNotMatch( + "app-initial~artifact-tab-content.electron~app-main~pull-request-route~pull-request-code-rev~jgoqfqy2-gdph-otp.js", + settingsDescriptor.pattern, + ); + assert.match( + "app-initial~artifact-tab-content.electron~app-main~pull-request-route~pull-request-code-rev~jgoqfqy2-gdph-otp.js", + installFlowDescriptor.pattern, + ); + assert.doesNotMatch("computer-use-settings-B1QCeMSP.js", installFlowDescriptor.pattern); + assert.doesNotMatch( + "app-initial~app-main~onboarding-page~hotkey-window-thread-page~quick-chat-window-page~chatg~gwqc41kz-current.js", + installFlowDescriptor.pattern, + ); + assert.doesNotMatch("use-model-settings-5PHNqYL4.js", settingsDescriptor.pattern); + assert.doesNotMatch("use-is-plugins-enabled-current.js", settingsDescriptor.pattern); + assert.doesNotMatch("use-native-apps.electron-DhuUEit1.js", settingsDescriptor.pattern); +}); + +test("Computer Use install-flow drift stays visible when the settings bundle still exists", () => { + const [, installFlowDescriptor] = require( + "./patches/core/all-linux/webview/computer-use-ui/patch.js" + ); + const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), "codex-computer-use-install-flow-drift-")); + try { + const assetsDir = path.join(tempRoot, "webview", "assets"); + fs.mkdirSync(assetsDir, { recursive: true }); + fs.writeFileSync(path.join(assetsDir, "computer-use-settings-current.js"), "settings"); + + const { value: result, warnings } = captureWarns(() => + patchAssetFiles( + tempRoot, + installFlowDescriptor.pattern, + installFlowDescriptor.apply, + installFlowDescriptor.missingDescription, + ), + ); - assert.match("computer-use-settings-B1QCeMSP.js", descriptor.pattern); - assert.doesNotMatch("use-model-settings-5PHNqYL4.js", descriptor.pattern); - assert.doesNotMatch("use-is-plugins-enabled-current.js", descriptor.pattern); - assert.doesNotMatch("use-native-apps.electron-DhuUEit1.js", descriptor.pattern); + assert.deepEqual(result, { matched: 0, changed: 0 }); + assert.deepEqual(warnings, [installFlowDescriptor.missingDescription]); + } finally { + fs.rmSync(tempRoot, { recursive: true, force: true }); + } }); test("keeps current Computer Use settings availability enabled on Linux", () => { @@ -8736,7 +8759,7 @@ test("warns without partially patching when Computer Use renderer availability g assert.equal(patched, source); assert.deepEqual(warnings, [ - "WARN: Could not find Computer Use renderer availability gate — skipping Linux Computer Use UI availability patch", + "WARN: Could not find Computer Use renderer availability gate — skipping Linux Computer Use renderer patch", ]); }); @@ -8796,20 +8819,6 @@ test("does not enable unrelated native desktop app queries on Linux", () => { assert.equal(applyLinuxComputerUseRendererAvailabilityPatch(source), source); }); -test("allows the current Computer Use platform while preserving upstream gates", () => { - const source = - "function Rj(e){return e===`macOS`||e===`windows`}" + - "function zj(e){let t=(0,Uj.c)(16),{enabled:n,hostId:r}=e,i=n===void 0?!0:n,{isLoading:a,platform:o}=Xt(),s=cn(`1506311413`),c;t[0]===r?c=t[1]:(c={featureName:`computer_use`,hostId:r},t[0]=r,t[1]=c);let l=Fj(c),u=o===`windows`&&!a,d=i&&u,f;t[2]===d?f=t[3]:(f={enabled:d},t[2]=d,t[3]=f);let p=Bj(f),m=l.isLoading||u&&p.isLoading,h=l.enabled&&(!u||p.enabled),g;t[4]!==h||t[5]!==i||t[6]!==m||t[7]!==s||t[8]!==a||t[9]!==o?(g=Hj({areRequiredFeaturesEnabled:h,enabled:i,isAnyFeatureLoading:m,isComputerUseGateEnabled:s,isHostCompatiblePlatform:Rj(o),isPlatformLoading:a,windowType:`electron`}),t[4]=h,t[5]=i,t[6]=m,t[7]=s,t[8]=a,t[9]=o,t[10]=g):g=t[10];return g}"; - - const patched = applyPatchTwice(applyLinuxComputerUseInstallFlowPatch, source); - - assert.match( - patched, - /g=Hj\(\{areRequiredFeaturesEnabled:h,enabled:i,isAnyFeatureLoading:m,isComputerUseGateEnabled:s,isHostCompatiblePlatform:o===`linux`\|\|Rj\(o\),isPlatformLoading:a,windowType:`electron`\}\)/, - ); - assert.doesNotMatch(patched, /areRequiredFeaturesEnabled:o===`linux`|isComputerUseGateEnabled:o===`linux`/); -}); - function externalOpenChildClosingWith(code) { const child = new EventEmitter(); child.unref = () => {}; @@ -9683,7 +9692,7 @@ test("patchExtractedApp scans current Computer Use settings bundles when UI is e fs.writeFileSync( path.join( assetsDir, - "app-initial~app-main~onboarding-page~hotkey-window-thread-page~quick-chat-window-page~chatg~gwqc41kz-current.js", + "app-initial~artifact-tab-content.electron~app-main~pull-request-route~pull-request-code-rev~jgoqfqy2-current.js", ), "function _p(e){return e===`macOS`||e===`windows`}" + "function vp(e){let t=(0,Sp.c)(16),{enabled:n,hostId:r}=e,i=n===void 0?!0:n,{isLoading:a,platform:o}=ba(),s=gr(`1506311413`),c;t[0]===r?c=t[1]:(c={featureName:`computer_use`,hostId:r},t[0]=r,t[1]=c);let l=mp(c),u=o===`windows`&&!a,d=i&&u,f;t[2]===d?f=t[3]:(f={enabled:d},t[2]=d,t[3]=f);let p=yp(f),m=l.isLoading||u&&p.isLoading,h=l.enabled&&(!u||p.enabled),g;t[4]!==h||t[5]!==i||t[6]!==m||t[7]!==s||t[8]!==a||t[9]!==o?(g=xp({areRequiredFeaturesEnabled:h,enabled:i,isAnyFeatureLoading:m,isComputerUseGateEnabled:s,isHostCompatiblePlatform:_p(o),isPlatformLoading:a,windowType:`electron`}),t[4]=h,t[5]=i,t[6]=m,t[7]=s,t[8]=a,t[9]=o,t[10]=g):g=t[10];return g}", @@ -9714,11 +9723,11 @@ test("patchExtractedApp scans current Computer Use settings bundles when UI is e fs.readFileSync( path.join( assetsDir, - "app-initial~app-main~onboarding-page~hotkey-window-thread-page~quick-chat-window-page~chatg~gwqc41kz-current.js", + "app-initial~artifact-tab-content.electron~app-main~pull-request-route~pull-request-code-rev~jgoqfqy2-current.js", ), "utf8", ), - /g=xp\(\{areRequiredFeaturesEnabled:h,enabled:i,isAnyFeatureLoading:m,isComputerUseGateEnabled:s,isHostCompatiblePlatform:o===`linux`\|\|_p\(o\),isPlatformLoading:a,windowType:`electron`\}\)/, + /g=xp\(\{areRequiredFeaturesEnabled:o===`linux`\|\|h,enabled:i,isAnyFeatureLoading:o===`linux`\?!1:m,isComputerUseGateEnabled:o===`linux`\|\|s,isHostCompatiblePlatform:o===`linux`\|\|_p\(o\),isPlatformLoading:a,windowType:`electron`\}\)/, ); } finally { fs.rmSync(tempRoot, { recursive: true, force: true }); diff --git a/scripts/patches/core/all-linux/webview/computer-use-ui/patch.js b/scripts/patches/core/all-linux/webview/computer-use-ui/patch.js index 220be9b3b..f1c1a885d 100644 --- a/scripts/patches/core/all-linux/webview/computer-use-ui/patch.js +++ b/scripts/patches/core/all-linux/webview/computer-use-ui/patch.js @@ -5,7 +5,6 @@ const { } = require("../../../../descriptor.js"); const { applyLinuxComputerUseRendererAvailabilityPatch, - applyLinuxComputerUseInstallFlowPatch, } = require("../../../../impl/computer-use.js"); module.exports = [ @@ -16,7 +15,7 @@ module.exports = [ ciPolicy: "opt-in", enabled: (context) => context.enableComputerUseUi, pattern: /^computer-use-settings.*\.js$/, - missingDescription: "Computer Use availability bundle", + missingDescription: "Computer Use settings bundle", skipDescription: "Linux Computer Use UI availability patch", apply: applyLinuxComputerUseRendererAvailabilityPatch, }), @@ -26,9 +25,10 @@ module.exports = [ order: 1110, ciPolicy: "opt-in", enabled: (context) => context.enableComputerUseUi, - pattern: /^app-initial~app-main~onboarding-page~hotkey-window-thread-page~quick-chat-window-page~chatg~[^.]+\.js$/, + pattern: + /^app-initial~artifact-tab-content\.electron~app-main~pull-request-route~pull-request-code-rev~.*\.js$/, missingDescription: "current Computer Use install flow bundle", skipDescription: "Linux Computer Use install flow patch", - apply: applyLinuxComputerUseInstallFlowPatch, + apply: applyLinuxComputerUseRendererAvailabilityPatch, }), ]; diff --git a/scripts/patches/impl/computer-use.js b/scripts/patches/impl/computer-use.js index 34c4ffa4b..9669b0dbf 100644 --- a/scripts/patches/impl/computer-use.js +++ b/scripts/patches/impl/computer-use.js @@ -593,7 +593,7 @@ function applyLinuxComputerUseRendererAvailabilityPatch(currentSource) { if (hasComputerUseAvailabilityGate() || availabilityGateFound) { console.warn( - "WARN: Could not find Computer Use renderer availability gate — skipping Linux Computer Use UI availability patch", + "WARN: Could not find Computer Use renderer availability gate — skipping Linux Computer Use renderer patch", ); return currentSource; } @@ -601,57 +601,6 @@ function applyLinuxComputerUseRendererAvailabilityPatch(currentSource) { return platformPredicateChanged ? patchedSource : currentSource; } -function applyLinuxComputerUseInstallFlowPatch(currentSource) { - const currentRequiredFeaturesObjectPattern = - /([A-Za-z_$][\w$]*)=([A-Za-z_$][\w$]*)\(\{areRequiredFeaturesEnabled:([A-Za-z_$][\w$]*),enabled:([A-Za-z_$][\w$]*),isAnyFeatureLoading:([A-Za-z_$][\w$]*),isComputerUseGateEnabled:([A-Za-z_$][\w$]*),isHostCompatiblePlatform:([A-Za-z_$][\w$]*)\(([A-Za-z_$][\w$]*)\),isPlatformLoading:([A-Za-z_$][\w$]*),windowType:`electron`\}\)/g; - - let changed = false; - let patchedSource = currentSource; - - patchedSource = patchedSource.replace( - currentRequiredFeaturesObjectPattern, - ( - match, - resultVar, - helperVar, - requiredFeaturesVar, - enabledVar, - featureLoadingVar, - rolloutVar, - platformPredicateVar, - platformVar, - platformLoadingVar, - offset, - ) => { - const contextStart = Math.max(0, offset - 1200); - const context = patchedSource.slice(contextStart, offset + match.length); - if (!context.includes("featureName:`computer_use`")) { - return match; - } - changed = true; - return `${resultVar}=${helperVar}({areRequiredFeaturesEnabled:${requiredFeaturesVar},enabled:${enabledVar},isAnyFeatureLoading:${featureLoadingVar},isComputerUseGateEnabled:${rolloutVar},isHostCompatiblePlatform:${platformVar}===\`linux\`||${platformPredicateVar}(${platformVar}),isPlatformLoading:${platformLoadingVar},windowType:\`electron\`})`; - }, - ); - - if (changed) { - return patchedSource; - } - - if ( - /featureName:`computer_use`[\s\S]{0,2200}?areRequiredFeaturesEnabled:[A-Za-z_$][\w$]*,enabled:[A-Za-z_$][\w$]*,isAnyFeatureLoading:[A-Za-z_$][\w$]*,isComputerUseGateEnabled:[A-Za-z_$][\w$]*,isHostCompatiblePlatform:([A-Za-z_$][\w$]*)===`linux`\|\|[A-Za-z_$][\w$]*\(\1\),isPlatformLoading:/.test(currentSource) - ) { - return currentSource; - } - - if (currentSource.includes("featureName:`computer_use`")) { - console.warn( - "WARN: Could not find Computer Use install flow gate — skipping Linux Computer Use install flow patch", - ); - } - - return currentSource; -} - function findHandlerValue(source, methodName) { const key = `${JSON.stringify(methodName)}:`; const keyIndex = source.indexOf(key); @@ -830,7 +779,6 @@ module.exports = { COMPUTER_USE_UI_ENV_VAR, COMPUTER_USE_UI_SETTINGS_KEY, applyLinuxComputerUseFeaturePatch, - applyLinuxComputerUseInstallFlowPatch, applyLinuxNativeDesktopAppsHandlerPatch, applyLinuxComputerUsePluginGatePatch, applyLinuxComputerUseRendererAvailabilityPatch, diff --git a/tests/scripts_smoke.sh b/tests/scripts_smoke.sh index 1ed743c8c..b74aecbd1 100755 --- a/tests/scripts_smoke.sh +++ b/tests/scripts_smoke.sh @@ -9301,7 +9301,7 @@ test_linux_computer_use_ui_opt_in_smoke() { local main_bundle="$extracted/.vite/build/main-test.js" local renderer_asset="$extracted/webview/assets/computer-use-settings-renderer-test.js" local current_renderer_asset="$extracted/webview/assets/computer-use-settings-current-test.js" - local install_flow_asset="$extracted/webview/assets/app-initial~app-main~onboarding-page~hotkey-window-thread-page~quick-chat-window-page~chatg~gwqc41kz-test.js" + local install_flow_asset="$extracted/webview/assets/app-initial~artifact-tab-content.electron~app-main~pull-request-route~pull-request-code-rev~jgoqfqy2-test.js" local native_apps_asset="$extracted/webview/assets/computer-use-settings-native-apps-test.js" local bundle_body local renderer_body @@ -9383,12 +9383,10 @@ JS assert_contains "$current_renderer_asset" 'areRequiredFeaturesEnabled:o===`linux`||y' assert_contains "$current_renderer_asset" 'isAnyFeatureLoading:o===`linux`?!1:g' assert_contains "$native_apps_asset" 'a===`macOS`||a===`windows`||a===`linux`' - assert_contains "$install_flow_asset" 'areRequiredFeaturesEnabled:h' - assert_contains "$install_flow_asset" 'isAnyFeatureLoading:m' - assert_contains "$install_flow_asset" 'isComputerUseGateEnabled:s' + assert_contains "$install_flow_asset" 'areRequiredFeaturesEnabled:o===`linux`||h' + assert_contains "$install_flow_asset" 'isAnyFeatureLoading:o===`linux`?!1:m' + assert_contains "$install_flow_asset" 'isComputerUseGateEnabled:o===`linux`||s' assert_contains "$install_flow_asset" 'isHostCompatiblePlatform:o===`linux`||Rj(o)' - assert_not_contains "$install_flow_asset" 'areRequiredFeaturesEnabled:o===`linux`||h' - assert_not_contains "$install_flow_asset" 'isComputerUseGateEnabled:o===`linux`||s' # Branch 3: settings.json flag opts in even without env var. rm "$main_bundle" "$renderer_asset" "$current_renderer_asset" "$install_flow_asset" "$native_apps_asset" @@ -9407,11 +9405,10 @@ JS assert_contains "$renderer_asset" 'function hae(e){return e===`macOS`||e===`windows`||e===`linux`}' assert_contains "$current_renderer_asset" 'areRequiredFeaturesEnabled:o===`linux`||y' assert_contains "$native_apps_asset" 'a===`macOS`||a===`windows`||a===`linux`' - assert_contains "$install_flow_asset" 'areRequiredFeaturesEnabled:h' - assert_contains "$install_flow_asset" 'isComputerUseGateEnabled:s' + assert_contains "$install_flow_asset" 'areRequiredFeaturesEnabled:o===`linux`||h' + assert_contains "$install_flow_asset" 'isAnyFeatureLoading:o===`linux`?!1:m' + assert_contains "$install_flow_asset" 'isComputerUseGateEnabled:o===`linux`||s' assert_contains "$install_flow_asset" 'isHostCompatiblePlatform:o===`linux`||Rj(o)' - assert_not_contains "$install_flow_asset" 'areRequiredFeaturesEnabled:o===`linux`||h' - assert_not_contains "$install_flow_asset" 'isComputerUseGateEnabled:o===`linux`||s' } test_linux_file_manager_patch_fails_soft() {