From 87be90ffb916a1d769548df12d8cfae87be46238 Mon Sep 17 00:00:00 2001 From: abhinavgautam01 Date: Mon, 1 Jun 2026 16:25:55 +0530 Subject: [PATCH] Add macOS app wrapper packaging --- .github/workflows/release-builds.yml | 4 ++ README.md | 3 ++ docs/MACOS_APP.md | 58 ++++++++++++++++++++++++++++ docs/RELEASES.md | 9 +++++ packaging/macos/Info.plist | 36 +++++++++++++++++ packaging/macos/Stringcast | 7 ++++ packaging/macos/build_app.sh | 39 +++++++++++++++++++ 7 files changed, 156 insertions(+) create mode 100644 docs/MACOS_APP.md create mode 100644 packaging/macos/Info.plist create mode 100755 packaging/macos/Stringcast create mode 100755 packaging/macos/build_app.sh diff --git a/.github/workflows/release-builds.yml b/.github/workflows/release-builds.yml index 665f2b0..cfeda34 100644 --- a/.github/workflows/release-builds.yml +++ b/.github/workflows/release-builds.yml @@ -60,6 +60,10 @@ jobs: cp "target/release/${{ matrix.binary }}" dist/stringcast/ cp README.md RUNNING.md SPEC.md dist/stringcast/ cp -R docs dist/stringcast/ + if [ "${{ runner.os }}" = "macOS" ]; then + packaging/macos/build_app.sh "target/release/${{ matrix.binary }}" dist/macos + cp -R dist/macos/Stringcast.app dist/stringcast/ + fi tar -czf "dist/${{ matrix.archive }}" -C dist stringcast - name: Prepare Windows artifact diff --git a/README.md b/README.md index ccf4bc9..9898811 100644 --- a/README.md +++ b/README.md @@ -98,6 +98,8 @@ Download artifacts from the GitHub Actions release workflow or from GitHub Relea See [docs/RELEASES.md](docs/RELEASES.md) for artifact download and smoke-test steps. +The macOS release also includes an unsigned `Stringcast.app` wrapper. See [docs/MACOS_APP.md](docs/MACOS_APP.md) for build and testing notes. + ## Development Run the local checks: @@ -120,6 +122,7 @@ sudo apt install build-essential pkg-config libdbus-1-dev libxdo-dev libx11-dev - [RUNNING.md](RUNNING.md): developer/local run instructions. - [docs/RELEASES.md](docs/RELEASES.md): downloadable artifact instructions. +- [docs/MACOS_APP.md](docs/MACOS_APP.md): macOS app wrapper notes. - [SPEC.md](SPEC.md): product and architecture spec. - [docs/WAYLAND_POC.md](docs/WAYLAND_POC.md): experimental Linux Wayland listener notes. diff --git a/docs/MACOS_APP.md b/docs/MACOS_APP.md new file mode 100644 index 0000000..7a67e16 --- /dev/null +++ b/docs/MACOS_APP.md @@ -0,0 +1,58 @@ +# macOS App Wrapper + +Stringcast can be packaged as an unsigned `.app` bundle around the Rust CLI binary. This gives macOS a stable app identity for permissions and Keychain prompts while the runtime still uses the existing CLI internally. + +This is not a full menu-bar UI yet. Launching the app starts `stringcast run` in the background. + +## Build Locally + +From the repo root: + +```bash +cargo build --release +packaging/macos/build_app.sh +``` + +The app is written to: + +```text +dist/macos/Stringcast.app +``` + +Open it: + +```bash +open dist/macos/Stringcast.app +``` + +Stop it: + +```bash +pkill -f "Stringcast.app" +``` + +## Permissions + +macOS may ask for: + +- Accessibility +- Input Monitoring +- Keychain access + +If permissions were granted to a terminal binary before, macOS may ask again because `Stringcast.app` has a different app identity. + +## Current Limitations + +- The app is unsigned. +- There is no menu-bar UI yet. +- There is no visible quit control yet. +- Logs are not surfaced in an app window. +- Packaging does not create a DMG or installer yet. + +## Next Packaging Steps + +- Add an icon. +- Add a menu-bar process with Start/Stop/Quit controls. +- Add log/status display. +- Add code signing and notarization. +- Produce a DMG for end users. diff --git a/docs/RELEASES.md b/docs/RELEASES.md index abceba5..e70a4b8 100644 --- a/docs/RELEASES.md +++ b/docs/RELEASES.md @@ -17,6 +17,7 @@ stringcast-windows-x86_64.zip Each archive includes: - `stringcast` or `stringcast.exe` +- `Stringcast.app` in the macOS archive - `README.md` - `RUNNING.md` - `SPEC.md` @@ -75,6 +76,12 @@ Run the app: ./stringcast run ``` +Or launch the app wrapper: + +```bash +open Stringcast.app +``` + macOS may ask for: - Accessibility permission for keyboard automation. @@ -83,6 +90,8 @@ macOS may ask for: If permissions were already granted to a different terminal or binary path, macOS may still ask again for the downloaded binary. +See [MACOS_APP.md](MACOS_APP.md) for current app-wrapper limitations. + ## Linux Smoke Test Install native dependencies first. Ubuntu/Debian: diff --git a/packaging/macos/Info.plist b/packaging/macos/Info.plist new file mode 100644 index 0000000..ab8751c --- /dev/null +++ b/packaging/macos/Info.plist @@ -0,0 +1,36 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + Stringcast + CFBundleExecutable + Stringcast + CFBundleIdentifier + com.lamecoders.stringcast + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + Stringcast + CFBundlePackageType + APPL + CFBundleShortVersionString + 0.1.0 + CFBundleVersion + 0.1.0 + LSMinimumSystemVersion + 12.0 + LSUIElement + + NSHumanReadableCopyright + Copyright © 2026 Lame-Coders + NSAppleEventsUsageDescription + Stringcast checks the foreground app so it can avoid sensitive or unsupported contexts. + NSInputMonitoringUsageDescription + Stringcast listens for typed trigger commands so it can transform text in the active field. + NSAccessibilityUsageDescription + Stringcast uses accessibility permissions to copy, paste, and replace text in the active field. + + diff --git a/packaging/macos/Stringcast b/packaging/macos/Stringcast new file mode 100755 index 0000000..62564fa --- /dev/null +++ b/packaging/macos/Stringcast @@ -0,0 +1,7 @@ +#!/bin/sh +set -eu + +APP_DIR=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd) +BIN="$APP_DIR/Resources/stringcast" + +exec "$BIN" run diff --git a/packaging/macos/build_app.sh b/packaging/macos/build_app.sh new file mode 100755 index 0000000..ff8c93b --- /dev/null +++ b/packaging/macos/build_app.sh @@ -0,0 +1,39 @@ +#!/bin/sh +set -eu + +if [ "${1:-}" = "--help" ]; then + cat <<'USAGE' +usage: packaging/macos/build_app.sh [release-binary-path] [output-dir] + +Builds an unsigned Stringcast.app bundle around the Rust CLI binary. + +Defaults: + release-binary-path: target/release/stringcast + output-dir: dist/macos +USAGE + exit 0 +fi + +BIN_PATH=${1:-target/release/stringcast} +OUT_DIR=${2:-dist/macos} +APP_DIR="$OUT_DIR/Stringcast.app" +CONTENTS_DIR="$APP_DIR/Contents" +MACOS_DIR="$CONTENTS_DIR/MacOS" +RESOURCES_DIR="$CONTENTS_DIR/Resources" + +if [ ! -f "$BIN_PATH" ]; then + echo "missing binary: $BIN_PATH" >&2 + echo "run: cargo build --release" >&2 + exit 1 +fi + +rm -rf "$APP_DIR" +mkdir -p "$MACOS_DIR" "$RESOURCES_DIR" + +cp packaging/macos/Info.plist "$CONTENTS_DIR/Info.plist" +cp packaging/macos/Stringcast "$MACOS_DIR/Stringcast" +cp "$BIN_PATH" "$RESOURCES_DIR/stringcast" + +chmod +x "$MACOS_DIR/Stringcast" "$RESOURCES_DIR/stringcast" + +echo "Built $APP_DIR"