diff --git a/.raywonder-sync/.gitignore b/.raywonder-sync/.gitignore new file mode 100644 index 0000000..9fbbd62 --- /dev/null +++ b/.raywonder-sync/.gitignore @@ -0,0 +1,2 @@ +.local/* +!.local/.gitkeep diff --git a/.raywonder-sync/.local/.gitkeep b/.raywonder-sync/.local/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/.raywonder-sync/LAYOUT_STANDARD.md b/.raywonder-sync/LAYOUT_STANDARD.md new file mode 100644 index 0000000..ff1247b --- /dev/null +++ b/.raywonder-sync/LAYOUT_STANDARD.md @@ -0,0 +1,14 @@ +# Raywonder Repo Layout Standard + +Use a simple top-level split: + +- `apps/` for user-facing apps grouped by OS. +- `servers/` for API, signal, relay, and other backend services. + +Required starter folders: + +- `apps/macos/mac-app/` +- `apps/windows/windows-app/` +- `servers/api/` +- `servers/signal/` +- `servers/windows/` (if Windows hosts server-side roles) diff --git a/.raywonder-sync/README.md b/.raywonder-sync/README.md new file mode 100644 index 0000000..69a8bdd --- /dev/null +++ b/.raywonder-sync/README.md @@ -0,0 +1,20 @@ +# Raywonder Project Sync + +This folder links this project to the shared private `.GITHUB` automation repo. + +## Purpose +- Keep this project aligned with shared Raywonder governance/workflow tooling. +- Provide per-OS entrypoints for humans and agents. +- Keep machine-specific values local-only in `.local/`. + +## Entrypoints +- Windows: `windows/sync-from-dotgithub.bat` +- macOS: `macos/sync-from-dotgithub.sh` +- WSL/Linux: `wsl/sync-from-dotgithub.sh` + +## Local-only files +- `.local/*` is intentionally ignored by git. + +## Layout helpers +- `LAYOUT_STANDARD.md` defines the OS/app/server folder standard. +- `apply-layout.sh` and `apply-layout.bat` create the standard starter folders in the repo root. diff --git a/.raywonder-sync/apply-layout.bat b/.raywonder-sync/apply-layout.bat new file mode 100644 index 0000000..ce50a7b --- /dev/null +++ b/.raywonder-sync/apply-layout.bat @@ -0,0 +1,18 @@ +@echo off +setlocal +set "REPO=%~dp0.." + +mkdir "%REPO%\apps\macos\mac-app" 2>nul +mkdir "%REPO%\apps\windows\windows-app" 2>nul +mkdir "%REPO%\servers\api" 2>nul +mkdir "%REPO%\servers\signal" 2>nul +mkdir "%REPO%\servers\windows" 2>nul + +type nul > "%REPO%\apps\macos\mac-app\.gitkeep" +type nul > "%REPO%\apps\windows\windows-app\.gitkeep" +type nul > "%REPO%\servers\api\.gitkeep" +type nul > "%REPO%\servers\signal\.gitkeep" +type nul > "%REPO%\servers\windows\.gitkeep" + +echo Layout folders ensured in: %REPO% +exit /b 0 diff --git a/.raywonder-sync/apply-layout.sh b/.raywonder-sync/apply-layout.sh new file mode 100755 index 0000000..f332ab4 --- /dev/null +++ b/.raywonder-sync/apply-layout.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +set -euo pipefail + +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" + +mkdir -p \ + "$REPO_ROOT/apps/macos/mac-app" \ + "$REPO_ROOT/apps/windows/windows-app" \ + "$REPO_ROOT/servers/api" \ + "$REPO_ROOT/servers/signal" \ + "$REPO_ROOT/servers/windows" + +touch \ + "$REPO_ROOT/apps/macos/mac-app/.gitkeep" \ + "$REPO_ROOT/apps/windows/windows-app/.gitkeep" \ + "$REPO_ROOT/servers/api/.gitkeep" \ + "$REPO_ROOT/servers/signal/.gitkeep" \ + "$REPO_ROOT/servers/windows/.gitkeep" + +echo "Layout folders ensured in: $REPO_ROOT" diff --git a/.raywonder-sync/macos/sync-from-dotgithub.sh b/.raywonder-sync/macos/sync-from-dotgithub.sh new file mode 100755 index 0000000..692563c --- /dev/null +++ b/.raywonder-sync/macos/sync-from-dotgithub.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +set -euo pipefail + +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../.." && pwd)" +TOOLS1="$HOME/DEV/APPS/.GITHUB/raywonder-repo-bootstrap" +TOOLS2="$HOME/dev/apps/.GITHUB/raywonder-repo-bootstrap" +TOOLS="" + +if [[ -x "$TOOLS1/run-repo-bootstrap.bat" || -f "$TOOLS1/run-repo-bootstrap.bat" ]]; then + TOOLS="$TOOLS1" +elif [[ -x "$TOOLS2/run-repo-bootstrap.bat" || -f "$TOOLS2/run-repo-bootstrap.bat" ]]; then + TOOLS="$TOOLS2" +fi + +if [[ -z "$TOOLS" ]]; then + echo "Could not find raywonder-repo-bootstrap tooling." + exit 1 +fi + +# On macOS call PowerShell updater directly if available; otherwise do report-only. +PS_SCRIPT="$TOOLS/scripts/pull_and_fix_repo.ps1" +if command -v pwsh >/dev/null 2>&1; then + pwsh -NoProfile -ExecutionPolicy Bypass -File "$PS_SCRIPT" -RepoRoot "$REPO_ROOT" +else + echo "pwsh not found; skipping PowerShell repo update." +fi diff --git a/.raywonder-sync/windows/sync-from-dotgithub.bat b/.raywonder-sync/windows/sync-from-dotgithub.bat new file mode 100644 index 0000000..5386e60 --- /dev/null +++ b/.raywonder-sync/windows/sync-from-dotgithub.bat @@ -0,0 +1,14 @@ +@echo off +setlocal +set "REPO=%~dp0..\..\.." +set "TOOLS=%USERPROFILE%\git\raywonder\.github\raywonder-repo-bootstrap" +if not exist "%TOOLS%\run-repo-bootstrap.bat" set "TOOLS=%USERPROFILE%\dev\apps\.GITHUB\raywonder-repo-bootstrap" +if not exist "%TOOLS%\run-repo-bootstrap.bat" ( + echo Could not find raywonder-repo-bootstrap tooling. + echo Expected in one of: + echo %USERPROFILE%\git\raywonder\.github\raywonder-repo-bootstrap + echo %USERPROFILE%\dev\apps\.GITHUB\raywonder-repo-bootstrap + exit /b 1 +) +call "%TOOLS%\run-repo-bootstrap.bat" "%REPO%" +exit /b %errorlevel% diff --git a/.raywonder-sync/wsl/sync-from-dotgithub.sh b/.raywonder-sync/wsl/sync-from-dotgithub.sh new file mode 100755 index 0000000..37b0903 --- /dev/null +++ b/.raywonder-sync/wsl/sync-from-dotgithub.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +set -euo pipefail + +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../.." && pwd)" +TOOLS1="/mnt/c/Users/$USER/git/raywonder/.github/raywonder-repo-bootstrap" +TOOLS2="/mnt/c/Users/$USER/dev/apps/.GITHUB/raywonder-repo-bootstrap" +TOOLS="" + +if [[ -f "$TOOLS1/run-repo-update.bat" ]]; then + TOOLS="$TOOLS1" +elif [[ -f "$TOOLS2/run-repo-update.bat" ]]; then + TOOLS="$TOOLS2" +fi + +if [[ -z "$TOOLS" ]]; then + echo "Could not find raywonder-repo-bootstrap tooling." + exit 1 +fi + +if command -v powershell.exe >/dev/null 2>&1; then + powershell.exe -NoProfile -ExecutionPolicy Bypass -File "$(wslpath -w "$TOOLS/scripts/pull_and_fix_repo.ps1")" -RepoRoot "$(wslpath -w "$REPO_ROOT")" +else + echo "powershell.exe not found in WSL PATH; skipping update." +fi diff --git a/build.py b/build.py index 783bd10..deb8501 100644 --- a/build.py +++ b/build.py @@ -6,6 +6,7 @@ import sys import shutil import tempfile +import argparse import platform as platform_mod from pathlib import Path @@ -241,7 +242,7 @@ def create_windows_zip(output_dir: Path, app_dir: Path) -> Path: return zip_path -def build_macos(script_dir: Path, output_dir: Path) -> tuple: +def build_macos(script_dir: Path, output_dir: Path, target_arch: str = "native") -> tuple: """Build for macOS using PyInstaller. Returns: @@ -279,6 +280,9 @@ def build_macos(script_dir: Path, output_dir: Path) -> tuple: f"--osx-bundle-identifier={bundle_id}", ] + if target_arch != "native": + cmd.extend(["--target-arch", target_arch]) + # Add hidden imports for imp in get_hidden_imports(): cmd.extend(["--hidden-import", imp]) @@ -293,7 +297,8 @@ def build_macos(script_dir: Path, output_dir: Path) -> tuple: # Add main script cmd.append(str(main_script)) - print(f"Building {APP_NAME} v{APP_VERSION} for macOS...") + arch_label = platform_mod.machine() if target_arch == "native" else target_arch + print(f"Building {APP_NAME} v{APP_VERSION} for macOS ({arch_label})...") print(f"Output: {output_dir}") print() @@ -337,7 +342,7 @@ def build_macos(script_dir: Path, output_dir: Path) -> tuple: sign_macos_app(app_path) # Create DMG - dmg_path = create_macos_dmg(output_dir, app_path) + dmg_path = create_macos_dmg(output_dir, app_path, target_arch=target_arch) return True, dmg_path @@ -361,9 +366,10 @@ def sign_macos_app(app_path: Path): print(f"Code signing warning: {result.stderr}") -def create_macos_dmg(output_dir: Path, app_path: Path) -> Path: +def create_macos_dmg(output_dir: Path, app_path: Path, target_arch: str = "native") -> Path: """Create a DMG disk image for macOS distribution.""" - dmg_name = f"{APP_NAME}-{APP_VERSION}.dmg" + arch_suffix = "" if target_arch == "native" else f"-{target_arch}" + dmg_name = f"{APP_NAME}-{APP_VERSION}{arch_suffix}.dmg" dmg_path = output_dir / dmg_name if dmg_path.exists(): @@ -408,12 +414,26 @@ def create_macos_dmg(output_dir: Path, app_path: Path) -> Path: def main(): """Build FastGH executable using PyInstaller.""" + parser = argparse.ArgumentParser(description="Build FastGH desktop artifacts") + parser.add_argument( + "--output-dir", + default=str(Path.home() / "app_dist" / APP_NAME), + help="Output directory for build artifacts (default: ~/app_dist/FastGH)" + ) + parser.add_argument( + "--mac-arch", + choices=["native", "x86_64", "arm64", "universal2"], + default="native", + help="macOS target architecture for PyInstaller build (default: native)" + ) + args = parser.parse_args() + script_dir = Path(__file__).parent.resolve() platform = get_platform() print(f"Detected platform: {platform}") - output_dir = Path.home() / "app_dist" / APP_NAME + output_dir = Path(args.output_dir).expanduser().resolve() print(f"Building {APP_NAME} v{APP_VERSION} with PyInstaller...") print(f"Output: {output_dir}") @@ -422,7 +442,7 @@ def main(): if platform == "windows": success, artifact_path = build_windows(script_dir, output_dir) elif platform == "macos": - success, artifact_path = build_macos(script_dir, output_dir) + success, artifact_path = build_macos(script_dir, output_dir, target_arch=args.mac_arch) else: print(f"Unsupported platform: {platform}") sys.exit(1)