ProleStatus: app-window default, light splash restored, status bar controls; endpoint config via properties; build + docs

- Default to Application Window mode with full app menu; status bar overlay remains available
- Restore clickable startup Splash Tip (5s) with animated GIF and live counter; use light theme (Aqua)
- Status bar item: monospaced "P" icon; left click shows overlay (status mode) or main window (app mode)
- Overlay: add Maximize button (□) to toggle back to main window; keep click‑through elsewhere
- Global hotkey Cmd+Opt+Shift+P toggles modes; Prole menu item mirrors the same toggle and updates title dynamically
- Application menu (Prole): Show Status Bar / Show Main Window (contextual), Refresh Now, Quit
- Application Window layout: non‑scrolling, vertical 1‑line rows (svc, k3s aggregate, local) with top‑right timestamp; bottom‑left controls (⟳ Refresh, _ Minimize)
- Parameterize endpoints via `prole.properties` (bundled + user override). Replace legacy raspberry with retropie defaults
- ServiceChecker + UI read endpoints from Config loader; tooltips/labels reflect configured hosts/ports
- Build script: generate `Info.plist` with `LSUIElement=false`; bundle resources (`prole-type.gif`, `prole.properties`); ad‑hoc codesign. Universal build supported
- Documentation: rewrite README with technical build/run/config details and operational posture

Files:
- proleStatus/Sources/: AppDelegate.swift, OverlayWindow.swift, StatusView.swift, StatusItemController.swift,
  SplashTipWindowController.swift, MainWindowController.swift, AppStatusView.swift, ServiceChecker.swift, Config.swift
- proleStatus/build.sh
- proleStatus/prole.properties
- proleStatus/README.md

Notes:
- Build verified via `./build.sh build` (arm64). App starts in App Window mode with light theme; menu + hotkey + overlay toggle operate as intended
This commit is contained in:
chrisfu 2025-12-01 21:08:30 -08:00
parent 053d907666
commit 8a6e8738db
24 changed files with 267 additions and 93 deletions

BIN
img/proleIcon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

View File

@ -27,6 +27,14 @@ from installer.workstation import (
)
from installer import deploy as inst_deploy
# On macOS, set process name as early as possible so the menu bar shows 'Prole Installer'
if platform.system() == 'Darwin':
try:
from Foundation import NSProcessInfo
NSProcessInfo.processInfo().setProcessName_("Prole Installer")
except Exception:
pass
# Get the project root directory (kept local for clarity in this legacy entry)
PROJECT_ROOT = Path(__file__).parent.absolute()
@ -90,8 +98,11 @@ class ProleInstaller:
self._bg_item = None
try:
from PIL import Image, ImageTk # optional
# Use the full-frame background image per latest spec
bg_path = PROJECT_ROOT / 'img' / 'proleLogoSepia.png'
# Use the full-frame background image from config
try:
bg_path = inst_config.get_ui_background_image_path()
except Exception:
bg_path = PROJECT_ROOT / 'img' / 'proleLogoSepia.png'
if bg_path.exists():
self._bg_pil = Image.open(str(bg_path)).convert('RGBA')
@ -190,16 +201,13 @@ class ProleInstaller:
# ---------------- App identity (title, Dock icon) ----------------
def _set_app_identity(self):
"""Set the app name shown by Tk and attempt to set the macOS Dock icon.
"""Set the installer identity: process/menu name and Dock icon on macOS.
Notes:
- tk appname affects Tk's internal application name and may improve
display in some OS integrations. On macOS, fully changing the menu bar
app name from "Python" typically requires running as a bundled app
with CFBundleName set, but we still set the Tk appname here.
- For the Dock icon on macOS, we try to use the ProleStatus.app icns
(capital P icon). If PyObjC (AppKit) isn't available, we fall back to
setting a Tk window icon from a PNG/GIF in img/.
- We set Tk's appname for consistency.
- On macOS, attempt to set the process/menu name to 'Prole Installer'
via NSProcessInfo if PyObjC is available.
- Prefer the Prole.app .icns from the built app; fallback to local PNG/GIF.
"""
# Set Tk application name
try:
@ -207,11 +215,30 @@ class ProleInstaller:
except Exception:
pass
# macOS Dock icon via AppKit (preferred)
# macOS: set process/menu name and Dock icon via AppKit/Foundation
if platform.system() == 'Darwin':
# Try to set the visible process name for the menu bar
try:
from Foundation import NSProcessInfo
NSProcessInfo.processInfo().setProcessName_("Prole Installer")
except Exception:
pass
# Also try to retitle the first main menu item so the menu next to the Apple logo reads 'Prole Installer'
try:
from AppKit import NSApplication
app = NSApplication.sharedApplication()
main_menu = app.mainMenu()
if main_menu is not None and main_menu.numberOfItems() > 0:
first_item = main_menu.itemAtIndex_(0)
if first_item is not None:
first_item.setTitle_("Prole Installer")
except Exception:
pass
icns_candidates = [
PROJECT_ROOT / 'proleStatus' / 'dist' / 'ProleStatus.app' / 'Contents' / 'Resources' / 'AppIcon.icns',
PROJECT_ROOT / 'proleStatus' / 'dist' / 'ProleStatus.app' / 'Contents' / 'Resources' / 'ProleStatus.icns',
PROJECT_ROOT / 'prole-app' / 'dist' / 'Prole.app' / 'Contents' / 'Resources' / 'AppIcon.icns',
PROJECT_ROOT / 'prole-app' / 'dist' / 'Prole.app' / 'Contents' / 'Resources' / 'Prole.icns',
]
icns_path = next((p for p in icns_candidates if p.exists()), None)
if icns_path is not None:
@ -226,10 +253,16 @@ class ProleInstaller:
pass
# Fallback: Tk icon from image assets (PNG/GIF)
# Prefer config-defined icon image
try:
cfg_icon = inst_config.get_ui_icon_image_path()
except Exception:
cfg_icon = PROJECT_ROOT / 'img' / 'proleIcon.png'
img_candidates = [
PROJECT_ROOT / 'img' / 'prole-type.gif',
cfg_icon,
PROJECT_ROOT / 'img' / 'prole-type.png',
PROJECT_ROOT / 'img' / 'ProleStatus.png',
PROJECT_ROOT / 'img' / 'prole-type.gif',
PROJECT_ROOT / 'img' / 'Prole.png',
PROJECT_ROOT / 'img' / 'proleLogoSepia.png',
]
for p in img_candidates:
@ -600,7 +633,7 @@ class ProleInstaller:
left = 56
if not hasattr(self, 'deploy_steps'):
self.deploy_steps = [
{'name': 'Build ProleStatus macOS app', 'status': 'pending'},
{'name': 'Build Prole macOS app', 'status': 'pending'},
{'name': 'Build workstation Vagrant VM', 'status': 'pending'},
{'name': 'Check Docker is running', 'status': 'pending'},
{'name': 'Check or configure container registry', 'status': 'pending'},
@ -664,7 +697,7 @@ class ProleInstaller:
self.show_page(target)
return
if current_id == 'build':
# Treat Next as Build for ProleStatus
# Treat Next as Build for Prole
self.perform_build()
return
if current_id == 'build_vm':
@ -949,7 +982,7 @@ class ProleInstaller:
# Reuse existing deploy steps UI but on light theme
self.deploy_steps = [
{'name': 'Build ProleStatus macOS app', 'status': 'pending'},
{'name': 'Build Prole macOS app', 'status': 'pending'},
{'name': 'Check Docker is running', 'status': 'pending'},
{'name': 'Check or configure container registry', 'status': 'pending'},
{'name': 'Ensure target cluster', 'status': 'pending'},
@ -1033,7 +1066,7 @@ class ProleInstaller:
# ---------------- Build integration ----------------
def perform_build(self):
"""Run ProleStatus build in an embedded console (Scopped bash subprocess)."""
"""Run Prole build in an embedded console (Scoped bash subprocess)."""
# Prepare logs dir and file
logs_dir = PROJECT_ROOT / 'logs'
try:
@ -1570,7 +1603,7 @@ class ProleInstaller:
if logp or vlog:
self._render_paragraph('Build output was captured from the embedded console.', y=90)
if logp:
self._render_paragraph('ProleStatus log:', y=120)
self._render_paragraph('Prole build log:', y=120)
self._render_paragraph(logp, y=140)
y_next = 180 if logp else 120
if vlog:
@ -1579,7 +1612,7 @@ class ProleInstaller:
# clickable link
link_y = (y_next + 56) if vlog else 200
if logp:
link1 = self.bg_canvas.create_text(56, link_y, anchor='nw', text='Open ProleStatus log', fill='#0a84ff', font=('Helvetica', 12, 'underline'))
link1 = self.bg_canvas.create_text(56, link_y, anchor='nw', text='Open Prole build log', fill='#0a84ff', font=('Helvetica', 12, 'underline'))
self._canvas_items.append(link1)
if vlog:
link2 = self.bg_canvas.create_text(56, link_y + 28, anchor='nw', text='Open Vagrant log', fill='#0a84ff', font=('Helvetica', 12, 'underline'))
@ -1993,10 +2026,10 @@ echo "All dependencies installed successfully!"
self.deploy_widgets['Ensure target cluster']['step']['name'] = f"Ensure target cluster ({env})"
self.deploy_widgets['Ensure target cluster']['label'].master.master.children['!label'].configure(text=f"Ensure target cluster ({env})")
# Step 0: Build ProleStatus macOS app
self.update_deploy_step_status('Build ProleStatus macOS app', 'running')
self.build_prole_status_app()
self.update_deploy_step_status('Build ProleStatus macOS app', 'completed')
# Step 0: Build Prole macOS app
self.update_deploy_step_status('Build Prole macOS app', 'running')
self.build_prole_app()
self.update_deploy_step_status('Build Prole macOS app', 'completed')
# Step 1: Check Docker
self.update_deploy_step_status('Check Docker is running', 'running')
@ -2049,9 +2082,9 @@ echo "All dependencies installed successfully!"
"""Check if Xcode Command Line Tools are installed via deploy helper."""
return inst_deploy.check_xcode_tools()
def build_prole_status_app(self):
def build_prole_app(self):
"""Delegate building the native ProleStatus app to deploy helper."""
return inst_deploy.build_prole_status_app(PROJECT_ROOT)
return inst_deploy.build_prole_app(PROJECT_ROOT)
def check_docker_running(self):
"""Check if Docker is running"""

View File

@ -1,7 +1,7 @@
"""
Build helpers for the Prole installer (root-level package).
UI-agnostic command composition for the ProleStatus build.
UI-agnostic command composition for the Prole macOS app build.
"""
from __future__ import annotations
@ -9,11 +9,11 @@ from pathlib import Path
def get_build_command(project_root: Path, env: str | None) -> str:
"""Return the ProleStatus build command with an env comment suffix.
"""Return the Prole app build command with an env comment suffix.
Example output:
cd "/path/to/repo" && ./proleStatus/build.sh build # Dev
cd "/path/to/repo" && ./prole-app/build.sh build # Dev
"""
env_label = (env or "Dev").strip().title()
prole_root = str(project_root)
return f"cd \"{prole_root}\" && ./proleStatus/build.sh build # {env_label}"
return f"cd \"{prole_root}\" && ./prole-app/build.sh build # {env_label}"

View File

@ -10,9 +10,82 @@ from pathlib import Path
import platform
import subprocess
from typing import Tuple, Optional
import os
# .properties loader (simple key=value, # comments)
def _load_properties(path: Path) -> dict:
props: dict[str, str] = {}
try:
text = path.read_text(encoding="utf-8")
except Exception:
return props
for line in text.splitlines():
s = line.strip()
if not s or s.startswith("#"):
continue
if "=" in s:
k, v = s.split("=", 1)
k = k.strip()
v = v.strip()
if k:
props[k] = v
return props
# Repository root: this file lives at <repo>/installer/config.py → parent is repo
PROJECT_ROOT = Path(__file__).resolve().parents[1]
PROLE_APP_DIR = PROJECT_ROOT / "prole-app"
PROLE_PROPS_PATH = PROLE_APP_DIR / "prole.properties"
_PROLE_PROPS_CACHE: Optional[dict] = None
def get_properties() -> dict:
"""Load and cache prole.properties from the repo (installer context).
Order:
- Repo default at prole-app/prole.properties
- Optional env override: PROLE_PROPERTIES points to a file
"""
global _PROLE_PROPS_CACHE
if _PROLE_PROPS_CACHE is None:
props: dict[str, str] = {}
# repo default
if PROLE_PROPS_PATH.exists():
props.update(_load_properties(PROLE_PROPS_PATH))
# env override (absolute path)
env_path = os.environ.get("PROLE_PROPERTIES")
if env_path:
p = Path(env_path)
if p.exists():
props.update(_load_properties(p))
_PROLE_PROPS_CACHE = props
return dict(_PROLE_PROPS_CACHE)
def get_config_value(key: str, default: Optional[str] = None) -> Optional[str]:
return get_properties().get(key, default)
def get_ui_icon_image_path() -> Path:
"""Return absolute path to the UI icon image (for installer fallback and builds).
Defaults to img/proleIcon.png under repo root if not set or missing.
"""
rel = get_config_value("ui.icon", "img/proleIcon.png") or "img/proleIcon.png"
p = (PROJECT_ROOT / rel).resolve()
if p.exists():
return p
# fallback
return (PROJECT_ROOT / "img/proleIcon.png").resolve()
def get_ui_background_image_path() -> Path:
"""Return absolute path to the UI background image.
Defaults to img/proleLogoSepia.png under repo root if not set or missing.
"""
rel = get_config_value("ui.background", "img/proleLogoSepia.png") or "img/proleLogoSepia.png"
p = (PROJECT_ROOT / rel).resolve()
if p.exists():
return p
# fallback
return (PROJECT_ROOT / "img/proleLogoSepia.png").resolve()
def is_apple_silicon() -> bool:

View File

@ -1,7 +1,7 @@
"""
Deploy/build helpers for the Prole installer (root-level package).
Encapsulates Xcode tools check and building the native ProleStatus app.
Encapsulates Xcode tools check and building the native Prole app.
"""
from __future__ import annotations
@ -21,37 +21,36 @@ def check_xcode_tools() -> bool:
return False
def build_prole_status_app(project_root: Path) -> None:
def build_prole_app(project_root: Path) -> None:
if platform.system() != "Darwin":
raise Exception("Building the macOS app requires macOS.")
if not check_xcode_tools():
raise Exception("Xcode Command Line Tools not found. Please run: xcode-select --install")
# Only use the top-level proleStatus project location; drop legacy
# references to nested paths under prole/ to keep the tree clean.
prole_status_dir = Path(project_root) / "proleStatus"
build_script = prole_status_dir / "build.sh"
# Use the top-level prole-app project directory
prole_app_dir = Path(project_root) / "prole-app"
build_script = prole_app_dir / "build.sh"
if not build_script.exists():
raise Exception(
f"Build script not found at {build_script}"
)
result = subprocess.run(["bash", str(build_script), "build"], cwd=prole_status_dir, capture_output=True, text=True)
result = subprocess.run(["bash", str(build_script), "build"], cwd=prole_app_dir, capture_output=True, text=True)
if result.returncode != 0:
raise Exception(f"ProleStatus build failed: {result.stderr or result.stdout}")
raise Exception(f"Prole build failed: {result.stderr or result.stdout}")
app_path = prole_status_dir / "dist" / "ProleStatus.app"
app_path = prole_app_dir / "dist" / "Prole.app"
if not app_path.exists():
raise Exception("Build completed but ProleStatus.app was not found in dist/")
raise Exception("Build completed but Prole.app was not found in dist/")
try:
msg = (
"ProleStatus.app has been built successfully.\n\n"
"Prole.app has been built successfully.\n\n"
f"Location: {app_path}\n\n"
"Would you like to copy it to /Applications?"
)
if messagebox.askyesno("ProleStatus Built", msg):
dest = Path("/Applications") / "ProleStatus.app"
if messagebox.askyesno("Prole Built", msg):
dest = Path("/Applications") / "Prole.app"
subprocess.run(["cp", "-R", str(app_path), str(dest)], check=True)
messagebox.showinfo("Copied", f"Copied to {dest}")
except Exception as copy_err:

View File

@ -10,11 +10,11 @@
#####################################################
```
ProleStatus
Prole
— macOS status and control surface for Prole endpoints, with a path to an integrated virtual workstation harness.
Overview
- ProleStatus provides live reachability and latency signals for Prole service endpoints. It operates in two modes: a regular application window for situational awareness and a minimalist statusbar overlay for persistent ataglance status.
- Prole provides live reachability and latency signals for Prole service endpoints. It operates in two modes: a regular application window for situational awareness and a minimalist statusbar overlay for persistent ataglance status.
- The application will evolve to include a virtual workstation surface to coordinate work across a network of Prolelinked LLMs. The current scope is operational visibility and control of endpoints.
Supported platform
@ -35,31 +35,31 @@ Build environment requirements
- `plutil` (plist formatting, via xcrun if needed)
Repository layout (subset)
- `proleStatus/` — macOS app sources and build system
- `prole-app/` — macOS app sources and build system
- `Sources/` — Swift sources (AppKit)
- `build.sh` — hermetic CLI build producing a `.app` bundle
- `prole.properties` — default endpoint configuration (bundled into Resources)
- `dist/ProleStatus.app` — build output
- `dist/Prole.app` — build output
Build script
- The build is driven by `proleStatus/build.sh`. Typical usage:
- The build is driven by `prole-app/build.sh`. Typical usage:
```
cd proleStatus
cd prole-app
./build.sh build # build for host arch
./build.sh run # build (if needed) and open the app
./build.sh build-universal # produce a universal (arm64+x86_64) binary
./build.sh debug # run in foreground with verbose logs
./build.sh clean # remove build artifacts
./build.sh package # zip dist/ProleStatus.app into dist/ProleStatus.zip
./build.sh package # zip dist/Prole.app into dist/Prole.zip
```
What the script does
- Compiles all Swift sources with `swiftc` (AppKit, Carbon, Network frameworks).
- Generates `Contents/Info.plist` with `LSUIElement=false` so the app can present a standard menu when in Application Window mode.
- Generates an application icon (`ProleStatus.icns`) and a template status glyph as needed.
- Generates an application icon (`Prole.icns`) and a template status glyph as needed.
- Copies resources:
- `www/images/prole-type.gif``Contents/Resources/prole-type.gif` (for the startup tip splash)
- `proleStatus/prole.properties` → `Contents/Resources/prole.properties`
- `prole-app/prole.properties` → `Contents/Resources/prole.properties`
- Performs adhoc code signing of the `.app` bundle.
Alternate build path (installer UI)
@ -67,7 +67,7 @@ Alternate build path (installer UI)
```
python3 install.py
```
- Use the “Build ProleStatus macOS app” step. The installer will produce `proleStatus/dist/ProleStatus.app` and can optionally copy it to `/Applications`.
- Use the “Build Prole macOS app” step. The installer will produce `prole-app/dist/Prole.app` and can optionally copy it to `/Applications`.
Run modes and controls
- Modes:
@ -81,8 +81,8 @@ Run modes and controls
Configuration
- Endpoint configuration is provided via Javastyle `key=value` properties. Two locations are read at startup; the user override has precedence:
1. Bundled defaults: `ProleStatus.app/Contents/Resources/prole.properties`
2. User override (optional): `~/Library/Application Support/ProleStatus/prole.properties`
1. Bundled defaults: `Prole.app/Contents/Resources/prole.properties`
2. User override (optional): `~/Library/Application Support/Prole/prole.properties`
- Default keys:
- `svc.host`, `svc.port`
- `k3s.retropie.host`, `k3s.retropie.port`
@ -116,7 +116,7 @@ Security & signing
- The `.app` bundle is adhoc signed by default. For distribution, replace with a Developer ID signature and notarize as appropriate for your environment.
Roadmap
- Integration of a virtual workstation to orchestrate a network of Prolelinked LLMs from within the ProleStatus surface.
- Integration of a virtual workstation to orchestrate a network of Prolelinked LLMs from within the Prole surface.
License
- See the repository `LICENSE` file.

View File

@ -28,7 +28,7 @@ final class Config {
// Load user override from Application Support
let fm = FileManager.default
if let appSupport = try? fm.url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: false) {
let dir = appSupport.appendingPathComponent("ProleStatus", isDirectory: true)
let dir = appSupport.appendingPathComponent("Prole", isDirectory: true)
let url = dir.appendingPathComponent("prole.properties")
if fm.fileExists(atPath: url.path) {
merge(loadProperties(url: url))
@ -68,4 +68,14 @@ final class Config {
var localHost: String { string("k3d.local.host", default: "localhost") }
var localPort: Int { int("k3d.local.port", default: 6443) }
// UI asset config
// Background image file name relative to the app bundle Resources. If a path is provided, only the last component is used.
var uiBackground: String {
let raw = string("ui.background", default: "img/proleLogoSepia.png")
if let lastSlash = raw.lastIndex(of: "/") {
return String(raw[raw.index(after: lastSlash)...])
}
return raw
}
}

View File

@ -67,13 +67,24 @@ final class SplashTipWindowController: NSWindowController {
counterLabel.bottomAnchor.constraint(equalTo: content.bottomAnchor, constant: -4)
])
// Load the animated GIF from bundle resources if present
if let url = Bundle.main.url(forResource: "prole-type", withExtension: "gif"),
let img = NSImage(contentsOf: url) {
imageView.image = img
} else {
// Fallback: show placeholder text if the gif is missing
let placeholder = NSTextField(labelWithString: "prole-type.gif not found")
// Load background/splash image from config (bundled in Resources) if present
let bgName = Config.shared.uiBackground
let candidates: [(String, String?)] = [
(bgName, nil),
("prole-type", "gif")
]
var loaded = false
for (res, ext) in candidates {
if let url = Bundle.main.url(forResource: res, withExtension: ext),
let img = NSImage(contentsOf: url) {
imageView.image = img
loaded = true
break
}
}
if !loaded {
// Fallback: show placeholder text if the resource is missing
let placeholder = NSTextField(labelWithString: "Splash background not found")
placeholder.textColor = .secondaryLabelColor
placeholder.alignment = .center
placeholder.translatesAutoresizingMaskIntoConstraints = false

View File

@ -1,10 +1,10 @@
#!/usr/bin/env bash
set -euo pipefail
# ProleStatus build script — builds a macOS .app bundle without launching Xcode
# Prole build script — builds a macOS .app bundle without launching Xcode
# Requirements: Xcode Command Line Tools (swiftc, codesign, plutil, lipo)
APP_NAME="ProleStatus"
APP_NAME="Prole"
BUNDLE_ID="org.prole.${APP_NAME}"
MIN_MACOS="12.0"
@ -50,6 +50,21 @@ ensure_dirs() {
mkdir -p "$BUILD_DIR" "$DIST_DIR" "$MACOS_DIR" "$RESOURCES_DIR"
}
# Read a key from prole.properties (very simple parser)
prop_get() {
local key="$1"
local file="$ROOT_DIR/prole.properties"
if [[ -f "$file" ]]; then
local line
line=$(grep -E "^${key}=" "$file" | tail -n1 || true)
if [[ -n "$line" ]]; then
echo "${line#*=}"
return 0
fi
fi
return 1
}
gen_statusbar_icon_png() {
# Generates a small monochrome template PNG for the status bar (18x18)
local out_png="$RESOURCES_DIR/statusIcon.png"
@ -89,15 +104,24 @@ SWIFT
}
gen_app_icns() {
# Create a basic .icns with a bold 'P' on transparent background
# Create an .icns for the app. Prefer a configured source image (ui.icon),
# otherwise fall back to generating a bold 'P'.
local icon_name="${APP_NAME}"
local iconset_dir="$BUILD_DIR/${icon_name}.iconset"
rm -rf "$iconset_dir"
mkdir -p "$iconset_dir"
# Generate a 1024 base PNG using AppKit so we don't depend on ImageMagick/Pillow
local base_png="$BUILD_DIR/${icon_name}_1024.png"
/usr/bin/env xcrun swift -F /System/Library/PrivateFrameworks - <<'SWIFT' "$base_png"
# Try configured ui.icon relative to repo root
local ui_icon
ui_icon="$(prop_get ui.icon || true)"
if [[ -n "$ui_icon" && -f "$PARENT_DIR/$ui_icon" ]]; then
# Use the provided icon image as base; if not already 1024x1024, sips will resize for each size
cp "$PARENT_DIR/$ui_icon" "$base_png"
else
# Generate a 1024 base PNG using AppKit so we don't depend on ImageMagick/Pillow
/usr/bin/env xcrun swift -F /System/Library/PrivateFrameworks - <<'SWIFT' "$base_png"
import AppKit
import Foundation
@ -137,6 +161,7 @@ guard let tiff = img.tiffRepresentation,
}
try! png.write(to: URL(fileURLWithPath: outPath))
SWIFT
fi
# Create all iconset sizes from the base image
for s in 16 32 128 256 512; do
@ -185,6 +210,19 @@ copy_extra_resources() {
echo "[resources] prole-type.gif not found at $gif_src (skipping)"
fi
# Copy configured background image (ui.background) into Resources, keeping basename
local ui_bg
ui_bg="$(prop_get ui.background || true)"
if [[ -n "$ui_bg" && -f "$PARENT_DIR/$ui_bg" ]]; then
mkdir -p "$RESOURCES_DIR"
local base
base="$(basename "$ui_bg")"
cp "$PARENT_DIR/$ui_bg" "$RESOURCES_DIR/$base"
echo "[resources] Copied background image ($base) into Resources"
else
echo "[resources] ui.background not set or file missing (skipping)"
fi
# Copy default properties file if present
local props_src="$ROOT_DIR/prole.properties"
if [[ -f "$props_src" ]]; then

View File

@ -0,0 +1,33 @@
# Prole default endpoints (bundled). Override in:
# ~/Library/Application Support/Prole/prole.properties
# using the same key=value format.
# UI assets (relative to repo root when building; file name within app bundle at runtime)
# Icon image used for app icon generation and installer UI fallback
ui.icon=img/proleIcon.png
# Background image used by the app splash/tip and installer background
ui.background=img/proleLogoSepia.png
# Core service
svc.host=svc.prole.org
svc.port=443
# k3s aggregate ? replace legacy raspberry with retropie
k3s.retropie.host=retropie.prole.org
k3s.retropie.port=6443
# k3s.pi.host=pi.prole.org
# k3s.pi.port=6443
# local k3d
k3d.local.host=localhost
k3d.local.port=6443
# internal postgres
postgres.host=k3s.prole.org
postgres.port=5432
# Reserved for future cloud endpoints
# aws.eks.host=
# aws.eks.port=
# gcp.gke.host=
# gcp.gke.port=

View File

@ -1,23 +0,0 @@
# ProleStatus default endpoints (bundled). Override in:
# ~/Library/Application Support/ProleStatus/prole.properties
# using the same key=value format.
# Core service
svc.host=svc.prole.org
svc.port=443
# k3s aggregate ? replace legacy raspberry with retropie
k3s.retropie.host=retropie.prole.org
k3s.retropie.port=6443
# k3s.pi.host=pi.prole.org
# k3s.pi.port=6443
# local k3d
k3d.local.host=localhost
k3d.local.port=6443
# Reserved for future cloud endpoints
# aws.eks.host=
# aws.eks.port=
# gcp.gke.host=
# gcp.gke.port=