commit 99fe36b767ebef2bcd64560ac170c84a68974682 Author: Franco Pellicciotti Date: Fri May 15 23:06:25 2026 -0400 feat: initial deployment of raycast core automation tools diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5ada4f4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +.DS_Store +.AppleDouble +.LSOverride +Icon +._* +.Spotlight-V100 +.Trashes diff --git a/LayoutMenuTrigger.app/Contents/Info.plist b/LayoutMenuTrigger.app/Contents/Info.plist new file mode 100644 index 0000000..2d003fb Binary files /dev/null and b/LayoutMenuTrigger.app/Contents/Info.plist differ diff --git a/LayoutMenuTrigger.app/Contents/MacOS/applet b/LayoutMenuTrigger.app/Contents/MacOS/applet new file mode 100755 index 0000000..49f5380 Binary files /dev/null and b/LayoutMenuTrigger.app/Contents/MacOS/applet differ diff --git a/LayoutMenuTrigger.app/Contents/PkgInfo b/LayoutMenuTrigger.app/Contents/PkgInfo new file mode 100644 index 0000000..3253614 --- /dev/null +++ b/LayoutMenuTrigger.app/Contents/PkgInfo @@ -0,0 +1 @@ +APPLaplt \ No newline at end of file diff --git a/LayoutMenuTrigger.app/Contents/Resources/Assets.car b/LayoutMenuTrigger.app/Contents/Resources/Assets.car new file mode 100644 index 0000000..5e303a5 Binary files /dev/null and b/LayoutMenuTrigger.app/Contents/Resources/Assets.car differ diff --git a/LayoutMenuTrigger.app/Contents/Resources/Scripts/main.scpt b/LayoutMenuTrigger.app/Contents/Resources/Scripts/main.scpt new file mode 100644 index 0000000..f43b09e Binary files /dev/null and b/LayoutMenuTrigger.app/Contents/Resources/Scripts/main.scpt differ diff --git a/LayoutMenuTrigger.app/Contents/Resources/applet.icns b/LayoutMenuTrigger.app/Contents/Resources/applet.icns new file mode 100644 index 0000000..0cdd170 Binary files /dev/null and b/LayoutMenuTrigger.app/Contents/Resources/applet.icns differ diff --git a/LayoutMenuTrigger.app/Contents/Resources/applet.rsrc b/LayoutMenuTrigger.app/Contents/Resources/applet.rsrc new file mode 100644 index 0000000..cf2473f Binary files /dev/null and b/LayoutMenuTrigger.app/Contents/Resources/applet.rsrc differ diff --git a/LayoutMenuTrigger.app/Contents/_CodeSignature/CodeResources b/LayoutMenuTrigger.app/Contents/_CodeSignature/CodeResources new file mode 100644 index 0000000..050b5a0 --- /dev/null +++ b/LayoutMenuTrigger.app/Contents/_CodeSignature/CodeResources @@ -0,0 +1,177 @@ + + + + + files + + Resources/Assets.car + + OYhR/OamYYa06V1uQdqCVBkF1Ko= + + Resources/Scripts/main.scpt + + IRm4ZywEQ4ZMcIHUgTIWR8b58Zg= + + Resources/applet.icns + + sINd6lbiqHD5dL8c6u79cFvVXhw= + + Resources/applet.rsrc + + ar5xmDs9mPpaINVXiVlVqUCB8ao= + + + files2 + + Resources/Assets.car + + hash + + OYhR/OamYYa06V1uQdqCVBkF1Ko= + + hash2 + + J6PhSy+PqAPXGUYhXlVVGP6Mmhwbpey0SFDxv1jkhEw= + + + Resources/Scripts/main.scpt + + hash + + IRm4ZywEQ4ZMcIHUgTIWR8b58Zg= + + hash2 + + GqYcgOfL5/VzHsFJy8ZoZcqcB6tF0eroD2hHdLcY//8= + + + Resources/applet.icns + + hash + + sINd6lbiqHD5dL8c6u79cFvVXhw= + + hash2 + + J7weZ6vlnv9r32tS5HFcyuPXl2StdDnfepLxAixlryk= + + + Resources/applet.rsrc + + hash + + ar5xmDs9mPpaINVXiVlVqUCB8ao= + + hash2 + + NV2dNLwgykV7aWfTBywUILBA9Lidl7F51PrkQw77SbM= + + + + rules + + ^Resources/ + + ^Resources/.*\.lproj/ + + optional + + weight + 1000 + + ^Resources/.*\.lproj/locversion.plist$ + + omit + + weight + 1100 + + ^Resources/Base\.lproj/ + + weight + 1010 + + ^version.plist$ + + + rules2 + + .*\.dSYM($|/) + + weight + 11 + + ^(.*/)?\.DS_Store$ + + omit + + weight + 2000 + + ^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/ + + nested + + weight + 10 + + ^.* + + ^Info\.plist$ + + omit + + weight + 20 + + ^PkgInfo$ + + omit + + weight + 20 + + ^Resources/ + + weight + 20 + + ^Resources/.*\.lproj/ + + optional + + weight + 1000 + + ^Resources/.*\.lproj/locversion.plist$ + + omit + + weight + 1100 + + ^Resources/Base\.lproj/ + + weight + 1010 + + ^[^/]+$ + + nested + + weight + 10 + + ^embedded\.provisionprofile$ + + weight + 20 + + ^version\.plist$ + + weight + 20 + + + + diff --git a/Rescue Windows.sh b/Rescue Windows.sh new file mode 100755 index 0000000..265692e --- /dev/null +++ b/Rescue Windows.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +# @raycast.schemaVersion 1 +# @raycast.title Rescue Windows +# @raycast.mode compact +# @raycast.packageName Window Management + +OUTPUT=$(/opt/homebrew/bin/node $HOME/Developer/raycast-scripts/layout_engine.js rescue) +echo "$OUTPUT" \ No newline at end of file diff --git a/WindowManagerTrigger.app/Contents/Info.plist b/WindowManagerTrigger.app/Contents/Info.plist new file mode 100644 index 0000000..25a67ee Binary files /dev/null and b/WindowManagerTrigger.app/Contents/Info.plist differ diff --git a/WindowManagerTrigger.app/Contents/MacOS/applet b/WindowManagerTrigger.app/Contents/MacOS/applet new file mode 100755 index 0000000..b331743 Binary files /dev/null and b/WindowManagerTrigger.app/Contents/MacOS/applet differ diff --git a/WindowManagerTrigger.app/Contents/PkgInfo b/WindowManagerTrigger.app/Contents/PkgInfo new file mode 100644 index 0000000..3253614 --- /dev/null +++ b/WindowManagerTrigger.app/Contents/PkgInfo @@ -0,0 +1 @@ +APPLaplt \ No newline at end of file diff --git a/WindowManagerTrigger.app/Contents/Resources/Assets.car b/WindowManagerTrigger.app/Contents/Resources/Assets.car new file mode 100644 index 0000000..5e303a5 Binary files /dev/null and b/WindowManagerTrigger.app/Contents/Resources/Assets.car differ diff --git a/WindowManagerTrigger.app/Contents/Resources/Scripts/main.scpt b/WindowManagerTrigger.app/Contents/Resources/Scripts/main.scpt new file mode 100644 index 0000000..516a83f Binary files /dev/null and b/WindowManagerTrigger.app/Contents/Resources/Scripts/main.scpt differ diff --git a/WindowManagerTrigger.app/Contents/Resources/applet.icns b/WindowManagerTrigger.app/Contents/Resources/applet.icns new file mode 100644 index 0000000..0cdd170 Binary files /dev/null and b/WindowManagerTrigger.app/Contents/Resources/applet.icns differ diff --git a/WindowManagerTrigger.app/Contents/Resources/applet.rsrc b/WindowManagerTrigger.app/Contents/Resources/applet.rsrc new file mode 100644 index 0000000..cf2473f Binary files /dev/null and b/WindowManagerTrigger.app/Contents/Resources/applet.rsrc differ diff --git a/WindowManagerTrigger.app/Contents/_CodeSignature/CodeResources b/WindowManagerTrigger.app/Contents/_CodeSignature/CodeResources new file mode 100644 index 0000000..ec61f8a --- /dev/null +++ b/WindowManagerTrigger.app/Contents/_CodeSignature/CodeResources @@ -0,0 +1,177 @@ + + + + + files + + Resources/Assets.car + + OYhR/OamYYa06V1uQdqCVBkF1Ko= + + Resources/Scripts/main.scpt + + 39zvn0IGQzPbng/wbsyDSMqYTnk= + + Resources/applet.icns + + sINd6lbiqHD5dL8c6u79cFvVXhw= + + Resources/applet.rsrc + + ar5xmDs9mPpaINVXiVlVqUCB8ao= + + + files2 + + Resources/Assets.car + + hash + + OYhR/OamYYa06V1uQdqCVBkF1Ko= + + hash2 + + J6PhSy+PqAPXGUYhXlVVGP6Mmhwbpey0SFDxv1jkhEw= + + + Resources/Scripts/main.scpt + + hash + + 39zvn0IGQzPbng/wbsyDSMqYTnk= + + hash2 + + 98lXdGdqePf0B0whqlcPE4FMnDdmWmxsGOd4e7wswqc= + + + Resources/applet.icns + + hash + + sINd6lbiqHD5dL8c6u79cFvVXhw= + + hash2 + + J7weZ6vlnv9r32tS5HFcyuPXl2StdDnfepLxAixlryk= + + + Resources/applet.rsrc + + hash + + ar5xmDs9mPpaINVXiVlVqUCB8ao= + + hash2 + + NV2dNLwgykV7aWfTBywUILBA9Lidl7F51PrkQw77SbM= + + + + rules + + ^Resources/ + + ^Resources/.*\.lproj/ + + optional + + weight + 1000 + + ^Resources/.*\.lproj/locversion.plist$ + + omit + + weight + 1100 + + ^Resources/Base\.lproj/ + + weight + 1010 + + ^version.plist$ + + + rules2 + + .*\.dSYM($|/) + + weight + 11 + + ^(.*/)?\.DS_Store$ + + omit + + weight + 2000 + + ^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/ + + nested + + weight + 10 + + ^.* + + ^Info\.plist$ + + omit + + weight + 20 + + ^PkgInfo$ + + omit + + weight + 20 + + ^Resources/ + + weight + 20 + + ^Resources/.*\.lproj/ + + optional + + weight + 1000 + + ^Resources/.*\.lproj/locversion.plist$ + + omit + + weight + 1100 + + ^Resources/Base\.lproj/ + + weight + 1010 + + ^[^/]+$ + + nested + + weight + 10 + + ^embedded\.provisionprofile$ + + weight + 20 + + ^version\.plist$ + + weight + 20 + + + + diff --git a/layout-menubar.sh b/layout-menubar.sh new file mode 100755 index 0000000..6a88583 --- /dev/null +++ b/layout-menubar.sh @@ -0,0 +1,45 @@ +#!/bin/bash + +# @raycast.schemaVersion 1 +# @raycast.title Window Layout Manager +# @raycast.mode menu-bar +# @raycast.packageName Window Management +# @raycast.icon ๐Ÿ’  +# @raycast.interval 1s + +LAYOUT_FILE="$HOME/.hammerspoon/saved_layout.json" +STATE_FILE="/tmp/raycast_layout_state.json" + +# Initialize state if missing +if [ ! -f "$STATE_FILE" ]; then + echo '{"countdown":300,"lastSaved":"Never"}' > "$STATE_FILE" +fi + +# Load current state safely +COUNTDOWN=$(osascript -e 'tell application "System Events" to get value of property list item "countdown" of property list file "'"$STATE_FILE"'"' 2>/dev/null || echo "300") +LAST_SAVED=$(osascript -e 'tell application "System Events" to get value of property list item "lastSaved" of property list file "'"$STATE_FILE"'"' 2>/dev/null || echo "Never") + +# Handle countdown decrement +COUNTDOWN=$((COUNTDOWN - 1)) +if [ $COUNTDOWN -lt 0 ]; then + COUNTDOWN=300 + /opt/homebrew/bin/node ~/Developer/raycast-scripts/layout_engine.js save silent > /dev/null 2>&1 + LAST_SAVED=$(date +"%H:%M:%S") +fi + +# Save the updated state +echo "{\"countdown\":$COUNTDOWN,\"lastSaved\":\"$LAST_SAVED\"}" > "$STATE_FILE" + +# Calculate minutes and seconds +MINUTES=$((COUNTDOWN / 60)) +SECONDS=$((COUNTDOWN % 60)) +DISPLAY_TIME=$(printf "%d:%02d" $MINUTES $SECONDS) + +# --- RAYCAST NATIVE MENU-BAR OUTPUT --- +# When mode is set to menu-bar, Raycast reads standard text output line-by-line +echo "$DISPLAY_TIME" +echo "---" +echo "๐Ÿ“… Last Saved: $LAST_SAVED" +echo "๐Ÿ“ธ Save Layout (โ‡งโŒ˜W) | bash='/opt/homebrew/bin/node $HOME/Developer/raycast-scripts/layout_engine.js save' terminal=false" +echo "๐Ÿ”„ Restore Layout (โ‡งโŒ˜R) | bash='/opt/homebrew/bin/node $HOME/Developer/raycast-scripts/layout_engine.js restore' terminal=false" +echo "๐Ÿš€ Rescue Windows (โ‡งโŒ˜โŒƒL) | bash='/opt/homebrew/bin/node $HOME/Developer/raycast-scripts/layout_engine.js rescue' terminal=false" diff --git a/layout_engine.js b/layout_engine.js new file mode 100755 index 0000000..14d24b8 --- /dev/null +++ b/layout_engine.js @@ -0,0 +1,201 @@ +const fs = require('fs'); +const path = require('path'); +const { execSync } = require('child_process'); + +const HOME = process.env.HOME; +const LAYOUT_FILE = path.join(HOME, '.hammerspoon/saved_layout.json'); +const CONFIG_FILE = path.join(HOME, '.hammerspoon/config.json'); +const TEMP_JS_FILE = '/tmp/raycast_window_engine.js'; + +let stubbornApps = ["Gemini", "AFFiNE", "Terminal", "System Settings"]; +let ignoreApps = ["TheBoringNotch", "Control Center", "Notification Center", "Dock", "BetterDisplay", "Stats", "DockDoor", "Bartender 6", "Bartender", "Arq", "Arq Agent", "TypeWhisper", "com.typewhisper.mac"]; + +if (fs.existsSync(CONFIG_FILE)) { + try { + const cfg = JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8')); + if (cfg.stubbornAppsList) stubbornApps = Object.keys(cfg.stubbornAppsList); + if (cfg.ignoreListItems) ignoreApps = Object.keys(cfg.ignoreListItems); + } catch (e) {} +} + +const action = process.argv[2]; + +function getVisibleWindows() { + // Queries the global System Events window array directly, replicating hs.window.allWindows() + const captureScript = ` + var sys = Application('System Events'); + var out = []; + try { + var allWins = sys.windows(); + for (var i = 0; i < allWins.length; i++) { + var win = allWins[i]; + var proc = win.process(); + if (!proc) continue; + + var procName = proc.name(); + var bundleID = proc.bundleIdentifier() || ""; + var size = win.size(); + var pos = win.position(); + var title = win.title() || ""; + + if (size && size[0] > 10 && size[1] > 10 && pos && pos[0] !== undefined) { + out.push({ + appName: procName, + bundleID: bundleID, + winTitle: title, + x: Math.floor(pos[0]), + y: Math.floor(pos[1]), + w: Math.floor(size[0]), + h: Math.floor(size[1]) + }); + } + } + } catch(e) {} + JSON.stringify(out); + `; + + try { + fs.writeFileSync(TEMP_JS_FILE, captureScript, 'utf8'); + const rawOutput = execSync(`osascript -l JavaScript ${TEMP_JS_FILE}`).toString().trim(); + if (fs.existsSync(TEMP_JS_FILE)) fs.unlinkSync(TEMP_JS_FILE); + + if (!rawOutput || rawOutput === "[]") return []; + return JSON.parse(rawOutput); + } catch (e) { + if (fs.existsSync(TEMP_JS_FILE)) fs.unlinkSync(TEMP_JS_FILE); + return []; + } +} + +function saveLayout() { + const windows = getVisibleWindows().filter(w => w && !ignoreApps.includes(w.appName) && !ignoreApps.includes(w.bundleID)); + if (windows.length === 0) { + console.log("No active windows detected to save."); + return; + } + + const layout = { + saveTime: new Date().toLocaleTimeString(), + windows: windows + }; + + if (!fs.existsSync(path.dirname(LAYOUT_FILE))) { + fs.mkdirSync(path.dirname(LAYOUT_FILE), { recursive: true }); + } + + fs.writeFileSync(LAYOUT_FILE, JSON.stringify(layout, null, 2)); + console.log("Layout Saved Successfully"); +} + +function restoreLayout() { + if (!fs.existsSync(LAYOUT_FILE)) { + console.log("Restore failed: No saved layout found."); + return; + } + + const data = JSON.parse(fs.readFileSync(LAYOUT_FILE, 'utf8')); + if (!data.windows || data.windows.length === 0) return; + + const savedByApp = {}; + data.windows.forEach(win => { + if (ignoreApps.includes(win.appName) || ignoreApps.includes(win.bundleID)) return; + if (!savedByApp[win.appName]) savedByApp[win.appName] = []; + savedByApp[win.appName].push(win); + }); + + Object.keys(savedByApp).forEach(appName => { + savedByApp[appName].sort((a, b) => { + if (a.y === b.y) return a.x - b.x; + return a.y - b.y; + }); + }); + + let restoreScript = `var sys = Application('System Events');\n`; + Object.keys(savedByApp).forEach(appName => { + const savedEntries = savedByApp[appName]; + restoreScript += ` + try { + if (sys.processes.names().includes("${appName}")) { + var proc = sys.processes["${appName}"]; + var physicalWins = []; + var allWins = proc.windows(); + + for (var k = 0; k < allWins.length; k++) { + try { + var w = allWins[k]; + var s = w.size(); + if (s && s[0] > 10 && s[1] > 10) { + physicalWins.push(w); + } + } catch(err) {} + } + + physicalWins.sort(function(a, b) { + var posA = a.position(); var posB = b.position(); + if (!posA || !posB) return 0; + if (posA[1] === posB[1]) return posA[0] - posB[0]; + return posA[1] - posB[1]; + }); + + var savedEntriesForApp = ${JSON.stringify(savedEntries)}; + for (var i = 0; i < Math.min(savedEntriesForApp.length, physicalWins.length); i++) { + try { + var winData = savedEntriesForApp[i]; + var targetWin = physicalWins[i]; + + targetWin.position = [winData.x, winData.y]; + targetWin.size = [winData.w, winData.h]; + } catch(err) {} + } + } + } catch(e) {} + `; + }); + + try { + fs.writeFileSync(TEMP_JS_FILE, restoreScript, 'utf8'); + execSync(`osascript -l JavaScript ${TEMP_JS_FILE} 2>/dev/null`); + + if (data.windows.some(w => stubbornApps.includes(w.appName))) { + setTimeout(() => { + try { execSync(`osascript -l JavaScript ${TEMP_JS_FILE} 2>/dev/null`); } catch(e){} + if (fs.existsSync(TEMP_JS_FILE)) fs.unlinkSync(TEMP_JS_FILE); + }, 500); + } else { + if (fs.existsSync(TEMP_JS_FILE)) fs.unlinkSync(TEMP_JS_FILE); + } + } catch (e) {} + console.log("Layout Restored Successfully"); +} + +function rescueWindows() { + let rescueScript = ` + var sys = Application('System Events'); + var allWins = sys.windows(); + var stagger = 0; + for (var i = 0; i < allWins.length; i++) { + try { + var win = allWins[i]; + var proc = win.process(); + if (proc && proc.name() !== "Finder" && proc.name() !== "Dock") { + var s = win.size(); + if (s && s[0] > 10) { + win.position = [50 + stagger, 50 + stagger]; + stagger += 30; + if (stagger > 150) stagger = 0; + } + } + } catch(e) {} + } + `; + try { + fs.writeFileSync(TEMP_JS_FILE, rescueScript, 'utf8'); + execSync(`osascript -l JavaScript ${TEMP_JS_FILE} 2>/dev/null`); + } catch(e){} + if (fs.existsSync(TEMP_JS_FILE)) fs.unlinkSync(TEMP_JS_FILE); + console.log("Windows Cascaded to Laptop"); +} + +if (action === 'save') saveLayout(); +if (action === 'restore') restoreLayout(); +if (action === 'rescue') rescueWindows(); \ No newline at end of file diff --git a/load-layout.sh b/load-layout.sh new file mode 100755 index 0000000..11253cd --- /dev/null +++ b/load-layout.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +# @raycast.schemaVersion 1 +# @raycast.title Load Window Layout +# @raycast.mode silent +# @raycast.icon ๐Ÿ–ฅ๏ธ +# @raycast.packageName Layout Selector + +# @raycast.argument1 { "type": "text", "placeholder": "Layout Name" } + +if [ ! -f /opt/homebrew/bin/hs ]; then + echo "Hammerspoon CLI link missing" + exit 1 +fi + +LAYOUT_NAME="$1" + +if [ -z "$LAYOUT_NAME" ]; then + exit 1 +fi + +/opt/homebrew/bin/hs -c "LayoutSelector.load('${LAYOUT_NAME}')" diff --git a/restore-layout.sh b/restore-layout.sh new file mode 100755 index 0000000..9d2e815 --- /dev/null +++ b/restore-layout.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +# @raycast.schemaVersion 1 +# @raycast.title Restore Layout +# @raycast.mode compact +# @raycast.packageName Window Management + +OUTPUT=$(/opt/homebrew/bin/node $HOME/Developer/raycast-scripts/layout_engine.js restore) +echo "$OUTPUT" \ No newline at end of file diff --git a/save-layout.sh b/save-layout.sh new file mode 100755 index 0000000..79e0b5f --- /dev/null +++ b/save-layout.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +# @raycast.schemaVersion 1 +# @raycast.title Save Current Layout +# @raycast.mode silent +# @raycast.icon ๐Ÿ’พ +# @raycast.packageName Layout Selector + +# @raycast.argument1 { "type": "text", "placeholder": "Layout Name (e.g. Work)" } + +if [ ! -f /opt/homebrew/bin/hs ]; then + echo "Hammerspoon CLI link missing" + exit 1 +fi + +LAYOUT_NAME="$1" + +if [ -z "$LAYOUT_NAME" ]; then + exit 1 +fi + +/opt/homebrew/bin/hs -c "LayoutSelector.save('${LAYOUT_NAME}')" diff --git a/script-command.template.sh b/script-command.template.sh new file mode 100755 index 0000000..b642b7e --- /dev/null +++ b/script-command.template.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +# Raycast Script Command Template +# +# Duplicate this file and remove ".template." from the filename to get started. +# See full documentation here: https://github.com/raycast/script-commands +# +# Required parameters: +# @raycast.schemaVersion 1 +# @raycast.title My First Script +# @raycast.mode fullOutput +# +# Optional parameters: +# @raycast.icon ๐Ÿค– +# @raycast.packageName Raycast Scripts + +echo "Hello from My First Script" \ No newline at end of file diff --git a/select-layout-menu.sh b/select-layout-menu.sh new file mode 100755 index 0000000..2d8496d --- /dev/null +++ b/select-layout-menu.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +# @raycast.schemaVersion 1 +# @raycast.title Select Layout Menu +# @raycast.mode silent +# @raycast.icon ๐Ÿ“‹ +# @raycast.packageName Layout Selector + +if [ ! -f /opt/homebrew/bin/hs ]; then + echo "Hammerspoon CLI link missing" + exit 1 +fi + +# Run the programmatic menu interface launcher +/opt/homebrew/bin/hs -c "LayoutSelector.showMenu()" diff --git a/trigger-monocle.sh b/trigger-monocle.sh new file mode 100755 index 0000000..09b1e15 --- /dev/null +++ b/trigger-monocle.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +# @raycast.schemaVersion 1 +# @raycast.title Trigger Monocle Window Layout +# @raycast.mode silent +# @raycast.icon ๐Ÿ–ฅ๏ธ +# @raycast.packageName Hammerspoon Core Automation + +# 1. Verify that the Hammerspoon command-line bridge is present +if [ ! -f /opt/homebrew/bin/hs ]; then + echo "Error: Hammerspoon CLI bridge not found at /opt/homebrew/bin/hs" + exit 1 +fi + +# 2. Send the execution string over to the headless background process +/opt/homebrew/bin/hs -c "hs.alert.show('Layout Synced via Raycast!', 2)" + +# Note: You can call any custom global functions defined inside your pulled Gitea scripts. +# To do that, replace the code string above with your specific Lua function name: +# /opt/homebrew/bin/hs -c "toggleMonocle()"