feat: initial deployment of raycast core automation tools
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
Icon
|
||||
._*
|
||||
.Spotlight-V100
|
||||
.Trashes
|
||||
Binary file not shown.
Executable
BIN
Binary file not shown.
@@ -0,0 +1 @@
|
||||
APPLaplt
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 362 B |
@@ -0,0 +1,177 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>files</key>
|
||||
<dict>
|
||||
<key>Resources/Assets.car</key>
|
||||
<data>
|
||||
OYhR/OamYYa06V1uQdqCVBkF1Ko=
|
||||
</data>
|
||||
<key>Resources/Scripts/main.scpt</key>
|
||||
<data>
|
||||
IRm4ZywEQ4ZMcIHUgTIWR8b58Zg=
|
||||
</data>
|
||||
<key>Resources/applet.icns</key>
|
||||
<data>
|
||||
sINd6lbiqHD5dL8c6u79cFvVXhw=
|
||||
</data>
|
||||
<key>Resources/applet.rsrc</key>
|
||||
<data>
|
||||
ar5xmDs9mPpaINVXiVlVqUCB8ao=
|
||||
</data>
|
||||
</dict>
|
||||
<key>files2</key>
|
||||
<dict>
|
||||
<key>Resources/Assets.car</key>
|
||||
<dict>
|
||||
<key>hash</key>
|
||||
<data>
|
||||
OYhR/OamYYa06V1uQdqCVBkF1Ko=
|
||||
</data>
|
||||
<key>hash2</key>
|
||||
<data>
|
||||
J6PhSy+PqAPXGUYhXlVVGP6Mmhwbpey0SFDxv1jkhEw=
|
||||
</data>
|
||||
</dict>
|
||||
<key>Resources/Scripts/main.scpt</key>
|
||||
<dict>
|
||||
<key>hash</key>
|
||||
<data>
|
||||
IRm4ZywEQ4ZMcIHUgTIWR8b58Zg=
|
||||
</data>
|
||||
<key>hash2</key>
|
||||
<data>
|
||||
GqYcgOfL5/VzHsFJy8ZoZcqcB6tF0eroD2hHdLcY//8=
|
||||
</data>
|
||||
</dict>
|
||||
<key>Resources/applet.icns</key>
|
||||
<dict>
|
||||
<key>hash</key>
|
||||
<data>
|
||||
sINd6lbiqHD5dL8c6u79cFvVXhw=
|
||||
</data>
|
||||
<key>hash2</key>
|
||||
<data>
|
||||
J7weZ6vlnv9r32tS5HFcyuPXl2StdDnfepLxAixlryk=
|
||||
</data>
|
||||
</dict>
|
||||
<key>Resources/applet.rsrc</key>
|
||||
<dict>
|
||||
<key>hash</key>
|
||||
<data>
|
||||
ar5xmDs9mPpaINVXiVlVqUCB8ao=
|
||||
</data>
|
||||
<key>hash2</key>
|
||||
<data>
|
||||
NV2dNLwgykV7aWfTBywUILBA9Lidl7F51PrkQw77SbM=
|
||||
</data>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>rules</key>
|
||||
<dict>
|
||||
<key>^Resources/</key>
|
||||
<true/>
|
||||
<key>^Resources/.*\.lproj/</key>
|
||||
<dict>
|
||||
<key>optional</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>1000</real>
|
||||
</dict>
|
||||
<key>^Resources/.*\.lproj/locversion.plist$</key>
|
||||
<dict>
|
||||
<key>omit</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>1100</real>
|
||||
</dict>
|
||||
<key>^Resources/Base\.lproj/</key>
|
||||
<dict>
|
||||
<key>weight</key>
|
||||
<real>1010</real>
|
||||
</dict>
|
||||
<key>^version.plist$</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>rules2</key>
|
||||
<dict>
|
||||
<key>.*\.dSYM($|/)</key>
|
||||
<dict>
|
||||
<key>weight</key>
|
||||
<real>11</real>
|
||||
</dict>
|
||||
<key>^(.*/)?\.DS_Store$</key>
|
||||
<dict>
|
||||
<key>omit</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>2000</real>
|
||||
</dict>
|
||||
<key>^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/</key>
|
||||
<dict>
|
||||
<key>nested</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>10</real>
|
||||
</dict>
|
||||
<key>^.*</key>
|
||||
<true/>
|
||||
<key>^Info\.plist$</key>
|
||||
<dict>
|
||||
<key>omit</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>20</real>
|
||||
</dict>
|
||||
<key>^PkgInfo$</key>
|
||||
<dict>
|
||||
<key>omit</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>20</real>
|
||||
</dict>
|
||||
<key>^Resources/</key>
|
||||
<dict>
|
||||
<key>weight</key>
|
||||
<real>20</real>
|
||||
</dict>
|
||||
<key>^Resources/.*\.lproj/</key>
|
||||
<dict>
|
||||
<key>optional</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>1000</real>
|
||||
</dict>
|
||||
<key>^Resources/.*\.lproj/locversion.plist$</key>
|
||||
<dict>
|
||||
<key>omit</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>1100</real>
|
||||
</dict>
|
||||
<key>^Resources/Base\.lproj/</key>
|
||||
<dict>
|
||||
<key>weight</key>
|
||||
<real>1010</real>
|
||||
</dict>
|
||||
<key>^[^/]+$</key>
|
||||
<dict>
|
||||
<key>nested</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>10</real>
|
||||
</dict>
|
||||
<key>^embedded\.provisionprofile$</key>
|
||||
<dict>
|
||||
<key>weight</key>
|
||||
<real>20</real>
|
||||
</dict>
|
||||
<key>^version\.plist$</key>
|
||||
<dict>
|
||||
<key>weight</key>
|
||||
<real>20</real>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
Executable
+9
@@ -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"
|
||||
Binary file not shown.
BIN
Binary file not shown.
@@ -0,0 +1 @@
|
||||
APPLaplt
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 362 B |
@@ -0,0 +1,177 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>files</key>
|
||||
<dict>
|
||||
<key>Resources/Assets.car</key>
|
||||
<data>
|
||||
OYhR/OamYYa06V1uQdqCVBkF1Ko=
|
||||
</data>
|
||||
<key>Resources/Scripts/main.scpt</key>
|
||||
<data>
|
||||
39zvn0IGQzPbng/wbsyDSMqYTnk=
|
||||
</data>
|
||||
<key>Resources/applet.icns</key>
|
||||
<data>
|
||||
sINd6lbiqHD5dL8c6u79cFvVXhw=
|
||||
</data>
|
||||
<key>Resources/applet.rsrc</key>
|
||||
<data>
|
||||
ar5xmDs9mPpaINVXiVlVqUCB8ao=
|
||||
</data>
|
||||
</dict>
|
||||
<key>files2</key>
|
||||
<dict>
|
||||
<key>Resources/Assets.car</key>
|
||||
<dict>
|
||||
<key>hash</key>
|
||||
<data>
|
||||
OYhR/OamYYa06V1uQdqCVBkF1Ko=
|
||||
</data>
|
||||
<key>hash2</key>
|
||||
<data>
|
||||
J6PhSy+PqAPXGUYhXlVVGP6Mmhwbpey0SFDxv1jkhEw=
|
||||
</data>
|
||||
</dict>
|
||||
<key>Resources/Scripts/main.scpt</key>
|
||||
<dict>
|
||||
<key>hash</key>
|
||||
<data>
|
||||
39zvn0IGQzPbng/wbsyDSMqYTnk=
|
||||
</data>
|
||||
<key>hash2</key>
|
||||
<data>
|
||||
98lXdGdqePf0B0whqlcPE4FMnDdmWmxsGOd4e7wswqc=
|
||||
</data>
|
||||
</dict>
|
||||
<key>Resources/applet.icns</key>
|
||||
<dict>
|
||||
<key>hash</key>
|
||||
<data>
|
||||
sINd6lbiqHD5dL8c6u79cFvVXhw=
|
||||
</data>
|
||||
<key>hash2</key>
|
||||
<data>
|
||||
J7weZ6vlnv9r32tS5HFcyuPXl2StdDnfepLxAixlryk=
|
||||
</data>
|
||||
</dict>
|
||||
<key>Resources/applet.rsrc</key>
|
||||
<dict>
|
||||
<key>hash</key>
|
||||
<data>
|
||||
ar5xmDs9mPpaINVXiVlVqUCB8ao=
|
||||
</data>
|
||||
<key>hash2</key>
|
||||
<data>
|
||||
NV2dNLwgykV7aWfTBywUILBA9Lidl7F51PrkQw77SbM=
|
||||
</data>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>rules</key>
|
||||
<dict>
|
||||
<key>^Resources/</key>
|
||||
<true/>
|
||||
<key>^Resources/.*\.lproj/</key>
|
||||
<dict>
|
||||
<key>optional</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>1000</real>
|
||||
</dict>
|
||||
<key>^Resources/.*\.lproj/locversion.plist$</key>
|
||||
<dict>
|
||||
<key>omit</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>1100</real>
|
||||
</dict>
|
||||
<key>^Resources/Base\.lproj/</key>
|
||||
<dict>
|
||||
<key>weight</key>
|
||||
<real>1010</real>
|
||||
</dict>
|
||||
<key>^version.plist$</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>rules2</key>
|
||||
<dict>
|
||||
<key>.*\.dSYM($|/)</key>
|
||||
<dict>
|
||||
<key>weight</key>
|
||||
<real>11</real>
|
||||
</dict>
|
||||
<key>^(.*/)?\.DS_Store$</key>
|
||||
<dict>
|
||||
<key>omit</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>2000</real>
|
||||
</dict>
|
||||
<key>^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/</key>
|
||||
<dict>
|
||||
<key>nested</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>10</real>
|
||||
</dict>
|
||||
<key>^.*</key>
|
||||
<true/>
|
||||
<key>^Info\.plist$</key>
|
||||
<dict>
|
||||
<key>omit</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>20</real>
|
||||
</dict>
|
||||
<key>^PkgInfo$</key>
|
||||
<dict>
|
||||
<key>omit</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>20</real>
|
||||
</dict>
|
||||
<key>^Resources/</key>
|
||||
<dict>
|
||||
<key>weight</key>
|
||||
<real>20</real>
|
||||
</dict>
|
||||
<key>^Resources/.*\.lproj/</key>
|
||||
<dict>
|
||||
<key>optional</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>1000</real>
|
||||
</dict>
|
||||
<key>^Resources/.*\.lproj/locversion.plist$</key>
|
||||
<dict>
|
||||
<key>omit</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>1100</real>
|
||||
</dict>
|
||||
<key>^Resources/Base\.lproj/</key>
|
||||
<dict>
|
||||
<key>weight</key>
|
||||
<real>1010</real>
|
||||
</dict>
|
||||
<key>^[^/]+$</key>
|
||||
<dict>
|
||||
<key>nested</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>10</real>
|
||||
</dict>
|
||||
<key>^embedded\.provisionprofile$</key>
|
||||
<dict>
|
||||
<key>weight</key>
|
||||
<real>20</real>
|
||||
</dict>
|
||||
<key>^version\.plist$</key>
|
||||
<dict>
|
||||
<key>weight</key>
|
||||
<real>20</real>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
Executable
+45
@@ -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"
|
||||
Executable
+201
@@ -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();
|
||||
Executable
+22
@@ -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}')"
|
||||
Executable
+9
@@ -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"
|
||||
Executable
+22
@@ -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}')"
|
||||
Executable
+17
@@ -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"
|
||||
Executable
+15
@@ -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()"
|
||||
Executable
+20
@@ -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()"
|
||||
Reference in New Issue
Block a user