Add reusable skill for self-contained macOS web app wrappers
This commit is contained in:
parent
19fa3d7371
commit
733a038638
72
skills/macos-selfcontained-webapp/SKILL.md
Normal file
72
skills/macos-selfcontained-webapp/SKILL.md
Normal file
@ -0,0 +1,72 @@
|
||||
---
|
||||
name: macos-selfcontained-webapp
|
||||
description: "Build or refactor a project so a web app runs as a self-contained macOS app: embedded local backend binary + SwiftUI/WKWebView shell + packaging scripts. Use when a user has web logic and wants no external browser, no separate web-code install, local execution from inside .app, and repeatable DMG packaging."
|
||||
---
|
||||
|
||||
# macOS Self-Contained Web App
|
||||
|
||||
## Outcome
|
||||
Deliver one installable macOS app that:
|
||||
- launches an embedded backend executable from app resources
|
||||
- opens the web UI only inside `WKWebView`
|
||||
- persists settings locally and supports native-to-web sync
|
||||
- can be packaged as a DMG
|
||||
|
||||
## Layout Standard
|
||||
Use this layout for new projects:
|
||||
- `web/` for web backend source (`app.py`, modules, requirements)
|
||||
- `mac/<AppName>Mac/` for Xcode project and SwiftUI shell
|
||||
- `scripts/` for build and packaging automation
|
||||
- `docs/` for architecture and onboarding docs
|
||||
|
||||
For existing repos, avoid destructive renames unless explicitly requested. Add compatibility paths or migration commits in small steps.
|
||||
|
||||
Detailed naming guidance: `references/layout-and-naming.md`
|
||||
|
||||
## Workflow
|
||||
1. Inventory existing architecture.
|
||||
- Identify backend entrypoint, runtime dependencies, and static/resource files.
|
||||
- Confirm current launch mode and where browser auto-open is happening.
|
||||
|
||||
2. Create embedded backend launcher.
|
||||
- Add a thin launcher (`backend_embedded_launcher.py` or equivalent) that starts the web server on `127.0.0.1` and reads port from env (for example `MANESH_TRADER_PORT`).
|
||||
- Ensure browser auto-open is disabled.
|
||||
|
||||
3. Build backend into a single executable.
|
||||
- Add `scripts/build_embedded_backend.sh` that compiles backend into a one-file executable and copies it into the mac target resource folder.
|
||||
- Include all required web files/modules in build inputs.
|
||||
|
||||
4. Implement SwiftUI host shell.
|
||||
- Use `@Observable` host state (no `ObservableObject`/Combine).
|
||||
- Start/stop backend process, detect available local port, and handle retries.
|
||||
- Render URL in `WKWebView` only.
|
||||
- Keep app responsive when backend fails and surface actionable status.
|
||||
|
||||
5. Define settings sync contract.
|
||||
- Use shared settings file (for example `~/.<app>/settings.json`) as source of truth.
|
||||
- Normalize settings both in web app and native app.
|
||||
- Pass effective settings via URL query params on launch/reload/restart.
|
||||
- Keep onboarding limited to starter fields; preserve advanced fields.
|
||||
|
||||
6. Automate packaging.
|
||||
- Add `scripts/build_selfcontained_mac_app.sh` to build embedded backend then Xcode app.
|
||||
- Add `scripts/create_installer_dmg.sh` for distributable DMG.
|
||||
|
||||
7. Validate.
|
||||
- Python syntax: `python -m py_compile` on web entrypoint.
|
||||
- Xcode build: `xcodebuild ... build`.
|
||||
- Runtime check: no external browser opens, webview loads locally, settings persist across relaunch.
|
||||
|
||||
## Required Deliverables
|
||||
- Embedded backend build script
|
||||
- macOS app host that launches backend + WKWebView
|
||||
- Shared settings sync path
|
||||
- README section for local build + DMG workflow
|
||||
- Verified build commands and final artifact locations
|
||||
|
||||
## References
|
||||
- Layout and migration rules: `references/layout-and-naming.md`
|
||||
- Implementation blueprint and command templates: `references/implementation-blueprint.md`
|
||||
|
||||
## Bundled Script
|
||||
Use `scripts/scaffold_web_mac_layout.sh` to create a new standardized folder skeleton for fresh projects.
|
||||
4
skills/macos-selfcontained-webapp/agents/openai.yaml
Normal file
4
skills/macos-selfcontained-webapp/agents/openai.yaml
Normal file
@ -0,0 +1,4 @@
|
||||
interface:
|
||||
display_name: "macOS Self-Contained Web App"
|
||||
short_description: "Embed web backend in local Mac app."
|
||||
default_prompt: "Create or refactor this project into a self-contained macOS app wrapper for a local web backend running inside WKWebView."
|
||||
@ -0,0 +1,69 @@
|
||||
# Implementation Blueprint
|
||||
|
||||
## Backend Build Script (Python Example)
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
PYTHON_BIN="$ROOT_DIR/.venv/bin/python"
|
||||
APP_NAME="TraderBackend"
|
||||
BUILD_ROOT="$ROOT_DIR/dist-backend-build"
|
||||
DIST_PATH="$BUILD_ROOT/dist"
|
||||
WORK_PATH="$BUILD_ROOT/build"
|
||||
SPEC_PATH="$BUILD_ROOT/spec"
|
||||
TARGET_DIR="$ROOT_DIR/mac/TraderMac/TraderMac/EmbeddedBackend"
|
||||
|
||||
mkdir -p "$DIST_PATH" "$WORK_PATH" "$SPEC_PATH" "$TARGET_DIR"
|
||||
|
||||
"$PYTHON_BIN" -m pip install -q pyinstaller
|
||||
|
||||
"$PYTHON_BIN" -m PyInstaller \
|
||||
--noconfirm --clean --onefile \
|
||||
--name "$APP_NAME" \
|
||||
--distpath "$DIST_PATH" \
|
||||
--workpath "$WORK_PATH" \
|
||||
--specpath "$SPEC_PATH" \
|
||||
--add-data "$ROOT_DIR/web/app.py:." \
|
||||
--add-data "$ROOT_DIR/web/<module_dir>:<module_dir>" \
|
||||
"$ROOT_DIR/web/backend_embedded_launcher.py"
|
||||
|
||||
cp "$DIST_PATH/$APP_NAME" "$TARGET_DIR/$APP_NAME"
|
||||
chmod +x "$TARGET_DIR/$APP_NAME"
|
||||
```
|
||||
|
||||
## SwiftUI Host Requirements
|
||||
- Use `@Observable` host object.
|
||||
- Compute `serverURL` from host/port + query items.
|
||||
- Start backend once on appear; stop on disappear.
|
||||
- Render backend URL in `WKWebView`.
|
||||
- Retry provisional load failure after short delay.
|
||||
- Keep debug controls behind `#if DEBUG`.
|
||||
|
||||
## Settings Sync Contract
|
||||
- Shared path: `~/.<app>/settings.json`
|
||||
- Normalize every field on web and native sides.
|
||||
- Load shared file before app launch.
|
||||
- Push normalized fields as query params when launching/reloading webview.
|
||||
- Persist setup-sheet changes back to shared file.
|
||||
|
||||
## Packaging Commands
|
||||
- Build app:
|
||||
|
||||
```bash
|
||||
./scripts/build_selfcontained_mac_app.sh
|
||||
```
|
||||
|
||||
- Create DMG:
|
||||
|
||||
```bash
|
||||
APP_BUNDLE_PATH="dist-mac/<timestamp>/<AppName>Mac.app" ./scripts/create_installer_dmg.sh
|
||||
```
|
||||
|
||||
## Verification Checklist
|
||||
- No external browser window opens.
|
||||
- App starts with embedded backend from app resources.
|
||||
- `WKWebView` loads local URL.
|
||||
- Settings persist across relaunch and remain in sync.
|
||||
- DMG installs and runs on a second machine.
|
||||
@ -0,0 +1,48 @@
|
||||
# Layout And Naming
|
||||
|
||||
## Canonical Structure
|
||||
|
||||
```text
|
||||
<repo-root>/
|
||||
web/
|
||||
app.py
|
||||
<web modules>
|
||||
requirements.txt
|
||||
mac/
|
||||
<AppName>Mac/
|
||||
<AppName>Mac.xcodeproj/
|
||||
<AppName>Mac/
|
||||
ContentView.swift
|
||||
<AppName>MacApp.swift
|
||||
EmbeddedBackend/
|
||||
<AppName>Backend
|
||||
scripts/
|
||||
build_embedded_backend.sh
|
||||
build_selfcontained_mac_app.sh
|
||||
create_installer_dmg.sh
|
||||
docs/
|
||||
architecture.md
|
||||
onboarding.md
|
||||
```
|
||||
|
||||
## Naming Rules
|
||||
- Repo: lowercase hyphenated (`trader-desktop-shell`).
|
||||
- macOS app target/project: PascalCase with `Mac` suffix (`TraderMac`).
|
||||
- Embedded backend binary: PascalCase + `Backend` (`TraderBackend`).
|
||||
- Settings directory: lowercase snake or kebab (`~/.trader_app`).
|
||||
- Environment port var: uppercase snake (`TRADER_PORT`).
|
||||
|
||||
## Migration Rules For Existing Projects
|
||||
1. Do not rename everything in one commit.
|
||||
2. First, add new folders and compatibility references.
|
||||
3. Move scripts and docs next.
|
||||
4. Move web source only after build scripts are updated.
|
||||
5. Rename Xcode project/target last, with a dedicated verification commit.
|
||||
|
||||
## Commit Strategy
|
||||
1. `chore(layout): add canonical folders`
|
||||
2. `build(backend): add embedded binary build`
|
||||
3. `feat(mac-shell): host local backend in webview`
|
||||
4. `feat(sync): add shared settings contract`
|
||||
5. `build(packaging): add self-contained app + dmg scripts`
|
||||
6. `chore(rename): finalize naming migration`
|
||||
41
skills/macos-selfcontained-webapp/scripts/scaffold_web_mac_layout.sh
Executable file
41
skills/macos-selfcontained-webapp/scripts/scaffold_web_mac_layout.sh
Executable file
@ -0,0 +1,41 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
if [[ $# -lt 2 ]]; then
|
||||
echo "Usage: $0 <repo-root> <app-name-pascal>"
|
||||
echo "Example: $0 ~/Code/trader-app Trader"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
REPO_ROOT="$1"
|
||||
APP_NAME="$2"
|
||||
MAC_APP_NAME="${APP_NAME}Mac"
|
||||
BACKEND_NAME="${APP_NAME}Backend"
|
||||
|
||||
mkdir -p "$REPO_ROOT/web"
|
||||
mkdir -p "$REPO_ROOT/mac/$MAC_APP_NAME/$MAC_APP_NAME/EmbeddedBackend"
|
||||
mkdir -p "$REPO_ROOT/scripts"
|
||||
mkdir -p "$REPO_ROOT/docs"
|
||||
|
||||
cat > "$REPO_ROOT/docs/architecture.md" <<DOC
|
||||
# ${APP_NAME} Architecture
|
||||
|
||||
- web backend source: ./web
|
||||
- mac shell source: ./mac/${MAC_APP_NAME}
|
||||
- embedded backend binary: ./mac/${MAC_APP_NAME}/${MAC_APP_NAME}/EmbeddedBackend/${BACKEND_NAME}
|
||||
DOC
|
||||
|
||||
cat > "$REPO_ROOT/scripts/README.build.md" <<DOC
|
||||
# Build Script Placeholders
|
||||
|
||||
Add:
|
||||
- build_embedded_backend.sh
|
||||
- build_selfcontained_mac_app.sh
|
||||
- create_installer_dmg.sh
|
||||
DOC
|
||||
|
||||
echo "Created layout for ${APP_NAME}:"
|
||||
echo "- $REPO_ROOT/web"
|
||||
echo "- $REPO_ROOT/mac/$MAC_APP_NAME"
|
||||
echo "- $REPO_ROOT/scripts"
|
||||
echo "- $REPO_ROOT/docs"
|
||||
Loading…
Reference in New Issue
Block a user