import "@johnlindquist/kit"
interface WindowState {
process: string
title: string
x: number
y: number
width: number
height: number
spaceId?: number
}
interface SavedLayout {
name: string
timestamp: number
windows: WindowState[]
}
const layoutsDb = await db("window-layouts", { layouts: [] as SavedLayout[] })
const getCurrentWindows = async (): Promise<WindowState[]> => {
const windows = await getWindowsBounds()
return windows.map(w => ({
process: w.process,
title: w.name,
x: w.position.x,
y: w.position.y,
width: w.size.width,
height: w.size.height
}))
}
const saveCurrentLayout = async () => {
const layoutName = await arg("Enter layout name:")
if (!layoutName) return
const windows = await getCurrentWindows()
const newLayout: SavedLayout = {
name: layoutName,
timestamp: Date.now(),
windows
}
layoutsDb.layouts.push(newLayout)
await layoutsDb.write()
await toast(`Layout "${layoutName}" saved with ${windows.length} windows`)
}
const restoreLayout = async () => {
if (layoutsDb.layouts.length === 0) {
await div(md("No saved layouts found. Save a layout first."))
return
}
const layoutChoices = layoutsDb.layouts.map(layout => ({
name: `${layout.name} (${layout.windows.length} windows)`,
description: `Saved ${formatDateToNow(new Date(layout.timestamp))}`,
value: layout
}))
const selectedLayout = await arg("Select layout to restore:", layoutChoices)
if (!selectedLayout) return
let restored = 0
for (const windowState of selectedLayout.windows) {
try {
await setWindowPosition(
windowState.process,
windowState.title,
windowState.x,
windowState.y
)
await setWindowSize(
windowState.process,
windowState.title,
windowState.width,
windowState.height
)
restored++
} catch (error) {
console.warn(`Failed to restore window: ${windowState.process} - ${windowState.title}`)
}
}
await toast(`Restored ${restored}/${selectedLayout.windows.length} windows`)
}
const moveWindowToSpace = async () => {
const windows = await getWindows()
if (windows.length === 0) {
await div(md("No windows found"))
return
}
const windowChoices = windows.map(w => ({
name: `${w.process} - ${w.title}`,
description: `Index: ${w.index}`,
value: w
}))
const selectedWindow = await arg("Select window to move:", windowChoices)
if (!selectedWindow) return
const spaceNumber = await arg("Enter space number (1-16):")
const spaceNum = parseInt(spaceNumber)
if (isNaN(spaceNum) || spaceNum < 1 || spaceNum > 16) {
await div(md("Invalid space number. Please enter a number between 1 and 16."))
return
}
try {
const script = `
tell application "System Events"
tell process "${selectedWindow.process}"
set frontmost to true
tell window "${selectedWindow.title}"
perform action "AXRaise"
end tell
end tell
-- Send window to space using Mission Control
key code 126 using {control down} -- Control+Up to open Mission Control
delay 0.5
key code ${48 + spaceNum} -- Number key for space
delay 0.5
end tell
`
await applescript(script)
await toast(`Moved "${selectedWindow.title}" to Space ${spaceNum}`)
} catch (error) {
await div(md(`Failed to move window: ${error.message}`))
}
}
const organizeWindows = async () => {
const action = await arg("Choose organization action:", [
{ name: "Tile All Windows", value: "tile" },
{ name: "Scatter Windows", value: "scatter" },
{ name: "Organize Windows", value: "organize" }
])
switch (action) {
case "tile":
await scatterWindows()
break
case "scatter":
await scatterWindows()
break
case "organize":
await organizeWindows()
break
}
await toast("Windows organized!")
}
const deleteLayout = async () => {
if (layoutsDb.layouts.length === 0) {
await div(md("No saved layouts to delete"))
return
}
const layoutChoices = layoutsDb.layouts.map((layout, index) => ({
name: `${layout.name} (${layout.windows.length} windows)`,
description: `Saved ${formatDateToNow(new Date(layout.timestamp))}`,
value: index
}))
const selectedIndex = await arg("Select layout to delete:", layoutChoices)
if (selectedIndex === undefined) return
const layoutName = layoutsDb.layouts[selectedIndex].name
layoutsDb.layouts.splice(selectedIndex, 1)
await layoutsDb.write()
await toast(`Layout "${layoutName}" deleted`)
}
const action = await arg("Window Manager - Choose action:", [
{ name: "💾 Save Current Layout", value: "save", description: "Save current window positions and sizes" },
{ name: "🔄 Restore Layout", value: "restore", description: "Apply a previously saved layout" },
{ name: "🚀 Move Window to Space", value: "move", description: "Move a window to a specific macOS space" },
{ name: "📐 Organize Windows", value: "organize", description: "Tile, scatter, or organize all windows" },
{ name: "🗑️ Delete Layout", value: "delete", description: "Remove a saved layout" },
{ name: "📋 Show Current Windows", value: "show", description: "Display all current windows" }
])
switch (action) {
case "save":
await saveCurrentLayout()
break
case "restore":
await restoreLayout()
break
case "move":
await moveWindowToSpace()
break
case "organize":
await organizeWindows()
break
case "delete":
await deleteLayout()
break
case "show":
const windows = await getCurrentWindows()
const windowList = windows.map(w =>
`**${w.process}** - ${w.title}\n Position: (${w.x}, ${w.y}) Size: ${w.width}x${w.height}`
).join('\n\n')
await div(md(`# Current Windows (${windows.length})\n\n${windowList}`))
break
}