Skip to content
This repository was archived by the owner on Jan 13, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 7 additions & 1 deletion .claude/settings.local.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,13 @@
"Bash(git show:*)",
"WebFetch(domain:stackoverflow.com)",
"WebFetch(domain:www.electronjs.org)",
"WebFetch(domain:www.electron.build)"
"WebFetch(domain:www.electron.build)",
"Bash(cargo test)",
"Bash(cargo test:*)",
"Bash(bun:*)",
"Bash(cargo clippy:*)",
"Bash(cargo clean:*)",
"Bash(awk:*)"
],
"deny": [],
"ask": []
Expand Down
9 changes: 6 additions & 3 deletions .github/workflows/ci-controller.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,19 @@ name: CI Controller
on:
push:
branches:
- '**'
- 'main'
- 'dev'
pull_request:
branches:
- main
- dev
- '**'

jobs:
run-tests:
uses: ./.github/workflows/test-runner.yml

native-build-check:
uses: ./.github/workflows/native-build-check.yml

# This job ONLY runs for pushes to 'dev' and 'main'
deploy-server:
needs: run-tests
Expand Down
74 changes: 74 additions & 0 deletions .github/workflows/native-build-check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
name: Native Build Check

on:
workflow_call:

jobs:
build-check-mac:
runs-on: macos-latest

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
targets: 'x86_64-apple-darwin,aarch64-apple-darwin'

- name: Cache Rust dependencies
uses: actions/cache@v4
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
native/target/
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-

- name: Verify native binaries compile (x86_64)
working-directory: native
run: cargo build --workspace --release --target x86_64-apple-darwin

- name: Verify native binaries compile (aarch64)
working-directory: native
run: cargo build --workspace --release --target aarch64-apple-darwin

build-check-windows:
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Install build dependencies
run: |
sudo apt-get update
sudo apt-get install -y mingw-w64

- name: Set up Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
targets: 'x86_64-pc-windows-gnu'

- name: Cache Rust dependencies
uses: actions/cache@v4
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
native/target/
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-

- name: Verify native binaries compile (Windows)
working-directory: native
run: cargo build --workspace --release --target x86_64-pc-windows-gnu
6 changes: 6 additions & 0 deletions .github/workflows/test-runner.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,9 @@ jobs:

- name: Check code linting
run: bun lint:app

- name: Check Rust formatting
run: bun format:native

- name: Check Rust linting
run: bun lint:native
83 changes: 80 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,89 @@ Main development branch: `dev`
- Dev: `bun dev` (starts electron-vite dev with watch)
- Server: `docker compose up --build` (run from server directory)
- Build: `bun build:app:mac` or `bun build:app:windows`
- Test: `bun runAllTests` (runs both lib and server tests)
- Test: `bun runAllTests` (runs lib, server, and native tests)
- Lib tests: `bun runLibTests`
- Server tests: `bun runServerTests`
- Lint: `bun lint` (check) or `bun lint:fix` (fix)
- Native tests: `bun runNativeTests` (or see "Native Binary Tests" section)
- Lint:
- TypeScript: `bun lint` (check) or `bun lint:fix` (fix)
- Rust: `bun lint:native` (check) or `bun lint:fix:native` (fix)
- Type check: `bun type-check`
- Format: `bun format` (check) or `bun format:fix` (fix)
- Format:
- TypeScript: `bun format` (check) or `bun format:fix` (fix)
- Rust: `bun format:native` (check) or `bun format:fix:native` (fix)

## Native Binary Tests

The `native/` directory contains Rust binaries that power the app's core functionality. The modules are organized as a Cargo workspace, allowing you to test and build all modules with a single command.

### Running Tests

Test all native modules:
```bash
cd native
cargo test --workspace
```

Or use the npm script:
```bash
bun runNativeTests
```

Test a single module:
```bash
cd native/global-key-listener
cargo test
```

### Native Modules

- `global-key-listener` - Keyboard event capture and hotkey management
- `audio-recorder` - Audio recording with sample rate conversion
- `text-writer` - Cross-platform text input simulation
- `active-application` - Active window detection
- `selected-text-reader` - Selected text extraction

### Linting and Formatting

Rust code follows standard formatting and linting rules defined in `native/`:
- **rustfmt.toml** - Code formatting configuration (100 char width, Unix line endings)
- **clippy.toml** - Linter configuration (cognitive complexity threshold)
- **Cargo.toml** - Workspace-level lint rules (pedantic + nursery warnings)

Run checks locally:
```bash
# Check formatting
bun format:native

# Auto-fix formatting
bun format:fix:native

# Check lints
bun lint:native

# Auto-fix lints (where possible)
bun lint:fix:native
```

### CI/CD

Native tests and builds are integrated into the existing CI workflows:

**Tests** (`.github/workflows/test-runner.yml`):
- Unit tests run on macOS runner (OS-agnostic tests)
- Runs automatically via `bun runAllTests` on all pushes and PRs
- Executed as part of the main CI controller workflow

**Compilation Checks** (`.github/workflows/native-build-check.yml`):
- macOS: Verifies compilation for x86_64 and aarch64 architectures
- Windows: Verifies cross-compilation for x86_64-pc-windows-gnu
- Runs automatically on all pushes and PRs via the CI controller
- Ensures binaries compile correctly for both platforms before merging

**Release Builds** (`.github/workflows/build.yml`):
- Full release compilation happens during tagged releases
- Also includes compilation verification before packaging

## Code Style Preferences

Expand Down
9 changes: 7 additions & 2 deletions build-app.sh
Original file line number Diff line number Diff line change
Expand Up @@ -107,13 +107,18 @@ build_native_modules() {

case $platform in
"mac")
./build-binaries.sh --mac --universal
# Build for both architectures for release
./build-binaries.sh --mac
./build-binaries.sh --mac --x64
;;
"windows")
./build-binaries.sh --windows
;;
"all")
./build-binaries.sh --all --universal
# Build for all platforms and architectures for release
./build-binaries.sh --mac
./build-binaries.sh --mac --x64
./build-binaries.sh --windows
;;
*)
print_error "Invalid platform: $platform. Use 'mac', 'windows', or 'all'"
Expand Down
111 changes: 49 additions & 62 deletions build-binaries.sh
Original file line number Diff line number Diff line change
Expand Up @@ -22,81 +22,62 @@ print_error() {
echo -e "${RED}Error:${NC} $1" >&2
}

# --- This function builds a single Rust native module ---
build_native_module() {
local module_name=$1
if [ ! -d "native/$module_name" ]; then
print_error "Directory native/$module_name not found. Skipping."
return
fi
# --- Build the entire native workspace ---
build_native_workspace() {
print_status "Building native workspace..."

print_status "Building module: ${module_name}"

# Change into the module's directory
cd "native/$module_name"
# Change into the native workspace directory
cd "native"

# Install dependencies
print_info "Installing dependencies for $module_name..."

# Check if we're compiling on a Windows machine
compiling_on_windows=false
if [[ "$OSTYPE" == "msys" ]] || [[ "$OSTYPE" == "win32" ]] || [[ "$OS" == "Windows_NT" ]]; then
compiling_on_windows=true
fi


# Install dependencies
print_info "Installing dependencies for workspace..."
cargo fetch

# --- macOS Build ---
if [ "$BUILD_MAC" = true ]; then
print_info "Building macOS binaries for $module_name..."

# Build for Intel
print_info "Building for x86_64-apple-darwin (Intel)..."
cargo build --release --target x86_64-apple-darwin

# Build for Apple Silicon
print_info "Building for aarch64-apple-darwin (Apple Silicon)..."
cargo build --release --target aarch64-apple-darwin

# If --universal flag is passed, create a single binary for both architectures
if [[ " ${ARGS[*]} " == *" --universal "* ]]; then
print_info "Creating Universal macOS binary for $module_name..."

local universal_dir="target/universal"
mkdir -p "$universal_dir"

lipo -create \
"target/x86_64-apple-darwin/release/$module_name" \
"target/aarch64-apple-darwin/release/$module_name" \
-output "$universal_dir/$module_name"

print_info "Universal binary created at $universal_dir/$module_name"
# Determine target architecture (default to arm64)
local mac_target="aarch64-apple-darwin"
local arch_name="Apple Silicon (arm64)"

if [[ " ${ARGS[*]} " == *" --x64 "* ]]; then
mac_target="x86_64-apple-darwin"
arch_name="Intel (x64)"
fi

print_status "Renaming Rust target directories for electron-builder..."
# This aligns the directory names with electron-builder's {arch} variable.
print_info "Building macOS binaries for entire workspace ($arch_name)..."
cargo build --release --workspace --target "$mac_target"

rm -rf "target/arm64-apple-darwin"
rm -rf "target/x64-apple-darwin"
mv "target/aarch64-apple-darwin" "target/arm64-apple-darwin"
mv "target/x86_64-apple-darwin" "target/x64-apple-darwin"
# Create symlinks for electron-builder compatibility
if [ "$mac_target" = "aarch64-apple-darwin" ]; then
print_info "Creating symlink: arm64-apple-darwin -> aarch64-apple-darwin"
ln -sfn aarch64-apple-darwin target/arm64-apple-darwin
else
print_info "Creating symlink: x64-apple-darwin -> x86_64-apple-darwin"
ln -sfn x86_64-apple-darwin target/x64-apple-darwin
fi
fi

# --- Windows Build ---
if [ "$BUILD_WINDOWS" = true ]; then
print_info "Building Windows binary for $module_name..."
print_info "Building Windows binaries for entire workspace..."

# Use GNU target (more reliable than MSVC)
if [ "$compiling_on_windows" = true ]; then
cargo +stable-x86_64-pc-windows-gnu build --release --target x86_64-pc-windows-gnu
cargo +stable-x86_64-pc-windows-gnu build --release --workspace --target x86_64-pc-windows-gnu
else
# Cross-compile from macOS/Linux using default toolchain
cargo build --release --target x86_64-pc-windows-gnu
cargo build --release --workspace --target x86_64-pc-windows-gnu
fi
fi

# Return to the project root for the next module
cd ../..
# Return to the project root
cd ..
}


Expand Down Expand Up @@ -127,15 +108,26 @@ fi
# If no platform flags are provided, print usage and exit.
if [ "$BUILD_MAC" = false ] && [ "$BUILD_WINDOWS" = false ]; then
print_error "No platform specified. Use --mac, --windows, or --all."
echo "Usage: $0 [--mac] [--windows] [--all] [--universal]"
echo "Usage: $0 [--mac] [--windows] [--all] [--x64]"
echo ""
echo "Options:"
echo " --mac Build for macOS (defaults to arm64, use --x64 for Intel)"
echo " --windows Build for Windows"
echo " --all Build for all platforms"
echo " --x64 Build for x64/Intel instead of arm64 (macOS only)"
exit 1
fi

# Add required Rust targets
if [ "$BUILD_MAC" = true ]; then
print_status "Adding macOS targets..."
rustup target add x86_64-apple-darwin
rustup target add aarch64-apple-darwin
# Determine which macOS target to add
if [[ " ${ARGS[*]} " == *" --x64 "* ]]; then
print_status "Adding macOS x64 target..."
rustup target add x86_64-apple-darwin
else
print_status "Adding macOS arm64 target..."
rustup target add aarch64-apple-darwin
fi
fi
if [ "$BUILD_WINDOWS" = true ]; then
print_status "Adding Windows target..."
Expand Down Expand Up @@ -175,12 +167,7 @@ if [ "$BUILD_WINDOWS" = true ]; then
fi


# --- Build all native modules ---
build_native_module "global-key-listener"
build_native_module "audio-recorder"
build_native_module "text-writer"
build_native_module "active-application"
build_native_module "selected-text-reader"

# --- Build the native workspace ---
build_native_workspace

print_status "All native module builds completed successfully!"
print_status "Native workspace build completed successfully!"
Loading