Skip to content
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
4 changes: 4 additions & 0 deletions .github/workflows/release-builds.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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.

Expand Down
58 changes: 58 additions & 0 deletions docs/MACOS_APP.md
Original file line number Diff line number Diff line change
@@ -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.
9 changes: 9 additions & 0 deletions docs/RELEASES.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand Down Expand Up @@ -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.
Expand All @@ -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:
Expand Down
36 changes: 36 additions & 0 deletions packaging/macos/Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "https://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>Stringcast</string>
<key>CFBundleExecutable</key>
<string>Stringcast</string>
<key>CFBundleIdentifier</key>
<string>com.lamecoders.stringcast</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>Stringcast</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>0.1.0</string>
<key>CFBundleVersion</key>
<string>0.1.0</string>
<key>LSMinimumSystemVersion</key>
<string>12.0</string>
<key>LSUIElement</key>
<true/>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2026 Lame-Coders</string>
<key>NSAppleEventsUsageDescription</key>
<string>Stringcast checks the foreground app so it can avoid sensitive or unsupported contexts.</string>
<key>NSInputMonitoringUsageDescription</key>
<string>Stringcast listens for typed trigger commands so it can transform text in the active field.</string>
<key>NSAccessibilityUsageDescription</key>
<string>Stringcast uses accessibility permissions to copy, paste, and replace text in the active field.</string>
</dict>
</plist>
7 changes: 7 additions & 0 deletions packaging/macos/Stringcast
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/bin/sh
set -eu

APP_DIR=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
BIN="$APP_DIR/Resources/stringcast"

exec "$BIN" run
39 changes: 39 additions & 0 deletions packaging/macos/build_app.sh
Original file line number Diff line number Diff line change
@@ -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"
Loading