Cross-platform development patterns for macOS, Windows, and Linux
detect_os() {
case "$(uname -s)" in
Darwin*) echo "macos" ;;
Linux*)
# Check for WSL
if grep -qi microsoft /proc/version 2>/dev/null; then
echo "wsl"
else
echo "linux"
fi
;;
CYGWIN*|MINGW*|MSYS*) echo "windows" ;;
*) echo "unknown" ;;
esac
}
function Get-Platform {
if ($IsWindows -or $env:OS -eq "Windows_NT") {
return "windows"
} elseif ($IsLinux) {
return "linux"
} elseif ($IsMacOS) {
return "macos"
}
return "unknown"
}
| Platform | Primary | Fallback | | -------- | ----------------- | -------------------- | | macOS | terminal-notifier | osascript | | Linux | notify-send | zenity, wall | | Windows | BurntToast | System.Windows.Forms | | WSL | wsl-notify-send | notify-send |
send_macos_notification() {
local title="$1"
local message="$2"
if command -v terminal-notifier &> /dev/null; then
terminal-notifier \
-title "$title" \
-message "$message" \
-sound "Glass"
else
osascript -e "display notification \"$message\" with title \"$title\""
fi
}
send_linux_notification() {
local title="$1"
local message="$2"
if command -v notify-send &> /dev/null; then
notify-send "$title" "$message" \
--urgency=normal \
--app-name="Code-Notify"
elif command -v zenity &> /dev/null; then
zenity --notification --text="$title\n$message"
else
echo "[$title] $message" | wall 2>/dev/null
fi
}
function Send-WindowsNotification {
param(
[string]$Title,
[string]$Message
)
if (Get-Module -ListAvailable -Name BurntToast) {
New-BurntToastNotification -Text $Title, $Message
} else {
Add-Type -AssemblyName System.Windows.Forms
$notification = New-Object System.Windows.Forms.NotifyIcon
$notification.Icon = [System.Drawing.SystemIcons]::Information
$notification.BalloonTipTitle = $Title
$notification.BalloonTipText = $Message
$notification.Visible = $true
$notification.ShowBalloonTip(10000)
}
}
send_wsl_notification() {
local title="$1"
local message="$2"
if command -v wsl-notify-send.exe &> /dev/null; then
wsl-notify-send.exe --category "$title" "$message"
else
# Fall back to Linux notification
send_linux_notification "$title" "$message"
fi
}
# Convert Unix path to Windows path (in WSL)
to_windows_path() {
local unix_path="$1"
wslpath -w "$unix_path"
}
# Convert Windows path to Unix path (in WSL)
to_unix_path() {
local win_path="$1"
wslpath -u "$win_path"
}
# Bash
HOME_DIR="$HOME"
# PowerShell
$HomeDir = $env:USERPROFILE
# Works on all platforms
get_project_name() {
local git_root
if git rev-parse --git-dir &> /dev/null; then
git_root=$(git rev-parse --show-toplevel 2>/dev/null)
if [[ -n "$git_root" ]]; then
basename "$git_root"
return 0
fi
fi
basename "$PWD"
}
function Get-ProjectName {
try {
$gitRoot = & git rev-parse --show-toplevel 2>$null
if ($LASTEXITCODE -eq 0 -and $gitRoot) {
return Split-Path $gitRoot -Leaf
}
} catch {
# Not in git repo
}
return Split-Path (Get-Location) -Leaf
}
strategy:
matrix:
os: [macos-latest, ubuntu-latest, windows-latest]
# test/test-platform.sh
test_current_platform() {
local os=$(detect_os)
case "$os" in
macos) test_macos_notification ;;
linux) test_linux_notification ;;
wsl) test_wsl_notification ;;
*) echo "Unknown platform: $os" ;;
esac
}
Line Endings: Windows uses CRLF, Unix uses LF
.gitattributes to enforce line endingsPath Separators: Windows uses \, Unix uses /
$HOME instead of hardcoded pathsCase Sensitivity: Windows is case-insensitive
Command Availability: Commands differ by platform
command -v before useSearch for places (restaurants, cafes, etc.) via Google Places API proxy on localhost.
Interact with GitHub using the `gh` CLI. Use `gh issue`, `gh pr`, `gh run`, and `gh api` for issues, PRs, CI runs, and advanced queries.
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Start voice calls via the OpenClaw voice-call plugin.
Notion API for creating and managing pages, databases, and blocks.
Gemini CLI for one-shot Q&A, summaries, and generation.
Category:developer