diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 20b8fd6..8d373bf 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -111,7 +111,41 @@ jobs: - name: package env: SEMVER: ${{ needs.tag.outputs.semver }} - run: bunx electron-builder ${{ matrix.args }} -c.extraMetadata.version="$SEMVER" --publish never + CSC_LINK: ${{ secrets.CSC_LINK }} + CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }} + WIN_CSC_LINK: ${{ secrets.WIN_CSC_LINK }} + WIN_CSC_KEY_PASSWORD: ${{ secrets.WIN_CSC_KEY_PASSWORD }} + APPLE_API_KEY: ${{ secrets.APPLE_API_KEY }} + APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }} + APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }} + APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} + run: | + set -euo pipefail + case "$RUNNER_OS" in + macOS) + unset WIN_CSC_LINK WIN_CSC_KEY_PASSWORD + ;; + Windows) + unset CSC_LINK CSC_KEY_PASSWORD APPLE_API_KEY APPLE_API_KEY_ID APPLE_API_ISSUER APPLE_TEAM_ID + ;; + *) + unset CSC_LINK CSC_KEY_PASSWORD WIN_CSC_LINK WIN_CSC_KEY_PASSWORD + unset APPLE_API_KEY APPLE_API_KEY_ID APPLE_API_ISSUER APPLE_TEAM_ID + ;; + esac + for name in CSC_LINK CSC_KEY_PASSWORD WIN_CSC_LINK WIN_CSC_KEY_PASSWORD APPLE_API_KEY APPLE_API_KEY_ID APPLE_API_ISSUER APPLE_TEAM_ID; do + if [ -z "${!name-}" ]; then + unset "$name" + fi + done + if [ "$RUNNER_OS" = "macOS" ] && [ -n "${CSC_LINK-}" ] && [ -n "${APPLE_API_KEY-}" ]; then + echo "signing and notarizing the macOS build" + elif [ "$RUNNER_OS" = "Windows" ] && [ -n "${WIN_CSC_LINK-}" ]; then + echo "signing the Windows build" + else + echo "no signing secrets for $RUNNER_OS; publishing unsigned artefacts" + fi + bunx electron-builder ${{ matrix.args }} -c.extraMetadata.version="$SEMVER" --publish never - name: upload installers env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/Casks/pidex.rb b/Casks/pidex.rb index 310d9a1..cc8baef 100644 --- a/Casks/pidex.rb +++ b/Casks/pidex.rb @@ -9,7 +9,7 @@ desc "Desktop workbench for the Pi coding agent" homepage "https://github.com/echohello-dev/pidex" - depends_on macos: :sonoma + depends_on macos: :monterey app "pidex.app" diff --git a/docs/adr/0010-distribution-channels.md b/docs/adr/0010-distribution-channels.md index e0711bd..82e8364 100644 --- a/docs/adr/0010-distribution-channels.md +++ b/docs/adr/0010-distribution-channels.md @@ -11,10 +11,11 @@ - electron-builder wants semver; CalVer tags with leading zeros (`2026.08.09-2`) are mapped to `2026.8.9-2` for the packager and `2026.8.9.2` for Winget. - Builds are unsigned. macOS Gatekeeper and Windows SmartScreen will warn until Developer ID / Authenticode certs are added via `CSC_*` secrets. - Docker is a Linux/X11 fallback, not the daily-driver install. The app reads `~/.pi/agent/sessions` and expects a local Pi CLI. - - Official Homebrew and Winget directory listings remain a follow-up (manual PR plus, for Winget, a `WINGET_TOKEN`). The org tap is the supported install path until then. - - Snap, Flathub, Chocolatey, and the Mac / Microsoft stores are out of scope until there is signing and a store account. + - Official Homebrew and Winget directory listings are manual pull requests against the published installers. The org tap stays the install path until those land. + - Signing and notarization run in the release workflow when Developer ID and Authenticode secrets are set. Without them the artefacts stay unsigned. + - A Flatpak manifest lives in `packaging/flatpak/`. Flathub submission is a human pull request. Snap, Chocolatey, and the Mac / Microsoft stores stay out of scope. - **Follow-ups**: - - Apple Developer ID + notarization; Authenticode for NSIS. + - Add `CSC_LINK`, `APPLE_API_*`, and `WIN_CSC_LINK` secrets. An Apple Development certificate cannot notarize. - `electron-updater` once macOS builds are signed (Squirrel.Mac refuses unsigned updates). - - PR the cask into `homebrew/homebrew-cask` and the singleton into `microsoft/winget-pkgs`. + - After the first `echoHello.Pidex` Winget manifest is merged, update PRs can use `WINGET_TOKEN`. diff --git a/docs/distribution.md b/docs/distribution.md index a6aabee..cc3e6be 100644 --- a/docs/distribution.md +++ b/docs/distribution.md @@ -2,7 +2,7 @@ pidex ships from GitHub Releases on every push to `main`. Tags stay CalVer (`YYYY.0M.0D`, see [ADR 0009](adr/0009-calver-releases.md)). The packager matrix and public channels are [ADR 0010](adr/0010-distribution-channels.md). -Builds are unsigned. First launch on macOS needs right-click → Open. Windows SmartScreen may ask you to keep the file. +Builds are unsigned until Developer ID and Authenticode secrets are set on the repository. Until then, first launch on macOS needs right-click → Open, and Windows SmartScreen may ask you to keep the file. ## GitHub Releases @@ -63,13 +63,35 @@ $ mise run package `mise run package` builds installers for the platform you are on. CI builds all three. -## Signing (not wired yet) +## Signing + +The release workflow signs when these repository secrets exist. Empty secrets stay unset, and that platform is published unsigned. + +| Secret | Value | +|---|---| +| `CSC_LINK` | Base64 of the Developer ID Application `.p12` | +| `CSC_KEY_PASSWORD` | Password for that `.p12` | +| `APPLE_API_KEY` | Base64 of the App Store Connect API `.p8` | +| `APPLE_API_KEY_ID` | Key ID | +| `APPLE_API_ISSUER` | Issuer ID | +| `APPLE_TEAM_ID` | 10-character Team ID | +| `WIN_CSC_LINK` | Base64 of the Authenticode `.pfx` | +| `WIN_CSC_KEY_PASSWORD` | Password for that `.pfx` | + +An Apple Development certificate cannot notarize a public DMG. It has to be a Developer ID Application certificate from the Apple Developer Program. With the four `APPLE_*` secrets set as well, electron-builder notarizes and staples the macOS build. Windows uses `WIN_CSC_*` only, so a Mac `.p12` is not sent to the Windows runner. + +```bash +$ base64 -i Certificates.p12 | pbcopy # store as CSC_LINK +$ base64 -i AuthKey_XXXX.p8 | pbcopy # store as APPLE_API_KEY +``` | Secret | Effect | |---|---| -| `CSC_LINK` + `CSC_KEY_PASSWORD` | electron-builder signs macOS / Windows when present | -| Apple notarization keys | Required before Gatekeeper stops warning | -| `WINGET_TOKEN` | Would let CI open the `winget-pkgs` PR | -| `TAP_TOKEN` | PAT with `repo` on `echohello-dev/homebrew-tap`; pidex dispatches `pidex-release` so the tap syncs immediately instead of waiting for the hourly cron | +| `WINGET_TOKEN` | Classic PAT (`public_repo`) so a later workflow can open `winget-pkgs` update PRs. The first listing is a manual PR. | +| `TAP_TOKEN` | PAT with `repo` on `echohello-dev/homebrew-tap`. pidex dispatches `pidex-release` so the tap syncs immediately instead of waiting for the hourly cron. | + +## Flathub + +`packaging/flatpak/` is a Flatpak manifest for `dev.echohello.Pidex`. It wraps the published AppImage and grants `filesystem=home` so `~/.pi` and home-directory workspaces are visible. -Leave them unset and the workflow publishes unsigned artefacts on purpose. +Flathub does not accept agent-opened submission pull requests. A person opens that PR against `flathub/flathub` branch `new-pr`. Reviewers also treat host-dependent developer tools as a special case, because pidex shells out to the Pi CLI on the host. The manifest is here so that submission can be made by hand. The AppImage and `.deb` remain the Linux install. diff --git a/electron-builder.yml b/electron-builder.yml index 0076603..1e97cd1 100644 --- a/electron-builder.yml +++ b/electron-builder.yml @@ -22,7 +22,6 @@ mac: arch: [arm64, x64] hardenedRuntime: true gatekeeperAssess: false - identity: null entitlements: build/entitlements.mac.plist entitlementsInherit: build/entitlements.mac.plist diff --git a/packaging/flatpak/dev.echohello.Pidex.desktop b/packaging/flatpak/dev.echohello.Pidex.desktop new file mode 100644 index 0000000..ab21f5b --- /dev/null +++ b/packaging/flatpak/dev.echohello.Pidex.desktop @@ -0,0 +1,9 @@ +[Desktop Entry] +Name=pidex +Comment=Desktop workbench for the Pi coding agent +Exec=pidex +Icon=dev.echohello.Pidex +Terminal=false +Type=Application +Categories=Development; +StartupWMClass=pidex diff --git a/packaging/flatpak/dev.echohello.Pidex.metainfo.xml b/packaging/flatpak/dev.echohello.Pidex.metainfo.xml new file mode 100644 index 0000000..3d52a12 --- /dev/null +++ b/packaging/flatpak/dev.echohello.Pidex.metainfo.xml @@ -0,0 +1,23 @@ + + + dev.echohello.Pidex + pidex + Desktop workbench for the Pi coding agent + CC0-1.0 + Apache-2.0 + + echoHello + + https://github.com/echohello-dev/pidex + +

+ pidex is a workspace-first desktop workbench for the Pi coding agent. + It reads existing sessions from the Pi CLI on this computer. +

+
+ dev.echohello.Pidex.desktop + + + + +
diff --git a/packaging/flatpak/dev.echohello.Pidex.png b/packaging/flatpak/dev.echohello.Pidex.png new file mode 100644 index 0000000..c07ff9c Binary files /dev/null and b/packaging/flatpak/dev.echohello.Pidex.png differ diff --git a/packaging/flatpak/dev.echohello.Pidex.yml b/packaging/flatpak/dev.echohello.Pidex.yml new file mode 100644 index 0000000..c11acd9 --- /dev/null +++ b/packaging/flatpak/dev.echohello.Pidex.yml @@ -0,0 +1,47 @@ +app-id: dev.echohello.Pidex +runtime: org.freedesktop.Platform +runtime-version: '25.08' +sdk: org.freedesktop.Sdk +base: org.electronjs.Electron2.BaseApp +base-version: '25.08' +command: pidex +separate-locales: false +finish-args: + - --share=ipc + - --share=network + - --socket=fallback-x11 + - --socket=wayland + - --socket=pulseaudio + - --device=dri + - --filesystem=home + - --talk-name=org.freedesktop.Notifications +modules: + - name: pidex + buildsystem: simple + build-commands: + - install -Dm644 dev.echohello.Pidex.metainfo.xml /app/share/metainfo/dev.echohello.Pidex.metainfo.xml + - install -Dm644 dev.echohello.Pidex.desktop /app/share/applications/dev.echohello.Pidex.desktop + - install -Dm644 dev.echohello.Pidex.png /app/share/icons/hicolor/256x256/apps/dev.echohello.Pidex.png + - install -Dm755 pidex.sh /app/bin/pidex + sources: + - type: file + path: dev.echohello.Pidex.metainfo.xml + - type: file + path: dev.echohello.Pidex.desktop + - type: file + path: dev.echohello.Pidex.png + - type: file + path: pidex.sh + - type: extra-data + filename: pidex.AppImage + only-arches: + - x86_64 + url: https://github.com/echohello-dev/pidex/releases/download/2026.09.28-2/pidex-linux-x86_64.AppImage + sha256: d619aa5afbc7c1cac7146135d41510ed97b7bc819e957b7aa009e2a454eaab6b + size: 126532577 + - type: script + dest-filename: apply_extra + commands: + - chmod +x pidex.AppImage + - ./pidex.AppImage --appimage-extract + - mv squashfs-root pidex diff --git a/packaging/flatpak/flathub.json b/packaging/flatpak/flathub.json new file mode 100644 index 0000000..637604e --- /dev/null +++ b/packaging/flatpak/flathub.json @@ -0,0 +1,3 @@ +{ + "only-arches": ["x86_64"] +} diff --git a/packaging/flatpak/pidex.sh b/packaging/flatpak/pidex.sh new file mode 100755 index 0000000..8ef17f6 --- /dev/null +++ b/packaging/flatpak/pidex.sh @@ -0,0 +1,2 @@ +#!/bin/sh +exec zypak-wrapper /app/extra/pidex/pidex "$@" diff --git a/scripts/release-manifests.ts b/scripts/release-manifests.ts index a394107..eeced82 100644 --- a/scripts/release-manifests.ts +++ b/scripts/release-manifests.ts @@ -61,7 +61,7 @@ export function homebrewCask(tag: string, checksums: ReleaseChecksums): string { desc "Desktop workbench for the Pi coding agent" homepage "${REPO}" - depends_on macos: :sonoma + depends_on macos: :monterey app "pidex.app" @@ -150,7 +150,7 @@ export function latestHomebrewCask(): string { desc "Desktop workbench for the Pi coding agent" homepage "${REPO}" - depends_on macos: :sonoma + depends_on macos: :monterey app "pidex.app"