#!/usr/bin/env node import { execFile } from "node:child_process"; import fs from "node:fs/promises"; import path from "node:path"; import { promisify } from "node:util"; import { patchAsarMember, readAsarMember } from "../src/asar.mjs"; const execFileAsync = promisify(execFile); const appPath = path.resolve(process.argv[2] || "/Applications/ChatGPT.app"); const proxyPath = path.resolve(process.argv[3] || path.join(appPath, "Contents", "Resources", "omp-codex-git")); const archivePath = path.join(appPath, "Contents", "Resources", "app.asar"); const backupPath = `${archivePath}.omp-upstream-bak`; const workerMember = ".vite/build/worker.js"; const proxyLiteral = JSON.stringify(proxyPath); const archive = await fs.readFile(archivePath); const worker = readAsarMember(archive, workerMember).toString("utf8"); let changed = false; if (!worker.includes(proxyLiteral)) { const pattern = /\[`git`,\.\.\.([A-Za-z_$][\w$]*),`-c`,([A-Za-z_$][\w$]*),`-c`,`core\.hooksPath=\$\{/g; const matches = [...worker.matchAll(pattern)]; if (matches.length !== 1) { throw new Error(`expected one central Git executor in ${workerMember}, found ${matches.length}`); } await fs.copyFile(archivePath, backupPath); changed = true; } const infoPlistPath = path.join(appPath, "Contents", "Info.plist"); const infoPlistBackupPath = `${infoPlistPath}.omp-tmp-${process.pid}`; await fs.copyFile(infoPlistPath, infoPlistBackupPath); let result; try { result = await patchAsarMember(archivePath, workerMember, (source) => { if (source.includes(proxyLiteral)) return source; return source.replace( /\[`git`,\.\.\.([A-Za-z_$][\w$]*),`-c`,([A-Za-z_$][\w$]*),`-c`,`core\.hooksPath=\$\{/, `[${proxyLiteral},...$1,\`-c\`,$2,\`-c\`,\`core.hooksPath=\${` ); }); await execFileAsync("/usr/libexec/PlistBuddy", [ "-c", `Set :ElectronAsarIntegrity:Resources/app.asar:hash ${result.headerHash}`, infoPlistPath, ]); await fs.rm(infoPlistBackupPath, { force: true }); } catch (error) { await fs.copyFile(infoPlistBackupPath, infoPlistPath).catch(() => {}); await fs.rm(infoPlistBackupPath, { force: true }).catch(() => {}); if (changed) await fs.copyFile(backupPath, archivePath); throw error; } process.stdout.write(`${JSON.stringify({ changed: changed && result.changed, headerHash: result.headerHash, proxyPath })}\n`);