Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
d6b8fbc
feat(desktop): ship macOS x64 and Linux packages
Astro-Han Sep 1, 2026
786c19e
fix(desktop): hold the packaging descriptor to what electron-builder …
Astro-Han Sep 1, 2026
d9b57b3
fix(desktop): give the Linux packages a launchable name and a homepage
Astro-Han Sep 1, 2026
9773ef6
fix(desktop): verify the deb instead of only hashing it
Astro-Han Sep 1, 2026
9cd1c4d
ci: run the Linux release path on pull requests
Astro-Han Sep 1, 2026
059551c
ci: name the Linux check job so it is distinguishable
Astro-Han Sep 1, 2026
7ef634d
ci: drop the Linux check's cron
Astro-Han Sep 1, 2026
7f9b147
ci: hold the Linux check to the repository's lane policy
Astro-Han Sep 1, 2026
8e80192
fix(desktop): let the desktop environment recognise the running window
Astro-Han Sep 1, 2026
98cc58b
test(desktop): verify Linux as deeply as macOS and Windows
Astro-Han Sep 1, 2026
a0f955b
refactor(desktop): let the descriptor name the macOS DMG
Astro-Han Sep 1, 2026
53d7a4e
refactor(scripts): drop an identity remap and two unused exports
Astro-Han Sep 1, 2026
59cbf4f
fix(test): copy the builder configuration through JSON
Astro-Han Sep 1, 2026
01e59c2
fix(desktop): verify the update the updater chose, not a platform table
Astro-Han Sep 2, 2026
0c8eff4
fix(release): hand Finalize the published set the publish job verified
Astro-Han Sep 2, 2026
8563937
test(desktop): verify the merged Linux update feed before checksums
Astro-Han Sep 2, 2026
4219dc9
fix(ci): run the Linux harness after dependencies are installed
Astro-Han Sep 2, 2026
11a5110
test: drop a vacuous checksum guard and a hand-copied payload list
Astro-Han Sep 2, 2026
16345a9
refactor(scripts): let every packaging and verify script read the des…
Astro-Han Sep 2, 2026
14eb8e4
refactor(release): drop the restated Windows installer name and the m…
Astro-Han Sep 2, 2026
cc3c0d5
refactor(scripts): resolve a release target in one place
Astro-Han Sep 2, 2026
1c3c796
docs(scripts): state the rule behind the checksum set
Astro-Han Sep 2, 2026
2a73c63
fix(release): run the Linux verification under xvfb on every lane
Astro-Han Sep 2, 2026
630ebad
fix(desktop): resolve the local setup package without naming a peer t…
Astro-Han Sep 2, 2026
30d575b
fix(desktop): require the downloaded update to be this platform's pac…
Astro-Han Sep 2, 2026
fc10401
docs: describe the five-target Desktop in the README and release notes
Astro-Han Sep 2, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/DESKTOP_NIGHTLY.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

Desktop Nightly is an ephemeral developer snapshot, not an Apache release. It builds the current `main` commit every day so contributors can try recent Desktop changes and report problems without waiting for an ASF source-release vote.

The npm publication workflow gives each snapshot an immutable version such as `0.2.0-dev.42.20260829`. The run number is the sole ordering authority. After that exact npm version is public, it triggers Desktop Nightly with a version-only artifact; the authenticated workflow event supplies the exact source commit and upstream run. Each fresh Desktop Nightly creates a `v<version>` tag protected by the checked-in `Immutable release tags` ruleset and one GitHub draft prerelease containing the macOS and Windows packages, blockmaps, `dev-mac.yml`, `dev.yml`, and one offline Sigstore bundle. The workflow verifies every remote asset before it publishes the prerelease as non-Latest. Packaged Nightlies use the GitHub `dev` channel and verify that downloaded bytes were attested by `.github/workflows/desktop-nightly.yml` on `main`. A formal Desktop build uses the separate stable GitHub Release channel and formal product-release attestation identity.
The npm publication workflow gives each snapshot an immutable version such as `0.2.0-dev.42.20260829`. The run number is the sole ordering authority. After that exact npm version is public, it triggers Desktop Nightly with a version-only artifact; the authenticated workflow event supplies the exact source commit and upstream run. Each fresh Desktop Nightly creates a `v<version>` tag protected by the checked-in `Immutable release tags` ruleset and one GitHub draft prerelease containing the macOS, Windows, and Linux packages, blockmaps, `dev-mac.yml`, `dev.yml`, `dev-linux.yml`, `dev-linux-arm64.yml`, and one offline Sigstore bundle. macOS builds one architecture per runner and both write the same feed name, so each upload carries `dev-mac-<arch>.yml` and publication merges them into the single `dev-mac.yml` clients read. The workflow verifies every remote asset before it publishes the prerelease as non-Latest. Packaged Nightlies use the GitHub `dev` channel and verify that downloaded bytes were attested by `.github/workflows/desktop-nightly.yml` on `main`. A formal Desktop build uses the separate stable GitHub Release channel and formal product-release attestation identity.

Nightly currently uses the same application identity as the formal Desktop. Installing it replaces the existing Maka installation rather than creating a second side-by-side app. Its user data remains in the same location. Testers who need the formal build should reinstall that build before returning to the formal channel. Builds previously downloaded from `nightlies.apache.org` do not migrate automatically; testers must install the newest GitHub prerelease once, after which GitHub Nightlies update automatically.

Expand All @@ -31,8 +31,8 @@ Nightly currently uses the same application identity as the formal Desktop. Inst
2. Configure npm Trusted Publishing for `apache/maka` and `.github/workflows/npm-publication.yml`, restricted to the `npm-publication` Environment and with both `npm publish` and `npm stage publish` allowed. Do not create or store a long-lived npm token.
3. After npm Trusted Publishing is ready, set `NPM_NIGHTLY_ENABLED` to `true`, run `npm publication` from `main` with `channel=nightly`, and verify the exact npm version and `nightly` dist-tag.
4. Set `DESKTOP_NIGHTLY_ENABLED` to `true` and manually dispatch a fresh npm Nightly. Confirm that its successful run triggers `Desktop Nightly`. Do not rerun a failed attempt in place.
5. Verify that `v<version>` points to the exact source SHA and that its GitHub Release is published with Draft off, Prerelease on, Latest off, and exactly the nine expected assets. Install that prerelease on both platforms.
6. Publish one later fresh Nightly and confirm a GitHub-to-GitHub automatic and differential update on both platforms before sharing the channel with testers.
5. Verify that `v<version>` points to the exact source SHA and that its GitHub Release is published with Draft off, Prerelease on, Latest off, and exactly the expected assets, which `desktopNightlyReleaseAssetNames` defines. Install that prerelease on every packaged target.
6. Publish one later fresh Nightly and confirm a GitHub-to-GitHub automatic and differential update on every packaged target before sharing the channel with testers. Linux AppImage installs update in place; Linux deb installs ask for the privilege `dpkg` needs.

The npm schedule starts at 18:17 UTC. Before changing the npm tag, the workflow requires its run number to exceed the current `nightly` version. Desktop assembles and verifies a draft before one publish mutation; a packaging, attestation, tag, upload, or digest failure leaves no partially published GitHub Release. Never rerun a failed workflow attempt in place; dispatch a fresh npm Nightly with a newer version.

Expand Down
36 changes: 29 additions & 7 deletions .github/RELEASE_CHECKLIST.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,9 @@ gate. The workflow creates no Draft until every required artifact job succeeds.

Phase 1 requires:

- signed and notarized Apple Silicon macOS Desktop artifacts;
- signed and notarized Apple Silicon and Intel macOS Desktop artifacts;
- the unsigned Windows x64 Desktop installer and ZIP;
- the unsigned x64 and arm64 Linux AppImage and deb;
- the signed, notarized, relocatable Apple Silicon CLI/TUI ZIP;
- checksums generated after each artifact reaches its final form.

Expand Down Expand Up @@ -84,12 +85,12 @@ bytes and expected filename are not covered by that protected workflow identity.
version, and the CLI manifest exposes only the `maka` command.
4. Dispatch `Release` from the exact approved candidate tag and supply the same tag as
`source_reference_tag`. A rerun must use that same tag; never select current `main` instead.
5. Confirm `release-identity`, both Desktop matrix entries, `cli-macos-arm64`, and
5. Confirm `release-identity`, every Desktop matrix entry, `cli-macos-arm64`, and
`publish` pass. A skipped or failed required job must prevent Draft creation.
6. Confirm one Draft named `v<version>` targets the approved source SHA, identifies the ASF source
reference in its notes, is not marked as a GitHub prerelease or Latest while it remains a Draft,
and contains exactly the manifest
reported by `node scripts/product-release-artifacts.mjs list`. The manifest covers both Desktop
and contains exactly the release asset names
reported by `node scripts/product-release-artifacts.mjs list`. That list covers all three Desktop
platforms and update metadata, the standalone CLI/TUI, and their required checksums.
7. Inspect the CLI ZIP. It must contain `bin/maka`, `RELEASE.json`, `DISCLAIMER-WIP`, `LICENSE`, `NOTICE`,
`THIRD_PARTY_NOTICES.txt`, the pinned Node license, and no `bin/maka-agent`.
Expand All @@ -100,7 +101,7 @@ bytes and expected filename are not covered by that protected workflow identity.
entitlements must retain the required hardened-runtime capabilities and omit
`com.apple.security.get-task-allow`, as required by Apple's
[notarization guidance](https://developer.apple.com/documentation/security/resolving-common-notarization-issues).
9. Inspect both Desktop resource trees and confirm `git/`, `bundled-git.json`, `licenses/git/`, and
9. Inspect every Desktop resource tree and confirm `git/`, `bundled-git.json`, `licenses/git/`, and
`licenses/dugite/` are absent.

If the publish job created the product tag or Draft but failed before every asset was uploaded,
Expand Down Expand Up @@ -131,7 +132,11 @@ stable release Latest in the same GitHub operation. Do not publish or
change the Latest designation manually. A failed or rejected npm candidate requires a new product
version; never publish the Draft to work around npm state.

## Acceptance on another Apple Silicon Mac
## Acceptance on another Mac

Run this section twice: once on an Apple Silicon Mac with the `mac-arm64` DMG, and once on an Intel
Mac with the `mac-x64` DMG. The CLI/TUI ships for Apple Silicon only, so steps 4 to 7 belong to the
Apple Silicon pass.

Download the DMG, CLI ZIP, and their checksum files through a browser from the Draft. Do not move
artifacts directly from the workflow runner; the browser path supplies the real quarantine
Expand Down Expand Up @@ -168,9 +173,26 @@ Download the installer, Windows Desktop ZIP, and both checksum files through a b
7. Add a clean remote Runtime Host from the packaged Desktop app. Confirm setup installs the exact
public `maka-agent@<version>` package and the remote session completes one model turn.

## Acceptance on a Linux machine

Run this section twice: once on x64 with the `x86_64` AppImage and the `amd64` deb, and once on
arm64 with the `arm64` pair. Download both distributables and their checksum files through a browser
from the same Draft.

1. Run `sha256sum -c` for the AppImage and the deb.
2. `chmod +x` the AppImage and launch it once to confirm the portable artifact starts.
3. Install the deb with `sudo apt install ./Maka-<version>-linux-<arch>.deb` and launch Maka from the
desktop launcher entry.
4. Configure a model connection, send one prompt, and run one representative file-tool task.
5. Run one terminal task and confirm packaged `node-pty` behavior.
6. Confirm the documented Computer Use limitation remains accurate: Computer Use is not offered on
Linux.
7. Add a clean remote Runtime Host from the packaged Desktop app. Confirm setup installs the exact
public `maka-agent@<version>` package and the remote session completes one model turn.

Immediately before approving the `product-release` Environment, reverify that the approved ASF
candidate tag and convenience `v<version>` tag still resolve to the same recorded commit. Approve
only after npm verification and both independent-machine acceptance passes. If any required artifact, npm step, or
only after npm verification and every independent-machine acceptance pass. If any required artifact, npm step, or
acceptance step fails, keep the Draft unpublished, fix the issue, increment the root product
version, and run the full workflow again. Never replace an existing release identity.

Expand Down
80 changes: 54 additions & 26 deletions .github/workflows/desktop-nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,20 @@ jobs:
matrix:
include:
- platform: macos
arch: arm64
runner: macos-15
- platform: macos
arch: x64
runner: macos-15-intel
- platform: windows
arch: x64
runner: windows-2025
- platform: linux
arch: x64
runner: ubuntu-24.04
- platform: linux
arch: arm64
runner: ubuntu-24.04-arm
runs-on: ${{ matrix.runner }}
environment: nightly
timeout-minutes: 75
Expand Down Expand Up @@ -145,60 +156,69 @@ jobs:
APPLE_API_KEY: ${{ runner.temp }}/AuthKey_Maka.p8
APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }}
APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }}
run: npm run package:macos-arm64
run: npm run package:macos-${{ matrix.arch }}

- name: Notarize and verify the macOS Nightly
if: matrix.platform == 'macos'
env:
APPLE_API_KEY: ${{ runner.temp }}/AuthKey_Maka.p8
APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }}
APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }}
DMG_PATH: apps/desktop/release/Maka-${{ needs.identity.outputs.version }}-mac-arm64.dmg
run: |
# Discovered, not spelled out — see the same step in release.yml.
shopt -s nullglob
dmgs=(apps/desktop/release/*.dmg)
if [[ ${#dmgs[@]} -ne 1 ]]; then
echo "Expected exactly one DMG to notarize, found ${#dmgs[@]}" >&2
exit 1
fi
DMG_PATH="${dmgs[0]}"

xcrun notarytool submit "$DMG_PATH" \
--key "$APPLE_API_KEY" \
--key-id "$APPLE_API_KEY_ID" \
--issuer "$APPLE_API_ISSUER" \
--wait
xcrun stapler staple "$DMG_PATH"
npm run verify:macos-arm64 -- "$DMG_PATH"
npm run verify:macos -- "${{ matrix.arch }}"

- name: Package the Windows Nightly
if: matrix.platform == 'windows'
run: npm run package:windows-x64

- name: Verify the Windows Nightly
if: matrix.platform == 'windows'
run: >-
npm run verify:windows-x64 --
"apps/desktop/release/Maka-${{ needs.identity.outputs.version }}-win-x64.exe"
run: npm run verify:windows-x64 -- "${{ matrix.arch }}"

- name: Package the Linux Nightly
if: matrix.platform == 'linux'
run: npm run package:linux

- name: Ensure xvfb
if: matrix.platform == 'linux'
run: command -v xvfb-run >/dev/null 2>&1 || { sudo apt-get update && sudo apt-get install -y xvfb; }

# `xvfb-run` because the verification launches the extracted AppImage's
# renderer over CDP, the way the macOS and Windows verifications do.
- name: Verify the Linux Nightly
if: matrix.platform == 'linux'
run: xvfb-run -a npm run verify:linux -- "${{ matrix.arch }}"

- name: Stage the exact Nightly artifacts
env:
NIGHTLY_VERSION: ${{ needs.identity.outputs.version }}
STAGE_DIRECTORY: ${{ runner.temp }}/desktop-nightly
run: |
mkdir -p "$STAGE_DIRECTORY"
if [[ "${{ matrix.platform }}" = macos ]]; then
cp -- \
"apps/desktop/release/Maka-$NIGHTLY_VERSION-mac-arm64.dmg" \
"apps/desktop/release/Maka-$NIGHTLY_VERSION-mac-arm64.zip" \
"apps/desktop/release/Maka-$NIGHTLY_VERSION-mac-arm64.zip.blockmap" \
apps/desktop/release/dev-mac.yml \
"$STAGE_DIRECTORY/"
else
cp -- \
"apps/desktop/release/Maka-$NIGHTLY_VERSION-win-x64.exe" \
"apps/desktop/release/Maka-$NIGHTLY_VERSION-win-x64.exe.blockmap" \
"apps/desktop/release/Maka-$NIGHTLY_VERSION-win-x64.zip" \
apps/desktop/release/dev.yml \
"$STAGE_DIRECTORY/"
fi
node scripts/desktop-nightly.mjs stage-target \
"${{ matrix.platform }}-${{ matrix.arch }}" \
apps/desktop/release \
"$STAGE_DIRECTORY" \
"$NIGHTLY_VERSION"

- name: Preserve the verified Nightly artifacts
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: desktop-nightly-${{ matrix.platform }}
name: desktop-nightly-${{ matrix.platform }}-${{ matrix.arch }}
path: ${{ runner.temp }}/desktop-nightly
if-no-files-found: error
compression-level: 0
Expand Down Expand Up @@ -236,7 +256,7 @@ jobs:
- name: Install publisher dependencies
run: npm ci --ignore-scripts

- name: Download both verified Desktop builds
- name: Download every verified Desktop build
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
pattern: desktop-nightly-*
Expand All @@ -263,7 +283,15 @@ jobs:
ATTESTATION_BUNDLE: ${{ steps.attest.outputs.bundle-path }}
CERTIFICATE_IDENTITY: https://github.com/${{ github.repository }}/.github/workflows/desktop-nightly.yml@refs/heads/main
GH_TOKEN: ${{ github.token }}
NIGHTLY_VERSION: ${{ needs.identity.outputs.version }}
run: |
# Verify what is on disk, and prove the count matches what the target
# descriptor says was attested. The list is written to a file first
# because a process substitution hides its exit code, which would let
# a failing lister leave this step green with nothing verified.
node scripts/desktop-nightly.mjs attested-assets "$NIGHTLY_VERSION" \
> "$RUNNER_TEMP/attested-assets.txt"
expected="$(wc -l < "$RUNNER_TEMP/attested-assets.txt")"
verified=0
while IFS= read -r -d '' artifact; do
gh attestation verify "$artifact" \
Expand All @@ -273,8 +301,8 @@ jobs:
--cert-oidc-issuer https://token.actions.githubusercontent.com
verified=$((verified + 1))
done < <(find "$GITHUB_WORKSPACE/.nightly-stage/release" -maxdepth 1 -type f -print0)
if (( verified != 8 )); then
echo "Expected 8 verified Desktop Nightly subjects, found $verified" >&2
if (( verified != expected )); then
echo "Expected $expected verified Desktop Nightly subjects, found $verified" >&2
exit 1
fi

Expand Down
3 changes: 1 addition & 2 deletions .github/workflows/release-cli-finalize.yml
Original file line number Diff line number Diff line change
Expand Up @@ -235,9 +235,8 @@ jobs:
- name: Download the exact verified Release run artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
pattern: release-*-${{ needs.inspect.outputs.release_run_attempt }}
name: product-release-assets-${{ needs.inspect.outputs.release_run_attempt }}
path: ${{ runner.temp }}/product-release
merge-multiple: true
github-token: ${{ github.token }}
repository: ${{ github.repository }}
run-id: ${{ needs.inspect.outputs.release_run_id }}
Expand Down
Loading