diff --git a/scripts/canary.mjs b/scripts/canary.mjs index 855ca19..0c1febd 100644 --- a/scripts/canary.mjs +++ b/scripts/canary.mjs @@ -165,7 +165,7 @@ function codePathsForFailure(name, phase) { ]; } - if (name.includes("open-target") || name.includes("window")) { + if (name.includes("window")) { return ["scripts/lib/upstream-patches.mjs", "test/upstream-patches.test.mjs"]; } diff --git a/scripts/lib/upstream-patches.mjs b/scripts/lib/upstream-patches.mjs index edb30d7..9c33073 100644 --- a/scripts/lib/upstream-patches.mjs +++ b/scripts/lib/upstream-patches.mjs @@ -4,22 +4,6 @@ import { parse } from "acorn"; import { linuxChromeExtensionHostContentVariantContract } from "./chrome-extension-patches.mjs"; -const linuxOpenTargetDefinitions = ({ openCommandName, executableResolverName }) => [ - "var __codexLinuxOpenTargetGotoArgs=(e,t)=>t?[`--goto`,`${e}:${t.line}:${t.column}`]:[e]", - "__codexLinuxOpenTargetColonArgs=(e,t)=>t?[`${e}:${t.line}:${t.column}`]:[e]", - `__codexLinuxOpenTargetTerminal=()=>{let e=process.env.TERMINAL?.trim();if(e&&${executableResolverName}(e))return{command:${executableResolverName}(e),args:e=>[\`-e\`,process.env.SHELL?.trim()||\`/bin/sh\`,\`-lc\`,e]};for(let e of [[\`ghostty\`,e=>[\`-e\`,process.env.SHELL?.trim()||\`/bin/sh\`,\`-lc\`,e]],[\`kitty\`,e=>[\`-e\`,process.env.SHELL?.trim()||\`/bin/sh\`,\`-lc\`,e]],[\`alacritty\`,e=>[\`-e\`,process.env.SHELL?.trim()||\`/bin/sh\`,\`-lc\`,e]],[\`wezterm\`,e=>[\`start\`,\`--\`,process.env.SHELL?.trim()||\`/bin/sh\`,\`-lc\`,e]],[\`gnome-terminal\`,e=>[\`--\`,process.env.SHELL?.trim()||\`/bin/sh\`,\`-lc\`,e]],[\`konsole\`,e=>[\`-e\`,process.env.SHELL?.trim()||\`/bin/sh\`,\`-lc\`,e]],[\`xterm\`,e=>[\`-e\`,process.env.SHELL?.trim()||\`/bin/sh\`,\`-lc\`,e]]]){let t=${executableResolverName}(e[0]);if(t)return{command:t,args:e[1]}}return null}`, - "__codexLinuxOpenTargetNvimArgs=(e,t)=>t?[`+call cursor(${t.line},${t.column})`,e]:[e]", - "__codexLinuxShellQuote=e=>{e=String(e);return e.length===0?`''`:/^[A-Za-z0-9_/:=.-]+$/.test(e)?e:`'${e.replaceAll(`'`,`'\\\\''`)}'`}", - "__codexLinuxOpenTargetNvimCommand=(e,n,r)=>[e,...__codexLinuxOpenTargetNvimArgs(n,r)].map(__codexLinuxShellQuote).join(` `)", - `__codexLinuxOpenTargetRunNvim=async({command:e,path:t,location:n})=>{let r=__codexLinuxOpenTargetTerminal();if(!r)throw Error(\`No terminal emulator found for Neovim\`);await ${openCommandName}(r.command,r.args(__codexLinuxOpenTargetNvimCommand(e,t,n)))}`, - `__codexLinuxVSCode={id:\`vscode\`,platforms:{linux:{label:\`VS Code\`,icon:\`apps/vscode.png\`,kind:\`editor\`,detect:()=>${executableResolverName}(\`code\`),args:__codexLinuxOpenTargetGotoArgs}}}`, - `__codexLinuxVSCodeInsiders={id:\`vscodeInsiders\`,platforms:{linux:{label:\`VS Code Insiders\`,icon:\`apps/vscode-insiders.png\`,kind:\`editor\`,detect:()=>${executableResolverName}(\`code-insiders\`),args:__codexLinuxOpenTargetGotoArgs}}}`, - `__codexLinuxCursor={id:\`cursor\`,platforms:{linux:{label:\`Cursor\`,icon:\`apps/cursor.png\`,kind:\`editor\`,detect:()=>${executableResolverName}(\`cursor\`),args:__codexLinuxOpenTargetGotoArgs}}}`, - `__codexLinuxZed={id:\`zed\`,platforms:{linux:{label:\`Zed\`,icon:\`apps/zed.png\`,kind:\`editor\`,detect:()=>${executableResolverName}(\`zed\`),args:__codexLinuxOpenTargetColonArgs}}}`, - `__codexLinuxNvim={id:\`nvim\`,platforms:{linux:{label:\`Neovim\`,icon:\`apps/terminal.png\`,kind:\`editor\`,detect:()=>${executableResolverName}(\`nvim\`),args:__codexLinuxOpenTargetNvimArgs,open:__codexLinuxOpenTargetRunNvim}}}` -].join(","); -const openTargetMapRegex = - /targets:\[\.\.\.([A-Za-z_$][\w$]*)\.map\(\(\{id:([A-Za-z_$][\w$]*),label:([A-Za-z_$][\w$]*),icon:([A-Za-z_$][\w$]*),kind:([A-Za-z_$][\w$]*),hidden:([A-Za-z_$][\w$]*)\}\)=>\(\{id:\2,target:\2,label:\3,icon:\4,kind:\5,hidden:\6,available:([A-Za-z_$][\w$]*)\.has\(\2\),default:([A-Za-z_$][\w$]*)===\2\|\|void 0\}\)\),\.\.\.([A-Za-z_$][\w$]*)\]/; const linuxTransparencyPatchedRegex = /transparent:[A-Za-z_$][\w$]*===`linux`\?!1:[A-Za-z_$][\w$]*,hasShadow:/; const linuxTransparencyPatchRegex = @@ -50,17 +34,6 @@ export const linuxChromeExtensionDetectionContract = { assertAfter: assertLinuxChromeExtensionDetectionAfter }; export const upstreamPatchContracts = [ - // Why: upstream desktop only registers macOS open-in-editor targets; Linux - // needs locally installed editors and terminal-backed Neovim. Contract: - // upstream still exposes an open-target registry, runner, and preferred-target - // mapper. Repro: node scripts/canary.mjs --channel prod --no-smoke. - { - name: "open-target-dispatcher", - find: findOpenTargetRegistry, - assertBefore: assertOpenTargetsBefore, - apply: applyLinuxOpenTargetsSource, - assertAfter: assertOpenTargetsAfter - }, // Why: transparent frameless windows render poorly under Linux compositors. // Contract: the main bundle still builds BrowserWindow background options // from the parsed window-options object. Repro: node scripts/canary.mjs --channel prod --no-smoke. @@ -139,20 +112,16 @@ export function patchUpstreamMainSource(source) { return applyUpstreamPatchContracts(source, upstreamPatchContracts); } -export function patchLinuxOpenTargetsSource(source) { - return applyUpstreamPatchContract(source, upstreamPatchContracts[0]); -} - export function patchLinuxChromeExtensionDetectionSource(source) { return applyUpstreamPatchContract(source, linuxChromeExtensionDetectionContract); } export function patchDisableTransparencySource(source) { - return applyUpstreamPatchContracts(source, upstreamPatchContracts.slice(1, 3)); + return applyUpstreamPatchContracts(source, upstreamPatchContracts.slice(0, 2)); } export function patchLinuxWindowFocusableSource(source) { - return applyUpstreamPatchContract(source, upstreamPatchContracts[3]); + return applyUpstreamPatchContract(source, upstreamPatchContracts[2]); } export function patchLinuxOwlFeatureBindingSource(source) { @@ -246,25 +215,6 @@ export function applyUpstreamPatchContract(source, contract) { } } -function applyLinuxOpenTargetsSource(source) { - let patched = source; - - if (!patched.includes("__codexLinuxVSCode=")) { - const openTargets = findOpenTargetRegistry(patched); - patched = replaceOnce( - patched, - openTargets.anchor, - `${linuxOpenTargetDefinitions(openTargets)};${openTargets.anchor.replace("[", "[__codexLinuxVSCode,__codexLinuxVSCodeInsiders,__codexLinuxCursor,__codexLinuxZed,__codexLinuxNvim,")}` - ); - } - - patched = patchOpenTargetMap(patched); - - patched = patchOpenTargetPlatformLookup(patched); - - return patched; -} - async function patchOwlFeatureBindingChunks(buildDir, entries) { for (const entry of entries) { if (!entry.endsWith(".js")) { @@ -376,29 +326,6 @@ function patchOwlFeatureBinding(source, patch = findOwlFeatureBindingPatch(sourc return replaceOnce(source, patch.anchor, replacement); } -function assertOpenTargetsBefore(source) { - findOpenTargetRegistry(source); - findOpenCommandName(source); - - if (!source.includes("appPath:process.platform===`linux`") && !openTargetMapRegex.test(source)) { - throw new Error("missing open target map"); - } -} - -function assertOpenTargetsAfter(source) { - if (!source.includes("__codexLinuxVSCode=")) { - throw new Error("missing Linux open target definitions"); - } - - if (!source.includes("appPath:process.platform===`linux`")) { - throw new Error("missing Linux appPath target metadata"); - } - - if (source.includes("let n=t.platforms[e];return n")) { - throw new Error("open target platform lookup is not null-safe"); - } -} - function patchLinuxWindowBackground(source) { const patch = findLinuxWindowBackgroundPatch(source); @@ -1162,137 +1089,6 @@ function assertLinuxWindowTransparencyAfter(source) { } } -function patchOpenTargetMap(source) { - if (source.includes("appPath:process.platform===`linux`")) { - return source; - } - - const match = source.match(openTargetMapRegex); - - if (!match) { - throw new Error("Unable to apply upstream patch; missing open target map"); - } - - const [ - anchor, - targetsVar, - idVar, - labelVar, - iconVar, - kindVar, - hiddenVar, - availableSetVar, - defaultTargetVar, - extraTargetsVar - ] = match; - - const patchedMap = - `targets:[...${targetsVar}.map(({id:${idVar},label:${labelVar},icon:${iconVar},kind:${kindVar},hidden:${hiddenVar}})=>({` + - `id:${idVar},target:${idVar},label:${labelVar},icon:${iconVar},kind:${kindVar},hidden:${hiddenVar},` + - `appPath:process.platform===\`linux\`&&${kindVar}===\`editor\`&&${availableSetVar}.has(${idVar})?Ld().get(${idVar})??null:null,` + - `available:${availableSetVar}.has(${idVar}),default:${defaultTargetVar}===${idVar}||void 0})),...${extraTargetsVar}]`; - - return replaceOnce(source, anchor, patchedMap); -} - -function patchOpenTargetPlatformLookup(source) { - return source.replaceAll( - "let n=t.platforms[e];return n", - "let n=t.platforms?.[e];return n" - ); -} - -function findOpenTargetRegistry(source) { - const match = source.match( - /var ([A-Za-z_$][\w$]*)=\[[^\]]+\](?:,[A-Za-z_$][\w$]*=[A-Za-z_$][\w$]*\.[A-Za-z_$][\w$]*\(`open-in-targets`\)|\s*;[A-Za-z_$][\w$]*\.[A-Za-z_$][\w$]*\(`open-in-targets`\));\s*function [A-Za-z_$][\w$]*\(e\)\{return \1\.flatMap/ - ); - - if (!match) { - throw new Error("Unable to apply upstream patch; missing open target registry"); - } - - const anchor = source.slice(match.index, source.indexOf("]", match.index) + 1); - - return { - anchor, - openCommandName: findOpenCommandName(source), - executableResolverName: findOpenExecutableResolverName(source) - }; -} - -function findOpenExecutableResolverName(source) { - const resolverMatch = source.match( - /function ([A-Za-z_$][\w$]*)\(e\)\{let [A-Za-z_$][\w$]*=[A-Za-z_$][\w$]*\.default\.sync\(e,\{nothrow:!0\}\);return typeof [A-Za-z_$][\w$]*==`string`&&/ - ); - - if (resolverMatch) { - return resolverMatch[1]; - } - - const targetDetectMatch = source.match( - /([A-Za-z_$][\w$]*)\(`(?:code|code-insiders|cursor|zed|nvim)`\)/ - ); - - if (targetDetectMatch) { - return targetDetectMatch[1]; - } - - throw new Error("Unable to apply upstream patch; missing open target executable resolver"); -} - -function findOpenCommandName(source) { - const openDispatcherName = findOpenCommandNameFromDispatcher(source); - - if (openDispatcherName) { - return openDispatcherName; - } - - const match = source.match( - /await ([A-Za-z_$][\w$]*)\([A-Za-z_$][\w$]*,[A-Za-z_$][\w$]*\.args\([^)]*\),\{env:[A-Za-z_$][\w$]*\.env\?\.\(\)\}\)/ - ); - - if (!match) { - throw new Error("Unable to apply upstream patch; missing open command runner"); - } - - return match[1]; -} - -function findOpenCommandNameFromDispatcher(source) { - const ast = parseJavaScript(source); - const names = new Set(); - - walkAst(ast, node => { - if (!isFunctionNode(node)) { - return; - } - - const body = source.slice(node.start, node.end); - - if ( - !body.includes("Unknown open target") || - !body.includes("Open target") || - !body.includes(".args(") - ) { - return; - } - - const match = body.match( - /await ([A-Za-z_$][\w$]*)\([A-Za-z_$][\w$]*,[A-Za-z_$][\w$]*\.args\([^)]*\)(?:,\{env:[A-Za-z_$][\w$]*\.env\?\.\(\)\})?\)/ - ); - - if (match) { - names.add(match[1]); - } - }); - - if (names.size > 1) { - throw new Error("Unable to apply upstream patch; ambiguous open command runner"); - } - - return names.values().next().value ?? null; -} - function replaceOnce(source, search, replacement) { const index = source.indexOf(search); diff --git a/test/canary-issue.test.mjs b/test/canary-issue.test.mjs index 4b31d4c..e82206c 100644 --- a/test/canary-issue.test.mjs +++ b/test/canary-issue.test.mjs @@ -11,12 +11,12 @@ import { const failure = { channel: "prod", phase: "build", - failingName: "open-target-dispatcher", + failingName: "linux-window-background", upstreamVersion: "26.616.30709", upstreamBuildNumber: "30709", packageVersion: "26.616.30709-launcher.29", - fingerprint: "prod:open-target-dispatcher:26.616.30709:30709", - errorMessage: "open-target-dispatcher contract changed: missing runner", + fingerprint: "prod:linux-window-background:26.616.30709:30709", + errorMessage: "linux-window-background contract changed: missing window background helper", localReproductionCommand: "node scripts/canary.mjs --channel prod --json-output dist/upstream-canary-prod.json", codePaths: ["scripts/lib/upstream-patches.mjs"], publishBlockedBeforeMutation: true @@ -25,7 +25,7 @@ const failure = { test("canary issue title uses stable dedupe fields", () => { assert.equal( issueTitleForFailure(failure), - "Upstream canary failed: prod open-target-dispatcher 26.616.30709" + "Upstream canary failed: prod linux-window-background 26.616.30709" ); }); @@ -42,9 +42,9 @@ test("canary issue body includes actionable repair evidence", () => { assert.match(body, /Channel \| prod/); assert.match(body, /Upstream build \| 30709/); assert.match(body, /Package version \| 26\.616\.30709-launcher\.29/); - assert.match(body, /Contract\/smoke \| open-target-dispatcher/); + assert.match(body, /Contract\/smoke \| linux-window-background/); assert.match(body, /Publish blocked before mutation \| yes/); - assert.match(body, /missing runner/); + assert.match(body, /missing window background helper/); assert.match(body, /stack line/); assert.match(body, /node scripts\/canary\.mjs --channel prod/); assert.match(body, /scripts\/lib\/upstream-patches\.mjs/); diff --git a/test/canary-reporter.test.mjs b/test/canary-reporter.test.mjs index f00234a..54506d0 100644 --- a/test/canary-reporter.test.mjs +++ b/test/canary-reporter.test.mjs @@ -22,12 +22,12 @@ test("report-canary-failure creates exactly one actionable GitHub issue", async { channel: "prod", phase: "build", - failingName: "open-target-dispatcher", + failingName: "linux-window-background", upstreamVersion: "26.616.30709", upstreamBuildNumber: "4108", packageVersion: "26.616.30709-launcher.29", - fingerprint: "prod:open-target-dispatcher:26.616.30709:4108", - errorMessage: "open-target-dispatcher contract changed: missing runner", + fingerprint: "prod:linux-window-background:26.616.30709:4108", + errorMessage: "linux-window-background contract changed: missing window background helper", localReproductionCommand: "node scripts/canary.mjs --channel prod", codePaths: ["scripts/lib/upstream-patches.mjs"], publishBlockedBeforeMutation: true @@ -64,7 +64,7 @@ test("report-canary-failure creates exactly one actionable GitHub issue", async assert.equal(issueMutations.length, 1); assert.equal(issueMutations[0][1], "create"); - assert.match(issueMutations[0].join(" "), /Upstream canary failed: prod open-target-dispatcher 26\.616\.30709/); + assert.match(issueMutations[0].join(" "), /Upstream canary failed: prod linux-window-background 26\.616\.30709/); const body = await readBodyFileFromArgs(issueMutations[0]); assert.match(body, /Workflow run \| https:\/\/github\.com\/better-slop\/codex-app-linux\/actions\/runs\/1/); @@ -73,7 +73,7 @@ test("report-canary-failure creates exactly one actionable GitHub issue", async assert.match(body, /Channel \| prod/); assert.match(body, /Upstream build \| 4108/); assert.match(body, /Package version \| 26\.616\.30709-launcher\.29/); - assert.match(body, /open-target-dispatcher contract changed/); + assert.match(body, /linux-window-background contract changed/); assert.match(body, /canary log excerpt/); assert.match(body, /scripts\/lib\/upstream-patches\.mjs/); assert.match(body, /Publish blocked before mutation \| yes/); diff --git a/test/fixtures/upstream-main-26.616.30709-open-target.slice.txt b/test/fixtures/upstream-main-26.616.30709-open-target.slice.txt deleted file mode 100644 index c4d569e..0000000 --- a/test/fixtures/upstream-main-26.616.30709-open-target.slice.txt +++ /dev/null @@ -1,7 +0,0 @@ -function DN(e){let t=e.indexOf(`.app/Contents/MacOS/`);return t===-1?null:e.slice(0,t+4)} -async function ON({command:e,path:t,location:n,hostConfig:r,remoteWorkspaceRoot:i,remotePath:a}){let o=qM(t,n,r,i,a),s=o[0]??t,c=n==null?s:qM(t,null,r,i,a)[0]??s,l=DN(e);if(l){if(await no(`open`,[`-a`,l,c]),!n)return;let t=Qa(`zed`)??e;try{await no(t,o)}catch{}return}await no(e,o)} -var kN=[cN,uN,oN,lM,Bj,pM,XM,wN,pN,Rj,SM,$M,mM,Hj,yM,sM,hN,wM,vM,fN,yN,AM,jM,MM,NM,PM,FM,IM,LM,nN],AN=t.qr(`open-in-targets`); -function jN(e){return kN.flatMap(t=>{let n=t.platforms[e];return n?[{id:t.id,...n}]:[]})} -var MN=jN(process.platform),NN=HN(MN),PN=new WeakMap,FN=new WeakMap,IN=async e=>a.shell.readShortcutLink(e); -async function BN(e,t,{appPath:n,detectedCommand:r,hostConfig:i,location:a,remotePath:o,remoteWorkspaceRoot:s,targets:c=MN}={}){if(o!=null&&i?.kind===`remote-control`)throw Error(`Remote control does not support open in ${e} yet.`);let l=c.find(t=>t.id===e);if(!l)throw Error(`Unknown open target "${e}"`);let u=r??await l.detect(IN);if(!u)throw Error(`Open target "${e}" is not available`);if(l.open){await l.open({command:u,path:t,appPath:n,location:a,hostConfig:i,remoteWorkspaceRoot:s,remotePath:o});return}await no(u,l.args(t,a,i,s,o),{env:l.env?.()})} -function preferredTargets(){return{targets:[...l.map(({id:e,label:t,icon:n,kind:r,hidden:i})=>({id:e,target:e,label:t,icon:n,kind:r,hidden:i,available:m.has(e),default:h===e||void 0})),...y]}} diff --git a/test/upstream-patches.test.mjs b/test/upstream-patches.test.mjs index 6ebb39b..c1f026c 100644 --- a/test/upstream-patches.test.mjs +++ b/test/upstream-patches.test.mjs @@ -1,6 +1,5 @@ import test from "node:test"; import assert from "node:assert/strict"; -import fs from "node:fs/promises"; import vm from "node:vm"; import { @@ -11,14 +10,9 @@ import { patchLinuxOwlFeatureBindingSource, patchLinuxChromeExtensionDetectionSource, patchLinuxWindowFocusableSource, - patchLinuxOpenTargetsSource, upstreamPatchContracts } from "../scripts/lib/upstream-patches.mjs"; -const openTargetResolverSource = - "function W(e){let t=which.default.sync(e,{nothrow:!0});return typeof t==`string`&&fs.existsSync(t)?t:null}"; -const withOpenTargetResolver = parts => [openTargetResolverSource, ...parts].join(";"); - test("patchLinuxChromeExtensionDetectionSource finds stable Chrome profiles", () => { const source = "function o({homeDir:e,localAppDataDir:t,platform:n}){return n===`darwin`?p.join(e,`Library`,`Application Support`,`Google`,`Chrome`):n===`win32`?p.join(t??p.join(e,`AppData`,`Local`),`Google`,`Chrome`,`User Data`):null};globalThis.resolveChromeRoot=o"; @@ -81,149 +75,6 @@ test("patchLinuxChromeExtensionDetectionSource accepts metadata-driven Linux pro assert.equal(patchLinuxChromeExtensionDetectionSource(source), source); }); -test("patchLinuxOpenTargetsSource adds Linux editor targets and exposes app paths", () => { - const source = withOpenTargetResolver([ - "prefix", - "var wd=[nd,id,ed,ou,Ll,Wu,vd,sd,Fl,vu,qu,uu,zl,hu,iu,ld,bu,mu,od,pd,Eu,Du,Ou,ku,Au,ju,Mu,Nu,Xu],Td=t.kr(`open-in-targets`);function Ed(e){return wd.flatMap(t=>{let n=t.platforms[e];return n?[{id:t.id,...n}]:[]})}", - "async function Fd(e,t,n,r,i,a,o){let s={args:()=>[],env:()=>({})},c=`open`;await ol(c,s.args(t,r,i,a,o),{env:s.env?.()})}", - "middle", - "targets:[...o.map(({id:e,label:t,icon:n,kind:r,hidden:i})=>({id:e,target:e,label:t,icon:n,kind:r,hidden:i,available:s.has(e),default:c===e||void 0})),...p]", - "suffix" - ]); - - const patched = patchLinuxOpenTargetsSource(source); - - assert.match(patched, /__codexLinuxVSCode=\{id:`vscode`,platforms:\{linux:/); - assert.match(patched, /__codexLinuxCursor=\{id:`cursor`,platforms:\{linux:/); - assert.match(patched, /__codexLinuxZed=\{id:`zed`,platforms:\{linux:/); - assert.match(patched, /__codexLinuxNvim=\{id:`nvim`,platforms:\{linux:/); - assert.match( - patched, - /var wd=\[__codexLinuxVSCode,__codexLinuxVSCodeInsiders,__codexLinuxCursor,__codexLinuxZed,__codexLinuxNvim,nd,id/ - ); - assert.match( - patched, - /await ol\(r\.command,r\.args\(__codexLinuxOpenTargetNvimCommand\(e,t,n\)\)\)/ - ); - assert.match( - patched, - /appPath:process\.platform===`linux`&&r===`editor`&&s\.has\(e\)\?Ld\(\)\.get\(e\)\?\?null:null/ - ); - assert.match(patched, /let n=t\.platforms\?\.\[e\];return n/); - assert.doesNotMatch(patched, /let n=t\.platforms\[e\];return n/); -}); - -test("patchLinuxOpenTargetsSource is idempotent for target definitions", () => { - const source = withOpenTargetResolver([ - "var wd=[nd,id,ed,ou,Ll,Wu,vd,sd,Fl,vu,qu,uu,zl,hu,iu,ld,bu,mu,od,pd,Eu,Du,Ou,ku,Au,ju,Mu,Nu,Xu],Td=t.kr(`open-in-targets`);function Ed(e){return wd.flatMap(t=>{let n=t.platforms[e];return n?[{id:t.id,...n}]:[]})}", - "async function Fd(e,t,n,r,i,a,o){let s={args:()=>[],env:()=>({})},c=`open`;await ol(c,s.args(t,r,i,a,o),{env:s.env?.()})}", - "targets:[...o.map(({id:e,label:t,icon:n,kind:r,hidden:i})=>({id:e,target:e,label:t,icon:n,kind:r,hidden:i,available:s.has(e),default:c===e||void 0})),...p]" - ]); - - const patched = patchLinuxOpenTargetsSource(source); - const repatched = patchLinuxOpenTargetsSource(patched); - - assert.equal(repatched.match(/__codexLinuxVSCode=\{id:`vscode`,platforms:\{linux:/g).length, 1); -}); - -test("patchLinuxOpenTargetsSource accepts alternate minified logger names", () => { - const source = withOpenTargetResolver([ - "var Cd=[td,rd,$u,au,Il,Uu,_d,od,Pl,_u,Ku,lu,Rl,mu,ru,cd,yu,pu,ad,fd,Tu,Eu,Du,Ou,ku,Au,ju,Mu,Yu],wd=t.Or(`open-in-targets`);function Td(e){return Cd.flatMap(t=>{let n=t.platforms[e];return n?[{id:t.id,...n}]:[]})}", - "async function Pd(e,t,n,r,i,a,o){let s={args:()=>[],env:()=>({})},c=`open`;await ol(c,s.args(t,r,i,a,o),{env:s.env?.()})}", - "targets:[...o.map(({id:e,label:t,icon:n,kind:r,hidden:i})=>({id:e,target:e,label:t,icon:n,kind:r,hidden:i,available:s.has(e),default:c===e||void 0})),...p]" - ]); - - const patched = patchLinuxOpenTargetsSource(source); - - assert.match( - patched, - /var Cd=\[__codexLinuxVSCode,__codexLinuxVSCodeInsiders,__codexLinuxCursor,__codexLinuxZed,__codexLinuxNvim,td,rd/ - ); -}); - -test("patchLinuxOpenTargetsSource accepts upstream electron 42 registry shape", () => { - const source = withOpenTargetResolver([ - "var Wk=[Tk,Dk,Ck,OO,aO,MO,pk,Vk,Ak,rO,VO,gk,NO,sO,RO,EO,Mk,UO,LO,kk,Ik,YO,XO,ZO,QO,$O,ek,tk,nk,yk],Gk=n.Rr(`open-in-targets`);function Kk(e){return Wk.flatMap(t=>{let n=t.platforms[e];return n?[{id:t.id,...n}]:[]})}", - "async function tA(e,t,n,r,i,a,o){let s={args:()=>[],env:()=>({})},c=`open`;await vo(c,s.args(t,r,i,a,o),{env:s.env?.()})}", - "targets:[...s.map(({id:e,label:t,icon:n,kind:r,hidden:i})=>({id:e,target:e,label:t,icon:n,kind:r,hidden:i,available:c.has(e),default:l===e||void 0})),...g]" - ]); - - const patched = patchLinuxOpenTargetsSource(source); - - assert.match( - patched, - /var Wk=\[__codexLinuxVSCode,__codexLinuxVSCodeInsiders,__codexLinuxCursor,__codexLinuxZed,__codexLinuxNvim,Tk,Dk/ - ); - assert.match( - patched, - /targets:\[\.\.\.s\.map\(\(\{id:e,label:t,icon:n,kind:r,hidden:i\}\)=>\(\{id:e,target:e,label:t,icon:n,kind:r,hidden:i,appPath:process\.platform===`linux`&&r===`editor`&&c\.has\(e\)\?Ld\(\)\.get\(e\)\?\?null:null,available:c\.has\(e\),default:l===e\|\|void 0\}\)\),\.\.\.g\]/ - ); -}); - -test("patchLinuxOpenTargetsSource accepts upstream dispatcher runner shape", () => { - const source = withOpenTargetResolver([ - "var kN=[cN,uN,oN,lM],AN=t.qr(`open-in-targets`);function jN(e){return kN.flatMap(t=>{let n=t.platforms[e];return n?[{id:t.id,...n}]:[]})}", - "async function BN(e,t,{appPath:n,detectedCommand:r,hostConfig:i,location:a,remotePath:o,remoteWorkspaceRoot:s,targets:c=MN}={}){if(o!=null&&i?.kind===`remote-control`)throw Error(`Remote control does not support open in ${e} yet.`);let l=c.find(t=>t.id===e);if(!l)throw Error(`Unknown open target \"${e}\"`);let u=r??await l.detect(IN);if(!u)throw Error(`Open target \"${e}\" is not available`);if(l.open){await l.open({command:u,path:t,appPath:n,location:a,hostConfig:i,remoteWorkspaceRoot:s,remotePath:o});return}await no(u,l.args(t,a,i,s,o),{env:l.env?.()})}", - "targets:[...s.map(({id:e,label:t,icon:n,kind:r,hidden:i})=>({id:e,target:e,label:t,icon:n,kind:r,hidden:i,available:c.has(e),default:l===e||void 0})),...g]" - ]); - - const patched = patchLinuxOpenTargetsSource(source); - - assert.match( - patched, - /var kN=\[__codexLinuxVSCode,__codexLinuxVSCodeInsiders,__codexLinuxCursor,__codexLinuxZed,__codexLinuxNvim,cN,uN/ - ); - assert.match( - patched, - /await no\(r\.command,r\.args\(__codexLinuxOpenTargetNvimCommand\(e,t,n\)\)\)/ - ); -}); - -test("patchLinuxOpenTargetsSource accepts bare open-target logger and discovered resolver", () => { - const source = [ - "function os(e){let t=rs.default.sync(e,{nothrow:!0});return typeof t==`string`&&u.existsSync(t)?t:null}", - "var GN=[wN,EN,SN,TM,nM,kM,fN,BN,kN,eM,RM,hN,AM,iM,FM,CM,jN,BM,PM,ON,FN,KM,qM,JM,YM,XM,ZM,QM,$M,vN];t.ri(`open-in-targets`);function KN(e){return GN.flatMap(t=>{let n=t.platforms[e];return n?[{id:t.id,...n}]:[]})}", - "async function XN(e,t,{appPath:n,detectedCommand:r,hostConfig:i,location:a,remotePath:o,remoteWorkspaceRoot:s,targets:c=qN}={}){if(o!=null&&i?.kind===`remote-control`)throw Error(`Remote control does not support open in ${e} yet.`);let l=c.find(t=>t.id===e);if(!l)throw Error(`Unknown open target \"${e}\"`);let u=r??await l.detect(JN);if(!u)throw Error(`Open target \"${e}\" is not available`);if(l.open){await l.open({command:u,path:t,appPath:n,location:a,hostConfig:i,remoteWorkspaceRoot:s,remotePath:o});return}await us(u,l.args(t,a,i,s,o),{env:l.env?.()})}", - "targets:[...l.map(({id:e,label:t,icon:n,kind:r,hidden:i})=>({id:e,target:e,label:t,icon:n,kind:r,hidden:i,available:m.has(e),default:h===e||void 0})),...y]" - ].join(";"); - - const patched = patchLinuxOpenTargetsSource(source); - - assert.match( - patched, - /var GN=\[__codexLinuxVSCode,__codexLinuxVSCodeInsiders,__codexLinuxCursor,__codexLinuxZed,__codexLinuxNvim,wN,EN/ - ); - assert.match(patched, /detect:\(\)=>os\(`code`\)/); - assert.match(patched, /__codexLinuxShellQuote=/); - assert.doesNotMatch(patched, /t\.En/); - assert.match( - patched, - /appPath:process\.platform===`linux`&&r===`editor`&&m\.has\(e\)\?Ld\(\)\.get\(e\)\?\?null:null/ - ); -}); - -test("patchLinuxOpenTargetsSource accepts latest real upstream dispatcher fixture slice", async () => { - const source = await fs.readFile( - "test/fixtures/upstream-main-26.616.30709-open-target.slice.txt", - "utf8" - ); - - const patched = patchLinuxOpenTargetsSource(source); - - assert.match( - patched, - /var kN=\[__codexLinuxVSCode,__codexLinuxVSCodeInsiders,__codexLinuxCursor,__codexLinuxZed,__codexLinuxNvim,cN,uN/ - ); - assert.match( - patched, - /await no\(r\.command,r\.args\(__codexLinuxOpenTargetNvimCommand\(e,t,n\)\)\)/ - ); - assert.match( - patched, - /appPath:process\.platform===`linux`&&r===`editor`&&m\.has\(e\)\?Ld\(\)\.get\(e\)\?\?null:null/ - ); -}); - test("upstream patch contracts declare required contract surface", () => { assert.deepEqual( upstreamPatchContracts.map(contract => Object.keys(contract).sort()), @@ -232,7 +83,6 @@ test("upstream patch contracts declare required contract surface", () => { assert.deepEqual( upstreamPatchContracts.map(contract => contract.name), [ - "open-target-dispatcher", "linux-window-background", "linux-window-transparency", "linux-window-focusable-default", @@ -242,13 +92,6 @@ test("upstream patch contracts declare required contract surface", () => { ); }); -test("patchLinuxOpenTargetsSource reports contract name on upstream drift", () => { - assert.throws( - () => patchLinuxOpenTargetsSource("function nope(){}"), - /open-target-dispatcher contract changed: Unable to apply upstream patch; missing open target registry/ - ); -}); - test("patchLinuxWindowFocusableSource defaults undefined BrowserWindow focusability", () => { const source = [ "async function createWindow(e={}){", @@ -306,34 +149,6 @@ test("patchLinuxWindowFocusableSource is idempotent", () => { assert.equal(patchLinuxWindowFocusableSource(patched), patched); }); -test("patchLinuxOpenTargetsSource tolerates targets without platform maps", () => { - const source = withOpenTargetResolver([ - "var wd=[nd,id],Td=t.kr(`open-in-targets`);function Ed(e){return wd.flatMap(t=>{let n=t.platforms[e];return n?[{id:t.id,...n}]:[]})}", - "async function Fd(e,t,n,r,i,a,o){let s={args:()=>[],env:()=>({})},c=`open`;await ol(c,s.args(t,r,i,a,o),{env:s.env?.()})}", - "targets:[...o.map(({id:e,label:t,icon:n,kind:r,hidden:i})=>({id:e,target:e,label:t,icon:n,kind:r,hidden:i,available:s.has(e),default:c===e||void 0})),...p]" - ]); - - const patched = patchLinuxOpenTargetsSource(source); - - assert.match(patched, /let n=t\.platforms\?\.\[e\];return n/); -}); - -test("patchLinuxOpenTargetsSource preserves native target spread variable", () => { - const source = withOpenTargetResolver([ - "var uD=[HE,WE],dD=t.ti(`open-in-targets`);function fD(e){return uD.flatMap(t=>{let n=t.platforms[e];return n?[{id:t.id,...n}]:[]})}", - "async function xD(e,t,n,r,i,a,o){let s={args:()=>[],env:()=>({})},c=`open`;await zi(c,s.args(t,r,i,a,o),{env:s.env?.()})}", - "targets:[...o.map(({id:e,label:t,icon:n,kind:r,hidden:i})=>({id:e,target:e,label:t,icon:n,kind:r,hidden:i,available:s.has(e),default:c===e||void 0})),...h]" - ]); - - const patched = patchLinuxOpenTargetsSource(source); - - assert.match( - patched, - /appPath:process\.platform===`linux`&&r===`editor`&&s\.has\(e\)\?Ld\(\)\.get\(e\)\?\?null:null/ - ); - assert.match(patched, /\}\)\),\.\.\.h\]/); -}); - test("patchDisableTransparencySource disables Linux BrowserWindow transparency and background", () => { const source = [ "function A2(e){return e===`avatarOverlay`||e===`browserCommentPopup`}",