Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
7ae2cdb
feat(windows): add native desktop preview and packaging
Sep 5, 2026
ca96354
fix(windows): preserve source checksums across checkouts
Sep 5, 2026
922b3a3
fix(windows): normalize worktree paths for Git
Sep 5, 2026
2eb1576
fix(windows): handle console readiness and isolated runtime setup
Sep 5, 2026
1210535
fix(windows): compile job guards in protected Unicode temp directories
Sep 5, 2026
da418ce
fix(windows): preserve compiler integrity labels through native APIs
Sep 5, 2026
575cb39
test(windows): expose native compiler security diagnostics early
Sep 5, 2026
63622fa
fix(windows): verify compiler integrity from raw security entries
Sep 5, 2026
648d478
fix(windows): use verified compiler path aliases for Unicode profiles
Sep 5, 2026
21ac3b6
fix(windows): compress compiler probes within command-line limits
Sep 5, 2026
f8f3bcb
fix(windows): finish packaged smoke after verified shutdown
Sep 5, 2026
2889326
test(windows): wait for descendant exit signal after job shutdown
Sep 5, 2026
b4e45c9
docs(windows): record verified preview installer [skip ci]
Sep 5, 2026
9f490f4
feat(windows): integrate beta.9 desktop runtime
devswha Sep 6, 2026
a905af7
fix(desktop): preserve process ownership across integration
devswha Sep 6, 2026
472d2ba
fix(desktop): scope native environment ownership to Windows
devswha Sep 6, 2026
68865fa
test(windows): use native paths and bounded SDK finalization
devswha Sep 6, 2026
9f8622c
test(windows): canonicalize SDK roots and expose retained owners
devswha Sep 6, 2026
b2e134c
fix(gjc): own embedded SDK settings and control endpoints
devswha Sep 6, 2026
6edef4a
test(gjc): classify SDK fixture support in engine manifest
devswha Sep 6, 2026
11bee00
test(windows): isolate pinned SDK file lock failures
devswha Sep 6, 2026
3a9506f
test(gjc): retain fixtures after unconfirmed SDK disposal
devswha Sep 6, 2026
044fe8d
docs(windows): record paused integration handoff
devswha Sep 6, 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
3 changes: 3 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Keep source and checksum-protected LICENSE/NOTICE bytes identical on Windows.
# Binary assets retain their bytes through Git's automatic text detection.
* text=auto eol=lf
175 changes: 175 additions & 0 deletions .github/workflows/windows.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
name: Windows desktop

on:
push:
branches:
- main
- feat/windows-desktop
pull_request:
branches:
- main
workflow_dispatch:

permissions:
contents: read

concurrency:
group: windows-desktop-${{ github.ref }}
cancel-in-progress: true

jobs:
compiler:
name: Windows compiler preflight
runs-on: windows-2022
timeout-minutes: 5
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Set up Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 22
architecture: x64
- name: Verify native compiler without npm dependencies
run: node --experimental-strip-types scripts/release/probe-windows-compiler.mjs

build:
name: Windows x64 NSIS installer
needs: compiler
runs-on: windows-2022
timeout-minutes: 60
defaults:
run:
shell: pwsh
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- name: Set up Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 22
architecture: x64
cache: npm

- name: Cache Rust dependencies
uses: Swatinem/rust-cache@49a0bdc70d2e1b713ca9e2869b211fcce03d3c1c # v2
with:
workspaces: |
native/gajae-core -> target
src-tauri -> target
cache-on-failure: true

- name: Install dependencies
run: npm ci

- name: Fetch pinned Bun runtime
run: node scripts/fetch-bun.mjs

- name: Audit dependencies
run: npm run audit

- name: Check source
id: source
run: |
npm run typecheck
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
npm run lint
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
npm run check:identity
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
npm run check:licenses
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }

- name: Test Windows build tooling
id: packaging
run: npm run test:windows -- --scripts-only

- name: Test Windows runtime
id: runtime
if: ${{ !cancelled() && steps.source.outcome == 'success' }}
run: |
npm run build:core:dev
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
npm run test:windows -- --server-only 2>&1 | Tee-Object -FilePath (Join-Path $env:RUNNER_TEMP 'gajae-runtime-windows.log')
exit $LASTEXITCODE

- name: Upload failed runtime diagnostics
if: ${{ !cancelled() && steps.runtime.outcome == 'failure' }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: windows-runtime-diagnostics
path: ${{ runner.temp }}/gajae-runtime-windows.log
retention-days: 7

- name: Verify Rust core
id: core
if: ${{ !cancelled() && steps.source.outcome == 'success' }}
run: |
npm run check:core 2>&1 | Tee-Object -FilePath (Join-Path $env:RUNNER_TEMP 'gajae-core-windows.log')
exit $LASTEXITCODE

- name: Upload failed core diagnostics
if: ${{ !cancelled() && steps.core.outcome == 'failure' }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: windows-core-diagnostics
path: ${{ runner.temp }}/gajae-core-windows.log
retention-days: 7

- name: Build payload and installer
id: build
# Gather independent Windows failures in one run. A failed core check
# still fails the job and prevents the final artifact upload.
if: ${{ !cancelled() && steps.source.outcome == 'success' && steps.packaging.outcome == 'success' }}
run: npm run desktop:build:windows

- name: Test desktop lifecycle
if: ${{ !cancelled() && steps.build.outcome == 'success' }}
run: |
cargo fmt --manifest-path src-tauri/Cargo.toml -- --check
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
cargo test --release --locked --manifest-path src-tauri/Cargo.toml --target x86_64-pc-windows-msvc

- name: Stage installer and checksum
if: ${{ !cancelled() && steps.build.outcome == 'success' }}
id: installer
run: |
$ErrorActionPreference = 'Stop'
$installers = @(Get-ChildItem 'src-tauri/target/x86_64-pc-windows-msvc/release/bundle/nsis/*-setup.exe')
if ($installers.Count -ne 1) { throw "Expected exactly one NSIS installer, found $($installers.Count)." }
$version = (Get-Content package.json -Raw | ConvertFrom-Json).version
$assetName = "gajae-app-desktop-$version-windows-x64-setup.exe"
New-Item -ItemType Directory -Path release/desktop -Force | Out-Null
Copy-Item $installers[0].FullName "release/desktop/$assetName"
$digest = (Get-FileHash "release/desktop/$assetName" -Algorithm SHA256).Hash.ToLowerInvariant()
[System.IO.File]::WriteAllText("$PWD/release/desktop/$assetName.sha256", "$digest $assetName`n", [System.Text.UTF8Encoding]::new($false))
"WINDOWS_INSTALLER=$($installers[0].FullName)" >> $env:GITHUB_ENV

- name: Verify installed payload
if: ${{ !cancelled() && steps.installer.outcome == 'success' }}
run: |
$ErrorActionPreference = 'Stop'
$installDir = Join-Path $env:RUNNER_TEMP 'Gajae Windows QA 가재'
$installer = Start-Process -FilePath $env:WINDOWS_INSTALLER -ArgumentList @('/S', "/D=$installDir") -Wait -PassThru
if ($installer.ExitCode -ne 0) { throw "NSIS install failed: $($installer.ExitCode)" }
$sidecar = Join-Path $installDir 'gajae-app-server.exe'
$payload = Join-Path $installDir 'resources/server-payload'
if (!(Test-Path $sidecar)) { throw 'Installed Node sidecar is missing.' }
if (!(Test-Path $payload)) { $payload = Join-Path $installDir 'server-payload' }
node scripts/release/smoke-windows-server.mjs --payload $payload --node $sidecar
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }

- name: Upload Windows preview installer
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: gajae-app-desktop-windows-x64
path: |
release/desktop/*-windows-x64-setup.exe
release/desktop/*-windows-x64-setup.exe.sha256
if-no-files-found: error
retention-days: 14
13 changes: 11 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ coding agent. MIT. Four runtime layers:
WebSocket, node-pty terminals. TypeScript + JS mixed, run through `tsx`.
- `native/gajae-core/` — Rust core, built to `dist-native/` by `scripts/build-rust-core.mjs`.
- `src-tauri/` — Tauri 2 desktop shell (Rust: `supervisor.rs`, `lifecycle.rs`,
`navigation.rs`); packages the server as a payload and supervises it.
`navigation.rs`, Windows Job Object owner in `windows_process.rs`); packages
the server as a payload and supervises it.

`shared/` is code shared between client and server (product identity, network hosts,
job projection protocol). `scripts/` holds build/release/verify tooling.
Expand All @@ -28,7 +29,12 @@ job projection protocol). `scripts/` holds build/release/verify tooling.
`node scripts/fetch-bun.mjs`.
- Server binds loopback by default (fail-closed; it can run shell commands).
`SERVER_PORT` defaults to 3001, Vite dev on 5173. Do not export `SERVER_PORT=0`.
- Tauri builds choke on `CI=1`: use `env -u CI npm run tauri -- build`.
- The Tauri wrapper normalizes `CI=1`/`0` to `true`/`false` for the CLI.
- Windows desktop packaging runs natively on x64 with MSVC, a Windows SDK,
and WebView2. See `docs/WINDOWS-DESKTOP.md`. Bundled Windows executables use
`.exe`; native-manifest paths always use forward slashes on every host.
- Direct Tauri CLI invocations reject `CI=1`; the repository wrapper normalizes
it for the CLI, and Linux desktop packaging clears `CI` before its build.
- Linux desktop packaging targets native `x86_64-unknown-linux-gnu`, bundles
Node **22.22.2** and Bun **1.4.0**, and needs GTK 3/WebKitGTK 4.1 plus the
prerequisites in `docs/DESKTOP-LINUX.md`. CI builds on Ubuntu 22.04/glibc 2.35;
Expand All @@ -45,6 +51,8 @@ npm run check:core # cargo fmt --check + clippy -D warnings + cargo test
npm run verify # FULL GATE: audit + typecheck + check:core + test + lint + check:identity + build
npm run test:e2e:gjc # 7 GJC wire/browser e2e tests (separate from npm test)
npm run desktop:dev # Tauri dev shell
npm run desktop:build:windows # Windows x64 payload + NSIS installer (on Windows)
npm run test:windows # focused runtime/packaging tests; build the core first
npm run server:payload:linux # Linux x64 payload + pinned runtimes
env -u CI npm run desktop:build:linux # payload + Tauri deb/AppImage + release/desktop staging
npm run smoke:packaged-server -- --linux-root <extracted-dir> # extracted deb or squashfs-root
Expand Down Expand Up @@ -192,6 +200,7 @@ is `.ts`/`.tsx`. Routing is react-router-dom 7.
- `server/GJC-LIVE-SPEC.md` — GJC provider/worker contract.
- `docs/DESKTOP-TAURI-VERIFICATION.md` — desktop packaging/verification (incl. the
human-gated notarization step).
- `docs/WINDOWS-DESKTOP.md` — Windows preview build, CI and desktop acceptance.
- `docs/DESKTOP-LINUX.md` — Linux x64 desktop prerequisites, package builds,
installation, compatibility floor, and validation procedure.
- `docs/SELF-HOST.md`, `CONTRIBUTING.md` — install/update lifecycle and PR rules.
21 changes: 12 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@
<p align="center">
<a href="https://github.com/devswha/gajae-code-app/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/devswha/gajae-code-app/actions/workflows/ci.yml/badge.svg"></a>
<a href="LICENSE"><img alt="License: MIT" src="https://img.shields.io/badge/License-MIT-yellow.svg"></a>
<a href="CHANGELOG.md"><img alt="Version 2.0.0-beta.7" src="https://img.shields.io/badge/version-2.0.0--beta.7-blue"></a>
<a href="#quick-start"><img alt="Platforms: macOS arm64 | Linux server | Linux desktop source" src="https://img.shields.io/badge/Platforms-macOS%20arm64%20%7C%20Linux%20server%20%7C%20Linux%20desktop%20source-green"></a>
<a href="https://github.com/devswha/gajae-code"><img alt="Runtime: Gajae Code SDK 0.15.6" src="https://img.shields.io/badge/Runtime-Gajae%20Code%20SDK%200.15.6-blueviolet"></a>
<a href="CHANGELOG.md"><img alt="Version 2.0.0-beta.9" src="https://img.shields.io/badge/version-2.0.0--beta.9-blue"></a>
<a href="#quick-start"><img alt="Platforms: macOS arm64 | Linux server | Linux desktop source | Windows x64 preview" src="https://img.shields.io/badge/Platforms-macOS%20arm64%20%7C%20Linux%20server%20%7C%20Linux%20desktop%20source%20%7C%20Windows%20x64%20preview-green"></a>
<a href="https://github.com/devswha/gajae-code"><img alt="Runtime: Gajae Code SDK 0.16.4" src="https://img.shields.io/badge/Runtime-Gajae%20Code%20SDK%200.16.4-blueviolet"></a>
</p>

<p align="center">
Expand All @@ -25,7 +25,7 @@
<img src="website/public/screenshots/session-review.jpg" alt="A two-turn Gajae Code App session that writes greet.py and adds a --shout flag, with the Changes tab open on the diff and a review comment waiting to be sent" width="960">
</p>

<p align="center"><em>Two turns on v2.0.0-beta.7: each turn's tool calls folded into a work block, the Changes tab showing the working tree as a diff, and a line comment waiting to become the next message.</em></p>
<p align="center"><em>Two turns in Gajae Code App: each turn's tool calls folded into a work block, the Changes tab showing the working tree as a diff, and a line comment waiting to become the next message.</em></p>


Gajae Code App is a self-hosted web and desktop interface for [Gajae Code](https://github.com/devswha/gajae-code). It drives the agent through the runtime's own SDK in an isolated worker, shows every turn as it happens, and puts a review loop between the agent's edits and your next message — on a machine you control, with credentials that never leave it.
Expand All @@ -39,21 +39,23 @@ Gajae Code App is a self-hosted web and desktop interface for [Gajae Code](https

## Quick Start

**macOS (Apple Silicon, macOS 11+) — the desktop app.** Download the DMG from [Releases](https://github.com/devswha/gajae-code-app/releases/latest), verify it, drag it to Applications, open it. Since v2.0.0-beta.7 the image is signed with a Developer ID and notarized by Apple; Gatekeeper opens it like any other app.
**macOS (Apple Silicon, macOS 11+) — the desktop app.** Download the DMG from [Releases](https://github.com/devswha/gajae-code-app/releases/latest), verify the matching checksum, drag it to Applications, and open it. The macOS release lane documents Developer ID signing and notarization.

```bash
cd ~/Downloads
shasum -a 256 -c gajae-app-desktop-2.0.0-beta.7-macos-arm64.dmg.sha256
shasum -a 256 -c gajae-app-desktop-2.0.0-beta.9-macos-arm64.dmg.sha256
```

**Linux server (x86_64, glibc 2.35+, Node.js 22) — self-host the web UI.** Unpack the server archive, run it as a per-user systemd service, reach it through a browser over an SSH tunnel or VPN.

```bash
sha256sum --check gajae-app-server-2.0.0-beta.7-linux-x64-node22.tar.gz.sha256
sha256sum --check gajae-app-server-2.0.0-beta.9-linux-x64-node22.tar.gz.sha256
```

Install, upgrade and rollback steps: [docs/INSTALL.md](docs/INSTALL.md) · [docs/SELF-HOST.md](docs/SELF-HOST.md).

**Windows x64 preview — build from source.** The Windows branch adds an NSIS installer with bundled runtimes. See [Windows setup, build and verification](docs/WINDOWS-DESKTOP.md). Preview installers are produced by the Windows desktop Actions workflow.

**Linux desktop (x86_64) — build from source.** Native Tauri `.deb` and `.AppImage`
packages bundle Node.js **22.22.2** and Bun **1.4.0**. See the
[Linux desktop guide](docs/DESKTOP-LINUX.md) for prerequisites, local builds,
Expand All @@ -74,7 +76,7 @@ npm run dev # server :3001, client :5173
npm run desktop:dev # the same, inside the Tauri desktop shell
```

The app uses the models, presets, skills and credentials of the Gajae Code installation in `~/.gjc`, and you can sign in to providers from inside the app. Linux desktop development requires the system libraries listed in the Linux guide. Intel Mac, Windows and Linux arm64 desktop builds are not available yet.
The app uses the models, presets, skills and credentials of the Gajae Code installation in `~/.gjc`, and you can sign in to providers from inside the app. Linux desktop development requires the system libraries listed in the Linux guide, and Windows x64 is available through the preview build path above. Intel Mac and Linux arm64 desktop builds are not available yet.

## Permission Modes

Expand All @@ -92,7 +94,7 @@ A card answered in one tab closes in every other viewer. Always deny is offered

| | |
|---|---|
| **Runtime** | Gajae Code SDK 0.15.6 on Bun 1.4.0, bundled, driven in an isolated worker; prompts pass through an owner-readable temp file, never a process argument |
| **Runtime** | Gajae Code SDK 0.16.4 on Bun 1.4.0, bundled, driven in an isolated worker; prompts pass through an owner-readable temp file, never a process argument |
| **Where things live** | Database, assets and cache under `~/.gajae-app`; transcripts stay in the runtime's own session files and are never copied into the app's database |
| **Network** | Loopback by default and fail-closed (it can run shell commands); cross-origin callers are rejected on HTTP and WebSocket |
| **Stack** | React 19 · Vite 7 · Tailwind 4 · Express · SQLite · a Rust core · Tauri 2 for the desktop shell |
Expand All @@ -104,6 +106,7 @@ A card answered in one tab closes in every other viewer. Always deny is offered
- [Self-hosting](docs/SELF-HOST.md) · [Install the server release](docs/INSTALL.md) · [Changelog](CHANGELOG.md)
- [Desktop packaging, signing and notarization](docs/DESKTOP-TAURI-VERIFICATION.md)
- [Linux desktop builds, installation and validation](docs/DESKTOP-LINUX.md)
- [Windows desktop preview](docs/WINDOWS-DESKTOP.md)
- [GJC provider and worker contract](server/GJC-LIVE-SPEC.md) · [Worker protocol](docs/GJC-WORKER-PROTOCOL.md)
- [Design system](DESIGN.md) · [Repository guide for agents](AGENTS.md)
- [Licensing](docs/LICENSING.md) · [Relicensing record](docs/RELICENSING.md) · [Upstream intake](docs/UPSTREAM.md)
Expand Down
8 changes: 8 additions & 0 deletions docs/DESKTOP-TAURI-VERIFICATION.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
# Tauri Desktop (macOS arm64) — Verification Record

Windows x64 has a separate [preview build and verification guide](WINDOWS-DESKTOP.md).
The acceptance records on this page apply to macOS.
Linux x86_64 `.deb`/`.AppImage` builds and their separate validation procedure
are documented in [DESKTOP-LINUX.md](DESKTOP-LINUX.md). The macOS results below
do not establish Linux package or GUI compatibility.

This page is a historical macOS verification record. The merged source currently
targets package `2.0.0-beta.9`, desktop version `0.2.3`, GJC SDK `0.16.4`, and
Bun `1.4.0`; no macOS package or interactive acceptance result for that source
tree is claimed here. Each result below remains scoped to the commit and
versions named in its own record.

> **Status (2026-07-22): beta.3 rename and reinstall QA passed; C7
> complete, C8 void, C9 complete.** The beta.3 installed-app smoke covered the
> visible rename, project/session navigation, preset and skill-command UI,
Expand Down
Loading
Loading