Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
80fa2cc
Route telemetry through ScientFactory gateway (#43)
yaacovcorcos Jul 20, 2026
e55716c
Fix unsigned macOS release signatures (#44)
yaacovcorcos Jul 20, 2026
1d72ef9
Add consent-aware desktop analytics (#47)
yaacovcorcos Jul 20, 2026
4e4019c
Fix Claude terminal auth and connection recovery (#52)
yaacovcorcos Jul 20, 2026
c88a239
Use direct OAuth for Grok sign-in (#53)
yaacovcorcos Jul 21, 2026
8058028
Secure Scient state initialization (#48)
yaacovcorcos Jul 21, 2026
a577f50
Supervise the desktop backend lifecycle (#49)
yaacovcorcos Jul 21, 2026
e1a4d4d
Supervise desktop connection recovery (#50)
yaacovcorcos Jul 21, 2026
40dfa6c
Define safe RPC recovery policies (#51)
yaacovcorcos Jul 21, 2026
211ed85
Surface connection recovery diagnostics (#55)
yaacovcorcos Jul 21, 2026
f658bbc
Recover Codex sessions after authentication loss (#56)
yaacovcorcos Jul 21, 2026
88ac61d
Support Linux desktop development launch (#57)
yaacovcorcos Jul 21, 2026
3c04060
Fix Antigravity browser authentication (#59)
yaacovcorcos Jul 21, 2026
71da4e4
Scope desktop signing credentials by platform (#60)
yaacovcorcos Jul 21, 2026
4813299
Fix managed Antigravity updates, authentication, and dialog UX (#62)
yaacovcorcos Jul 21, 2026
b80b249
Stabilize macOS release identity (#63)
yaacovcorcos Jul 21, 2026
f55be4e
Reduce unintended macOS permission prompts (#64)
yaacovcorcos Jul 21, 2026
1eafedb
Control macOS notarization lifecycle (#65)
yaacovcorcos Jul 21, 2026
9d175d6
Promote validated main to release/stable for v0.5.9
yaacovcorcos Jul 21, 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
10 changes: 10 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,16 @@ jobs:
- name: Test Effect Windows process spawn
run: bun run --cwd apps/server test src/windowsProcessEffect.test.ts

- name: Test Windows private state initialization
run: |
bun run --cwd apps/server test src/serverPrivateDirectories.test.ts
bun run --cwd apps/desktop test src/desktopScientDataDirectories.test.ts

- name: Test Windows backend lifecycle
run: |
bun run --cwd apps/desktop test src/desktopBackendSupervisor.test.ts src/backendProcessTree.test.ts
bun run --cwd apps/server test src/desktopParentShutdown.test.ts

- name: Exercise Windows release staging
run: bun run release:smoke

Expand Down
235 changes: 117 additions & 118 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ on:
default: false
type: boolean
allow_unsigned_release:
description: "Explicitly allow unsigned desktop artifacts for this manual early-access release"
description: "Allow an unsigned Windows installer for this manual early-access release (macOS always requires signing)"
required: true
default: false
type: boolean
Expand Down Expand Up @@ -201,7 +201,7 @@ jobs:
name: Build ${{ matrix.label }}
needs: preflight
runs-on: ${{ matrix.runner }}
timeout-minutes: 30
timeout-minutes: ${{ matrix.timeout_minutes }}
strategy:
fail-fast: false
matrix:
Expand All @@ -211,21 +211,25 @@ jobs:
platform: mac
target: dmg
arch: arm64
timeout_minutes: 120
- label: macOS x64
runner: macos-15-intel
platform: mac
target: dmg
arch: x64
timeout_minutes: 120
- label: Linux x64
runner: ubuntu-24.04
platform: linux
target: AppImage
arch: x64
timeout_minutes: 30
- label: Windows x64
runner: windows-2022
platform: win
target: nsis
arch: x64
timeout_minutes: 30
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
Expand Down Expand Up @@ -253,14 +257,52 @@ jobs:
node scripts/update-release-package-versions.ts "${{ needs.preflight.outputs.version }}"
bun install --lockfile-only --ignore-scripts

- name: Build desktop artifact
- name: Build macOS desktop artifact
if: matrix.platform == 'mac'
shell: bash
env:
CSC_LINK: ${{ secrets.CSC_LINK }}
CSC_KEY_PASSWORD: ${{ secrets.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 }}
SCIENT_DESKTOP_UPDATE_REPOSITORY: ${{ needs.preflight.outputs.update_repository }}
PUBLISH_RELEASE: ${{ needs.preflight.outputs.publish_release }}
ALLOW_UNSIGNED_RELEASE: ${{ needs.preflight.outputs.unsigned_release }}
run: |
bash scripts/build-release-desktop-artifact.sh \
"${{ matrix.platform }}" \
"${{ matrix.target }}" \
"${{ matrix.arch }}" \
"${{ needs.preflight.outputs.version }}"

- name: Upload macOS notarization evidence
if: ${{ always() && matrix.platform == 'mac' }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: notarization-${{ matrix.arch }}
path: release/notarization-*.json
if-no-files-found: warn
retention-days: 30

- name: Build Linux desktop artifact
if: matrix.platform == 'linux'
shell: bash
env:
SCIENT_DESKTOP_UPDATE_REPOSITORY: ${{ needs.preflight.outputs.update_repository }}
PUBLISH_RELEASE: ${{ needs.preflight.outputs.publish_release }}
ALLOW_UNSIGNED_RELEASE: ${{ needs.preflight.outputs.unsigned_release }}
run: |
bash scripts/build-release-desktop-artifact.sh \
"${{ matrix.platform }}" \
"${{ matrix.target }}" \
"${{ matrix.arch }}" \
"${{ needs.preflight.outputs.version }}"

- name: Build Windows desktop artifact
if: matrix.platform == 'win'
shell: bash
env:
WIN_CSC_LINK: ${{ secrets.WIN_CSC_LINK }}
WIN_CSC_KEY_PASSWORD: ${{ secrets.WIN_CSC_KEY_PASSWORD }}
AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
Expand All @@ -274,119 +316,11 @@ jobs:
PUBLISH_RELEASE: ${{ needs.preflight.outputs.publish_release }}
ALLOW_UNSIGNED_RELEASE: ${{ needs.preflight.outputs.unsigned_release }}
run: |
args=(
--platform "${{ matrix.platform }}"
--target "${{ matrix.target }}"
--arch "${{ matrix.arch }}"
--build-version "${{ needs.preflight.outputs.version }}"
--verbose
)

has_all() {
for value in "$@"; do
if [[ -z "$value" ]]; then
return 1
fi
done
return 0
}

has_any() {
for value in "$@"; do
if [[ -n "$value" ]]; then
return 0
fi
done
return 1
}

if [[ "${{ matrix.platform }}" == "mac" ]]; then
apple_values=(
"$CSC_LINK"
"$CSC_KEY_PASSWORD"
"$APPLE_API_KEY"
"$APPLE_API_KEY_ID"
"$APPLE_API_ISSUER"
)
if has_all "${apple_values[@]}"; then
key_path="$RUNNER_TEMP/AuthKey_${APPLE_API_KEY_ID}.p8"
printf '%s' "$APPLE_API_KEY" > "$key_path"
export APPLE_API_KEY="$key_path"
echo "macOS signing enabled."
args+=(--signed)
elif has_any "${apple_values[@]}"; then
if [[ "$PUBLISH_RELEASE" == "true" ]]; then
echo "Public macOS releases cannot use a partial Apple signing configuration." >&2
exit 1
fi
echo "Build-only macOS signing disabled because the Apple signing configuration is incomplete."
elif [[ "$PUBLISH_RELEASE" == "true" && "$ALLOW_UNSIGNED_RELEASE" == "true" ]]; then
echo "Unsigned macOS early-access publication explicitly enabled."
elif [[ "$PUBLISH_RELEASE" == "true" ]]; then
echo "Public macOS releases require all Apple signing and notarization secrets." >&2
exit 1
else
echo "Build-only macOS signing disabled (missing one or more Apple signing secrets)."
fi
elif [[ "${{ matrix.platform }}" == "win" ]]; then
# Build-only validation may produce an unsigned installer. Public
# releases fail closed unless exactly one signing provider is complete.
certificate_values=("$WIN_CSC_LINK" "$WIN_CSC_KEY_PASSWORD")
azure_values=(
"$AZURE_TENANT_ID"
"$AZURE_CLIENT_ID"
"$AZURE_CLIENT_SECRET"
"$AZURE_TRUSTED_SIGNING_ENDPOINT"
"$AZURE_TRUSTED_SIGNING_ACCOUNT_NAME"
"$AZURE_TRUSTED_SIGNING_CERTIFICATE_PROFILE_NAME"
"$AZURE_TRUSTED_SIGNING_PUBLISHER_NAME"
)

if has_all "${certificate_values[@]}" && ! has_any "${azure_values[@]}"; then
echo "Windows signing enabled (standard Authenticode certificate)."
args+=(--signed)
elif has_all "${azure_values[@]}" && ! has_any "${certificate_values[@]}"; then
echo "Windows signing enabled (Azure Trusted Signing)."
args+=(--signed)
elif has_any "${certificate_values[@]}" || has_any "${azure_values[@]}"; then
if [[ "$PUBLISH_RELEASE" == "true" ]]; then
echo "Public Windows releases require exactly one complete signing provider: WIN_CSC_LINK plus WIN_CSC_KEY_PASSWORD, or all Azure Trusted Signing secrets." >&2
exit 1
fi
echo "Build-only Windows signing disabled because the signing configuration is incomplete or conflicting."
elif [[ "$PUBLISH_RELEASE" == "true" && "$ALLOW_UNSIGNED_RELEASE" == "true" ]]; then
echo "Unsigned Windows early-access publication explicitly enabled."
elif [[ "$PUBLISH_RELEASE" == "true" ]]; then
echo "Public Windows releases require a standard Authenticode certificate or Azure Trusted Signing." >&2
exit 1
else
echo "Build-only Windows signing disabled because no signing provider is configured."
fi
else
echo "Signing disabled for ${{ matrix.platform }}."
fi

if [[ "${{ matrix.platform }}" == "mac" && "${{ matrix.arch }}" == "x64" ]]; then
# electron-builder occasionally times out fetching x64 DMG helper bundles on GitHub-hosted macOS runners.
# Retry this narrow packaging path so transient upstream 504s do not block the whole release.
max_attempts=3
for attempt in $(seq 1 "$max_attempts"); do
if bun run dist:desktop:artifact -- "${args[@]}"; then
break
fi

if [[ "$attempt" -eq "$max_attempts" ]]; then
echo "macOS x64 desktop artifact build failed after $max_attempts attempts."
exit 1
fi

sleep_seconds=$((attempt * 15))
echo "macOS x64 desktop artifact build failed on attempt $attempt/$max_attempts. Retrying in ${sleep_seconds}s..."
sleep "$sleep_seconds"
done
else
bun run dist:desktop:artifact -- "${args[@]}"
fi
bash scripts/build-release-desktop-artifact.sh \
"${{ matrix.platform }}" \
"${{ matrix.target }}" \
"${{ matrix.arch }}" \
"${{ needs.preflight.outputs.version }}"

- name: Collect release assets
shell: bash
Expand Down Expand Up @@ -522,6 +456,8 @@ jobs:
required_assets=(
"Scient-${RELEASE_VERSION}-arm64.dmg"
"Scient-${RELEASE_VERSION}-x64.dmg"
"Scient-${RELEASE_VERSION}-arm64.zip"
"Scient-${RELEASE_VERSION}-x64.zip"
"Scient-${RELEASE_VERSION}-x64.exe"
"Scient-${RELEASE_VERSION}-x86_64.AppImage"
"latest-mac.yml"
Expand All @@ -543,6 +479,8 @@ jobs:
required_payloads=(
"Scient-${RELEASE_VERSION}-arm64.dmg"
"Scient-${RELEASE_VERSION}-x64.dmg"
"Scient-${RELEASE_VERSION}-arm64.zip"
"Scient-${RELEASE_VERSION}-x64.zip"
"Scient-${RELEASE_VERSION}-x64.exe"
"Scient-${RELEASE_VERSION}-x86_64.AppImage"
)
Expand Down Expand Up @@ -637,7 +575,7 @@ jobs:
if [[ "$UNSIGNED_RELEASE" == "true" ]]; then
printf '%s\n' \
'> [!WARNING]' \
'> This early-access release is unsigned. Windows may show an Unknown Publisher warning. On macOS, Scient downloads updates in-app and opens them in Finder for manual replacement.' \
'> This early-access release includes an unsigned Windows installer, which may show an Unknown Publisher warning. macOS artifacts remain Developer ID signed, notarized, and stapled.' \
> release-notice.md
else
: > release-notice.md
Expand Down Expand Up @@ -715,10 +653,71 @@ jobs:
exit 1
fi

verify_published_macos:
name: Verify published macOS ${{ matrix.arch }}
if: ${{ needs.preflight.outputs.publish_release == 'true' }}
needs: [preflight, release]
runs-on: ${{ matrix.runner }}
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
include:
- arch: arm64
runner: macos-14
- arch: x64
runner: macos-15-intel
steps:
- name: Checkout exact release source
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
ref: ${{ needs.preflight.outputs.ref }}

- name: Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
bun-version-file: package.json

- name: Download published macOS artifact
shell: bash
env:
GH_TOKEN: ${{ github.token }}
RELEASE_TAG: ${{ needs.preflight.outputs.tag }}
RELEASE_VERSION: ${{ needs.preflight.outputs.version }}
run: |
set -euo pipefail
mkdir -p published-macos
gh release download "$RELEASE_TAG" \
--repo "$GITHUB_REPOSITORY" \
--pattern "Scient-${RELEASE_VERSION}-${{ matrix.arch }}.dmg" \
--pattern "Scient-${RELEASE_VERSION}-${{ matrix.arch }}.zip" \
--pattern SHA256SUMS.txt \
--dir published-macos

- name: Verify checksum and delivered macOS identity
shell: bash
env:
RELEASE_VERSION: ${{ needs.preflight.outputs.version }}
run: |
set -euo pipefail
for extension in dmg zip; do
asset="Scient-${RELEASE_VERSION}-${{ matrix.arch }}.${extension}"
expected_line="$(grep -F " ${asset}" published-macos/SHA256SUMS.txt | head -n 1 || true)"
if [[ -z "$expected_line" ]]; then
echo "Published checksum manifest is missing $asset." >&2
exit 1
fi
(
cd published-macos
printf '%s\n' "$expected_line" | shasum -a 256 -c -
)
done
bun scripts/verify-mac-release-artifact.ts published-macos

finalize:
name: Finalize release
if: ${{ needs.preflight.outputs.publish_release == 'true' && vars.SCIENT_FINALIZE_RELEASE == '1' }}
needs: [preflight, release]
needs: [preflight, verify_published_macos]
runs-on: ubuntu-24.04
timeout-minutes: 10
steps:
Expand Down
5 changes: 5 additions & 0 deletions apps/desktop/resources/entitlements.appsnap.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict/>
</plist>
22 changes: 11 additions & 11 deletions apps/desktop/scripts/dev-electron.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { join } from "node:path";
import waitOn from "wait-on";

import { buildAppSnapHelper } from "./build-appsnap-helper.mjs";
import { desktopDir, resolveElectronPath } from "./electron-launcher.mjs";
import { desktopDir, resolveElectronLaunchCommand } from "./electron-launcher.mjs";

const port = Number(process.env.ELECTRON_RENDERER_PORT ?? 5733);
const devServerUrl = `http://localhost:${port}`;
Expand Down Expand Up @@ -140,18 +140,18 @@ function startApp() {
return;
}

const app = spawn(
resolveElectronPath(),
const electronCommand = resolveElectronLaunchCommand(
[`--synara-dev-root=${desktopDir}`, "dist-electron/main.js"],
{
cwd: desktopDir,
env: {
...childEnv,
VITE_DEV_SERVER_URL: devServerUrl,
},
stdio: "inherit",
},
{ development: true },
);
const app = spawn(electronCommand.electronPath, electronCommand.args, {
cwd: desktopDir,
env: {
...childEnv,
VITE_DEV_SERVER_URL: devServerUrl,
},
stdio: "inherit",
});

currentApp = app;

Expand Down
Loading
Loading