diff --git a/ai.opencode.opencode.yml b/ai.opencode.opencode.yml index 1564db6..7e8e0c0 100644 --- a/ai.opencode.opencode.yml +++ b/ai.opencode.opencode.yml @@ -57,6 +57,7 @@ modules: - mv usr/share/applications usr/share/icons /app/share - desktop-file-edit --set-key Exec --set-value "run.sh %U" /app/share/applications/ai.opencode.desktop.desktop - patch-electron-desktop-filename /app/main/resources/app.asar + - python3 patch-opencode-asar.py /app/main/resources/app.asar - install -Dm644 usr/share/metainfo/ai.opencode.desktop.metainfo.xml /app/share/metainfo/ai.opencode.opencode.metainfo.xml - install -Dm755 -t /app/bin run.sh sources: @@ -86,3 +87,5 @@ modules: - zypak-wrapper.sh /app/main/ai.opencode.desktop "$@" - type: file path: metainfo.patch + - type: file + path: patch-opencode-asar.py diff --git a/patch-opencode-asar.py b/patch-opencode-asar.py new file mode 100644 index 0000000..47a2ed1 --- /dev/null +++ b/patch-opencode-asar.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python3 +""" +Disable the OpenCode Electron app's self-updater inside a Flatpak, in place. + +Sets UPDATER_ENABLED = false in out/main/index.js inside app.asar. This is a +same-length text replacement, so the asar binary is patched directly without +extract/repack (which would drop the app.asar.unpacked native-module +metadata). The asar header, all offsets, and the unpacked entries are +preserved byte-for-byte. + +Flatpak provides updates via the OS updater (GNOME Software / KDE Discover / +flatpak update); the electron-updater self-updater can't install into the +read-only /app anyway, so it must be disabled. Upstream issue: +https://github.com/anomalyco/opencode/issues/39670 + +Usage: patch-opencode-asar.py +""" +import os +import sys + + +def main() -> None: + if len(sys.argv) != 2: + print(f"usage: {sys.argv[0]} ", file=sys.stderr) + sys.exit(2) + + asar_path = sys.argv[1] + if not os.environ.get("FLATPAK_ID"): + print("FLATPAK_ID is not set; expected to be run inside flatpak-builder", file=sys.stderr) + sys.exit(1) + + with open(asar_path, "rb") as f: + data = f.read() + + # out/main/index.js: `const UPDATER_ENABLED = app.isPackaged && CHANNEL !== "dev";` + # Replace the RHS with `false` plus a comment, padded to the same byte + # length so the asar layout (offsets, unpacked entries) is unchanged. + old = b'app.isPackaged && CHANNEL !== "dev"' + new = b'false/*packed&&CHANNEL!=="dev"*/'.ljust(len(old), b" ") + if len(old) != len(new): + raise SystemExit(f"length mismatch: {len(old)} vs {len(new)}") + count = data.count(old) + if count != 1: + raise SystemExit(f"expected exactly 1 occurrence of UPDATER_ENABLED, found {count}") + data = data.replace(old, new, 1) + + with open(asar_path, "wb") as f: + f.write(data) + + print(f"patched {asar_path}: UPDATER_ENABLED = false") + + +if __name__ == "__main__": + main() \ No newline at end of file