diff --git a/.github/workflows/relay-build.yml b/.github/workflows/relay-build.yml index 2a17e9ee..1e23f6d4 100644 --- a/.github/workflows/relay-build.yml +++ b/.github/workflows/relay-build.yml @@ -20,7 +20,7 @@ permissions: env: BUNDLED_NODE_VERSION: "24.14.1" CHROME_DEVTOOLS_MCP_VERSION: "0.20.0" - BUNDLED_PYTHON_VERSION: "3.14.1" + BUNDLED_PYTHON_VERSION: "3.13.10" BUNDLED_PYTHON_STANDALONE_RELEASE: "20251202" BUNDLED_WINDOWS_GIT_VERSION: "2.49.0.windows.1" BUNDLED_FFMPEG_RELEASE_TAG: "n7.1-2" @@ -131,7 +131,7 @@ jobs: if: matrix.goos == 'linux' && matrix.goarch == 'amd64' run: | sudo apt-get update -qq - sudo apt-get install -y -qq libfuse-dev libfuse2t64 + sudo apt-get install -y -qq libfuse-dev libfuse2t64 libx11-dev libxtst-dev libxinerama-dev libxrandr-dev - name: Prepare shared Node runtime run: node relay/scripts/prepare-node-bundle.mjs --target-platform=${{ matrix.goos }}-${{ matrix.goarch }} --node-version=${{ env.BUNDLED_NODE_VERSION }} diff --git a/.github/workflows/relay-ci.yml b/.github/workflows/relay-ci.yml index cc468772..57f3398a 100644 --- a/.github/workflows/relay-ci.yml +++ b/.github/workflows/relay-ci.yml @@ -16,7 +16,7 @@ permissions: env: BUNDLED_NODE_VERSION: "24.14.1" CHROME_DEVTOOLS_MCP_VERSION: "0.20.0" - BUNDLED_PYTHON_VERSION: "3.14.1" + BUNDLED_PYTHON_VERSION: "3.13.10" BUNDLED_PYTHON_STANDALONE_RELEASE: "20251202" BUNDLED_WINDOWS_GIT_VERSION: "2.49.0.windows.1" BUNDLED_FFMPEG_RELEASE_TAG: "n7.1-2" @@ -64,10 +64,10 @@ jobs: env: MATRIX_JSON: >- [ - {"runner":"ubuntu-latest","goos":"linux","goarch":"amd64","suffix":"linux-amd64","wails_tags":"desktop_cua,webkit2_41","cgo_ldflags_allow":"","wails_extra_args":"","setup":"sudo apt-get update -qq\nsudo apt-get install -y -qq libgtk-3-dev libwebkit2gtk-4.1-dev desktop-file-utils patchelf squashfs-tools"}, - {"runner":"macos-15","goos":"darwin","goarch":"arm64","suffix":"darwin-arm64","wails_tags":"desktop_cua","cgo_ldflags_allow":"^(-weak_framework|ScreenCaptureKit)$","wails_extra_args":"","setup":""}, - {"runner":"macos-15-intel","goos":"darwin","goarch":"amd64","suffix":"darwin-amd64","wails_tags":"desktop_cua","cgo_ldflags_allow":"^(-weak_framework|ScreenCaptureKit)$","wails_extra_args":"","setup":""}, - {"runner":"windows-latest","goos":"windows","goarch":"amd64","suffix":"windows-amd64","ext":".exe","wails_tags":"desktop_cua","cgo_ldflags_allow":"","wails_extra_args":"-nsis","setup":"pwsh -File .github/scripts/setup-windows-gui-build.ps1"} + {"runner":"ubuntu-latest","goos":"linux","goarch":"amd64","suffix":"linux-amd64","wails_tags":"desktop_cua,webkit2_41","cgo_ldflags_allow":"","macos_deployment_target":"","wails_extra_args":"","setup":"sudo apt-get update -qq\nsudo apt-get install -y -qq libgtk-3-dev libwebkit2gtk-4.1-dev desktop-file-utils patchelf squashfs-tools"}, + {"runner":"macos-15","goos":"darwin","goarch":"arm64","suffix":"darwin-arm64","wails_tags":"desktop_cua","cgo_ldflags_allow":"^(-weak_framework|ScreenCaptureKit)$","macos_deployment_target":"14.4","wails_extra_args":"","setup":""}, + {"runner":"macos-15-intel","goos":"darwin","goarch":"amd64","suffix":"darwin-amd64","wails_tags":"desktop_cua","cgo_ldflags_allow":"^(-weak_framework|ScreenCaptureKit)$","macos_deployment_target":"14.4","wails_extra_args":"","setup":""}, + {"runner":"windows-latest","goos":"windows","goarch":"amd64","suffix":"windows-amd64","ext":".exe","wails_tags":"desktop_cua","cgo_ldflags_allow":"","macos_deployment_target":"","wails_extra_args":"-nsis","setup":"pwsh -File .github/scripts/setup-windows-gui-build.ps1"} ] REQUESTED_PLATFORMS: ${{ vars.RELAY_GUI_BUILD_PLATFORMS || 'all' }} run: python3 .github/scripts/filter-platform-matrix.py @@ -224,7 +224,7 @@ jobs: if: matrix.goos == 'linux' && matrix.goarch == 'amd64' run: | sudo apt-get update -qq - sudo apt-get install -y -qq libfuse-dev libfuse2t64 + sudo apt-get install -y -qq libfuse-dev libfuse2t64 libx11-dev libxtst-dev libxinerama-dev libxrandr-dev - name: Build working-directory: relay @@ -467,6 +467,9 @@ jobs: env: CGO_LDFLAGS_ALLOW: ${{ matrix.cgo_ldflags_allow }} run: | + if [ -n "${{ matrix.macos_deployment_target }}" ]; then + export MACOSX_DEPLOYMENT_TARGET="${{ matrix.macos_deployment_target }}" + fi extra_args="${{ matrix.wails_extra_args }}" if [ "${{ matrix.goos }}" = "windows" ]; then extra_args="${{ steps.windows_package_variants.outputs.wails_extra_args }}" diff --git a/.github/workflows/relay-gui-build.yml b/.github/workflows/relay-gui-build.yml index e1ce50dd..71f33439 100644 --- a/.github/workflows/relay-gui-build.yml +++ b/.github/workflows/relay-gui-build.yml @@ -24,7 +24,7 @@ permissions: env: BUNDLED_NODE_VERSION: "24.14.1" CHROME_DEVTOOLS_MCP_VERSION: "0.20.0" - BUNDLED_PYTHON_VERSION: "3.14.1" + BUNDLED_PYTHON_VERSION: "3.13.10" BUNDLED_PYTHON_STANDALONE_RELEASE: "20251202" BUNDLED_WINDOWS_GIT_VERSION: "2.49.0.windows.1" BUNDLED_FFMPEG_RELEASE_TAG: "n7.1-2" @@ -76,10 +76,10 @@ jobs: env: MATRIX_JSON: >- [ - {"runner":"ubuntu-latest","goos":"linux","goarch":"amd64","suffix":"linux-amd64","wails_tags":"desktop_cua,webkit2_41","cgo_ldflags_allow":"","wails_extra_args":"","setup":"sudo apt-get update -qq\nsudo apt-get install -y -qq libgtk-3-dev libwebkit2gtk-4.1-dev desktop-file-utils patchelf squashfs-tools"}, - {"runner":"macos-15","goos":"darwin","goarch":"arm64","suffix":"darwin-arm64","wails_tags":"desktop_cua","cgo_ldflags_allow":"^(-weak_framework|ScreenCaptureKit)$","wails_extra_args":"","setup":""}, - {"runner":"macos-15-intel","goos":"darwin","goarch":"amd64","suffix":"darwin-amd64","wails_tags":"desktop_cua","cgo_ldflags_allow":"^(-weak_framework|ScreenCaptureKit)$","wails_extra_args":"","setup":""}, - {"runner":"windows-latest","goos":"windows","goarch":"amd64","suffix":"windows-amd64","ext":".exe","wails_tags":"desktop_cua","cgo_ldflags_allow":"","wails_extra_args":"-nsis","setup":"pwsh -File .github/scripts/setup-windows-gui-build.ps1"} + {"runner":"ubuntu-latest","goos":"linux","goarch":"amd64","suffix":"linux-amd64","wails_tags":"desktop_cua,webkit2_41","cgo_ldflags_allow":"","macos_deployment_target":"","wails_extra_args":"","setup":"sudo apt-get update -qq\nsudo apt-get install -y -qq libgtk-3-dev libwebkit2gtk-4.1-dev desktop-file-utils patchelf squashfs-tools"}, + {"runner":"macos-15","goos":"darwin","goarch":"arm64","suffix":"darwin-arm64","wails_tags":"desktop_cua","cgo_ldflags_allow":"^(-weak_framework|ScreenCaptureKit)$","macos_deployment_target":"14.4","wails_extra_args":"","setup":""}, + {"runner":"macos-15-intel","goos":"darwin","goarch":"amd64","suffix":"darwin-amd64","wails_tags":"desktop_cua","cgo_ldflags_allow":"^(-weak_framework|ScreenCaptureKit)$","macos_deployment_target":"14.4","wails_extra_args":"","setup":""}, + {"runner":"windows-latest","goos":"windows","goarch":"amd64","suffix":"windows-amd64","ext":".exe","wails_tags":"desktop_cua","cgo_ldflags_allow":"","macos_deployment_target":"","wails_extra_args":"-nsis","setup":"pwsh -File .github/scripts/setup-windows-gui-build.ps1"} ] REQUESTED_PLATFORMS: ${{ github.event_name == 'workflow_dispatch' && inputs.platforms || vars.RELAY_GUI_BUILD_PLATFORMS || 'all' }} run: python3 .github/scripts/filter-platform-matrix.py @@ -210,6 +210,9 @@ jobs: env: CGO_LDFLAGS_ALLOW: ${{ matrix.cgo_ldflags_allow }} run: | + if [ -n "${{ matrix.macos_deployment_target }}" ]; then + export MACOSX_DEPLOYMENT_TARGET="${{ matrix.macos_deployment_target }}" + fi extra_args="${{ matrix.wails_extra_args }}" if [ "${{ matrix.goos }}" = "windows" ]; then extra_args="${{ steps.windows_package_variants.outputs.wails_extra_args }}" diff --git a/relay/cmd/synapse-relay-gui/packaging/linux/synapse-relay-gui.png b/relay/cmd/synapse-relay-gui/packaging/linux/synapse-relay-gui.png new file mode 100644 index 00000000..acde14a1 Binary files /dev/null and b/relay/cmd/synapse-relay-gui/packaging/linux/synapse-relay-gui.png differ diff --git a/relay/internal/builtinmcp/cua/overlay_darwin.go b/relay/internal/builtinmcp/cua/overlay_darwin.go index 6ab1e214..b2dd6431 100644 --- a/relay/internal/builtinmcp/cua/overlay_darwin.go +++ b/relay/internal/builtinmcp/cua/overlay_darwin.go @@ -799,22 +799,3 @@ func (d *darwinOverlayController) CaptureInfo(runtimeSessionID string) overlayCa } return overlayCaptureInfo{ExcludedWindowIDs: windowIDs} } - -//export synapseDarwinOverlayHotkeyCallback -func synapseDarwinOverlayHotkeyCallback(controllerID C.uintptr_t, action C.int) { - raw, ok := darwinOverlayControllers.Load(uint64(controllerID)) - if !ok { - return - } - controller, ok := raw.(*darwinOverlayController) - if !ok || controller == nil || controller.hotkeyHandler == nil { - return - } - - switch int(action) { - case int(C.SynapseDarwinHotkeyTerminate): - go controller.hotkeyHandler(overlayHotkeyTerminate) - case int(C.SynapseDarwinHotkeyDisable): - go controller.hotkeyHandler(overlayHotkeyDisableBoot) - } -} diff --git a/relay/internal/builtinmcp/cua/overlay_darwin_export.go b/relay/internal/builtinmcp/cua/overlay_darwin_export.go new file mode 100644 index 00000000..dad220a3 --- /dev/null +++ b/relay/internal/builtinmcp/cua/overlay_darwin_export.go @@ -0,0 +1,32 @@ +//go:build darwin && desktop_cua && cgo + +package cua + +/* +#include +*/ +import "C" + +const ( + synapseDarwinHotkeyTerminate = 1 + synapseDarwinHotkeyDisable = 2 +) + +//export synapseDarwinOverlayHotkeyCallback +func synapseDarwinOverlayHotkeyCallback(controllerID C.uintptr_t, action C.int) { + raw, ok := darwinOverlayControllers.Load(uint64(controllerID)) + if !ok { + return + } + controller, ok := raw.(*darwinOverlayController) + if !ok || controller == nil || controller.hotkeyHandler == nil { + return + } + + switch int(action) { + case synapseDarwinHotkeyTerminate: + go controller.hotkeyHandler(overlayHotkeyTerminate) + case synapseDarwinHotkeyDisable: + go controller.hotkeyHandler(overlayHotkeyDisableBoot) + } +} diff --git a/relay/scripts/package-gui-linux.sh b/relay/scripts/package-gui-linux.sh index 35b13aef..8352c71f 100755 --- a/relay/scripts/package-gui-linux.sh +++ b/relay/scripts/package-gui-linux.sh @@ -47,6 +47,7 @@ portable_root="synapse-relay-gui-${suffix}-portable" portable_archive="synapse-relay-gui-${suffix}-portable.tar.gz" deb_output="synapse-relay-gui-${suffix}.deb" appimage_output="synapse-relay-gui-${suffix}.AppImage" +icon_path="${repo_root}/relay/cmd/synapse-relay-gui/packaging/linux/synapse-relay-gui.png" package_version="${version#v}" if [[ ! "$package_version" =~ ^[0-9] ]]; then @@ -83,7 +84,7 @@ mkdir -p \ "${deb_root}/DEBIAN" install -m 0755 "$binary_path" "${install_root}/synapse-relay-gui" node "${repo_root}/relay/scripts/prepare-gui-build-assets.mjs" --runtime-output="${install_root}/runtime" -install -m 0644 "${repo_root}/packages/web-next/public/synapse.png" "${deb_root}/usr/share/icons/hicolor/256x256/apps/synapse-relay-gui.png" +install -m 0644 "$icon_path" "${deb_root}/usr/share/icons/hicolor/256x256/apps/synapse-relay-gui.png" ln -s /opt/synapse-relay-gui/synapse-relay-gui "${deb_root}/usr/bin/synapse-relay-gui" cat >"${deb_root}/usr/share/applications/synapse-relay-gui.desktop" <<'EOF' @@ -119,8 +120,7 @@ mkdir -p \ "${appdir}/usr/share/icons/hicolor/256x256/apps" \ "${appdir}/usr/share/metainfo" install -m 0755 "$binary_path" "${appdir}/usr/bin/synapse-relay-gui-bin" -node "${repo_root}/relay/scripts/prepare-gui-build-assets.mjs" --runtime-output="${appdir}/usr/lib/synapse-relay-gui/runtime" -install -m 0644 "${repo_root}/packages/web-next/public/synapse.png" "${appdir}/usr/share/icons/hicolor/256x256/apps/synapse-relay-gui.png" +install -m 0644 "$icon_path" "${appdir}/usr/share/icons/hicolor/256x256/apps/synapse-relay-gui.png" cat >"${appdir}/usr/share/applications/synapse-relay-gui.desktop" <<'EOF' [Desktop Entry] @@ -161,6 +161,8 @@ APPIMAGE_EXTRACT_AND_RUN=1 "$linuxdeploy" \ -d "${appdir}/usr/share/applications/synapse-relay-gui.desktop" \ -i "${appdir}/usr/share/icons/hicolor/256x256/apps/synapse-relay-gui.png" +node "${repo_root}/relay/scripts/prepare-gui-build-assets.mjs" --runtime-output="${appdir}/usr/lib/synapse-relay-gui/runtime" + cat >"${appdir}/usr/bin/synapse-relay-gui" <<'EOF' #!/bin/sh set -eu diff --git a/relay/scripts/prepare-commandline-bundle.mjs b/relay/scripts/prepare-commandline-bundle.mjs index 89d97f3a..0e873692 100644 --- a/relay/scripts/prepare-commandline-bundle.mjs +++ b/relay/scripts/prepare-commandline-bundle.mjs @@ -22,7 +22,7 @@ import { fileURLToPath } from "node:url" import { resolveRequiredSubprojectRoot } from "./lib/subprojects.mjs" const DEFAULT_NODE_VERSION = "24.14.1" -const DEFAULT_PYTHON_VERSION = "3.14.1" +const DEFAULT_PYTHON_VERSION = "3.13.10" const DEFAULT_PYTHON_STANDALONE_RELEASE = "20251202" const DEFAULT_WINDOWS_GIT_VERSION = "2.49.0.windows.1" const DEFAULT_FFMPEG_RELEASE_TAG = "n7.1-2" @@ -49,7 +49,7 @@ const PYTHON_DISTRIBUTIONS = { }, "darwin-amd64": { distribution: "x86_64-apple-darwin-install_only_stripped", - pipPlatform: "macosx_10_13_x86_64", + pipPlatform: "macosx_11_0_x86_64", }, "darwin-arm64": { distribution: "aarch64-apple-darwin-install_only_stripped", @@ -128,7 +128,7 @@ const PYTHON_REQUIREMENTS = [ "lxml==6.0.2", "mutagen==1.47.0", "openpyxl==3.1.5", - "pandas==3.0.2", + "pandas==2.3.2", "pdfplumber==0.11.4", "Pillow==12.2.0", "pydub==0.25.1", @@ -146,6 +146,9 @@ const PYTHON_REQUIREMENTS = [ "xlrd==2.0.1", ] +// Cross-platform pip installs require wheels; prebuild known pure-Python sdists. +const PURE_PYTHON_SOURCE_WHEEL_REQUIREMENTS = ["pyaes==1.6.1"] + const NODE_MODULE_PRUNE_DIRS = new Set([ "__image_snapshots__", "__snapshots__", @@ -378,6 +381,7 @@ function getCommandlineAssetVersion( nodeAssetVersion, nodeDependencies: NODE_DEPENDENCIES, pythonRequirements: PYTHON_REQUIREMENTS, + purePythonSourceWheelRequirements: PURE_PYTHON_SOURCE_WHEEL_REQUIREMENTS, managedProviders: managedProviders.map((provider) => ({ slug: provider.slug, displayName: provider.displayName, @@ -648,6 +652,32 @@ async function installPythonPackages( ) } +async function preparePurePythonSourceWheelhouse(wheelhouseDirectory) { + if (PURE_PYTHON_SOURCE_WHEEL_REQUIREMENTS.length === 0) { + return + } + + const hostPython = + process.env.PYTHON || (process.platform === "win32" ? "python" : "python3") + await mkdir(wheelhouseDirectory, { recursive: true }) + await runCommand( + hostPython, + [ + "-m", + "pip", + "wheel", + "--disable-pip-version-check", + "--no-deps", + "--wheel-dir", + wheelhouseDirectory, + ...PURE_PYTHON_SOURCE_WHEEL_REQUIREMENTS, + ], + { + shell: process.platform === "win32", + } + ) +} + async function findFiles(rootDir, matcher) { const queue = [rootDir] const matches = [] @@ -1177,7 +1207,8 @@ async function installManagedPythonPackages( pythonVersion, targetDirectory, providers, - providerRoots + providerRoots, + wheelhouseDirectory ) { const pythonSpec = PYTHON_DISTRIBUTIONS[targetPlatform] if (!pythonSpec) { @@ -1210,6 +1241,9 @@ async function installManagedPythonPackages( "--target", targetDirectory, ] + if (wheelhouseDirectory) { + pipArgs.push("--find-links", wheelhouseDirectory) + } const shouldAllowSourceDists = installSpec.allowSourceDists && targetPlatform === getNativeTargetPlatform() @@ -1595,12 +1629,14 @@ async function main() { const pythonArchivePath = join(workDir, pythonSpec.archiveFileName) const pythonExtractDir = join(workDir, "python-extract") const pythonPackageDir = join(workDir, "python-site-packages") + const pythonSourceWheelhouseDir = join(workDir, "python-source-wheelhouse") const gitExtractDir = join(workDir, "git-extract") const ffmpegDownloadDir = join(workDir, "ffmpeg-downloads") await mkdir(nodePackageDir, { recursive: true }) await mkdir(pythonExtractDir, { recursive: true }) await mkdir(pythonPackageDir, { recursive: true }) + await mkdir(pythonSourceWheelhouseDir, { recursive: true }) await mkdir(gitExtractDir, { recursive: true }) await mkdir(ffmpegDownloadDir, { recursive: true }) @@ -1625,6 +1661,7 @@ async function main() { console.log( `Installing bundled Python packages (${options.packageProfile})` ) + await preparePurePythonSourceWheelhouse(pythonSourceWheelhouseDir) await installPythonPackages( options.targetPlatform, options.pythonVersion, @@ -1635,7 +1672,8 @@ async function main() { options.pythonVersion, pythonPackageDir, managedProviderManifest, - providerRoots + providerRoots, + pythonSourceWheelhouseDir ) await installCliAnythingExtraPythonPackages( options.targetPlatform,