Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ This is where I tweak config files till 4am like a goblin. It's pretty cozy in h
- **[pi](https://github.com/badlogic/pi-mono)**
- **[wezterm](https://wezterm.org/index.html)**
- **[stow](https://www.gnu.org/software/stow/)**
- **[SwiftBar](https://github.com/swiftbar/SwiftBar)**
- **[Tinycast](https://github.com/abue-ammar/tinycast)**
- **[yazi](https://yazi-rs.github.io/)**

Expand Down
128 changes: 128 additions & 0 deletions fish/.config/fish/functions/latte.fish
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
# latte: friendlier `caffeinate` wrapper that takes hours or minutes instead
# of seconds. Handy for keeping the Mac awake while long-running agents /
# background jobs do their thing. `latte -a` stays awake only as long as
# coding agents (claude, codex, pi) are running, then exits.
function latte --description 'caffeinate with -h HOURS, -m MINUTES, or -a until coding agents finish'
argparse 'h/hours=' 'm/minutes=' 'a/agents' -- $argv
or return

set -l seconds
set -l label

function __latte_plural -S -a n word
if test "$n" = 1
echo "$n $word"
else
echo "$n "$word"s"
end
end

function __latte_brew -S -a msg
set_color -o magenta
echo -n "☕ latte"
set_color normal
echo " · $msg"
end

# Coding agents watched by -a/--agents. pi execs a node script, so its
# process name is `node` — match its command line instead. claude is
# lowercase so this won't match the Claude desktop app (capital C).
function __latte_agents_running -S
pgrep -qx claude; and echo claude
pgrep -qx codex; and echo codex
pgrep -qf pi-coding-agent; and echo pi
end

# Run caffeinate with the TTY in no-echo, non-canonical mode so stray
# keystrokes in the pane don't corrupt the display or leak into the next
# prompt. isig stays on so Ctrl-C still terminates caffeinate normally.
# Restored via a SIGINT handler so interrupts can't leave the TTY broken.
function __latte_run -S -a mode seconds
set -l tty_saved ""
set -l tty_active false
if isatty stdin
set tty_saved (stty -g 2>/dev/null)
if test -n "$tty_saved"
stty -echo -icanon 2>/dev/null
printf '\e[?25l'
set tty_active true
end
end
function __latte_restore_tty --inherit-variable tty_saved --inherit-variable tty_active
if test "$tty_active" = true
command -q python3; and python3 -c 'import termios,sys; termios.tcflush(sys.stdin, termios.TCIFLUSH)' 2>/dev/null
stty "$tty_saved" 2>/dev/null
printf '\e[?25h'
set tty_active false
end
functions -q __latte_sigint_handler; and functions -e __latte_sigint_handler
end
function __latte_sigint_handler --on-signal SIGINT
__latte_restore_tty
end
switch $mode
case timed
caffeinate -dimsu -t $seconds
case agents
# Poll for agents every 30s; caffeinate -t doubles as the
# sleep so the wake assertion is held between checks.
while test (count (__latte_agents_running)) -gt 0
caffeinate -dimsu -t 30
if test $status -gt 128
break
end
end
case '*'
caffeinate -dimsu
end
set -l rc $status
__latte_restore_tty
return $rc
end

set -l flag_count 0
set -q _flag_hours; and set flag_count (math $flag_count + 1)
set -q _flag_minutes; and set flag_count (math $flag_count + 1)
set -q _flag_agents; and set flag_count (math $flag_count + 1)
if test $flag_count -gt 1
set_color -o red
echo -n "☕ latte"
set_color normal
echo " · pick one: -h/--hours, -m/--minutes, or -a/--agents" >&2
return 1
end

if set -q _flag_agents
set -l running (__latte_agents_running)
if test (count $running) -eq 0
__latte_brew "no coding agents running — nothing to babysit"
return 0
end
__latte_brew "keeping macOS awake while agents run: "(string join ', ' $running)
__latte_run agents
set -l rc $status
__latte_brew "all agents done — macOS can nap now"
return $rc
else if set -q _flag_hours
set seconds (math -s0 "$_flag_hours * 3600")
or begin
__latte_brew "invalid hours: $_flag_hours" >&2
return 1
end
set label (__latte_plural $_flag_hours hour)
else if set -q _flag_minutes
set seconds (math -s0 "$_flag_minutes * 60")
or begin
__latte_brew "invalid minutes: $_flag_minutes" >&2
return 1
end
set label (__latte_plural $_flag_minutes minute)
else
__latte_brew "bottomless cup — keeping macOS awake until ctrl-c"
__latte_run forever
return
end

__latte_brew "keeping macOS awake for $label — sip slow"
__latte_run timed $seconds
end
1 change: 0 additions & 1 deletion homebrew/Brewfile
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ if OS.mac?
cask "codex"
cask "handy"
cask "orbstack"
cask "swiftbar"
cask "tamnd/tap/kage"
cask "tinycast"
cask "vlc"
Expand Down
46 changes: 3 additions & 43 deletions scripts/bootstrap.sh
Original file line number Diff line number Diff line change
Expand Up @@ -176,46 +176,6 @@ bootstrap_fish() {
ok 'Login shell changed to Fish (takes effect on next login)'
fi
}
bootstrap_insomnia() {
section 'SwiftBar / Insomnia'
if [[ "$(uname -s)" != Darwin ]]; then warn 'SwiftBar skipped: macOS only'; return; fi
ensure_brew
if ! brew list --cask swiftbar >/dev/null 2>&1; then
run 'Install SwiftBar' brew install --cask swiftbar
else
ok 'SwiftBar already installed'
fi
link_configs swiftbar
local plugins domain plist reload=0
plugins="$HOME/.config/swiftbar/plugins"
domain="gui/$(id -u)"
plist="$HOME/Library/LaunchAgents/com.wu-json.swiftbar-login.plist"
need defaults 'Run this recipe on macOS.'
need launchctl 'Run this recipe in a macOS desktop session.'
if [[ "$(defaults read com.ameba.SwiftBar PluginDirectory 2>/dev/null || true)" != "$plugins" ]]; then
run 'Set SwiftBar plugin directory' defaults write com.ameba.SwiftBar PluginDirectory -string "$plugins"
reload=1
else
ok 'SwiftBar plugin directory already configured'
fi
if ! launchctl print "$domain" >/dev/null 2>&1; then
warn 'SwiftBar launch skipped: no GUI session; rerun just bootstrap insomnia from the desktop'
return
fi
if ! launchctl print "$domain/com.wu-json.swiftbar-login" >/dev/null 2>&1; then
run 'Register SwiftBar login agent' launchctl bootstrap "$domain" "$plist"
else
ok 'SwiftBar login agent already registered'
fi
if [[ "$reload" == 1 ]] && pgrep -x SwiftBar >/dev/null 2>&1; then
run 'Quit SwiftBar to apply its plugin directory' osascript -e 'tell application "SwiftBar" to quit'
fi
if ! pgrep -x SwiftBar >/dev/null 2>&1; then
run 'Start SwiftBar' open -a SwiftBar
else
ok 'SwiftBar already running'
fi
}
bootstrap_tinycast() {
section 'Tinycast'
if [[ "$(uname -s)" != Darwin ]]; then warn 'Tinycast skipped: macOS only'; return; fi
Expand Down Expand Up @@ -292,11 +252,11 @@ bootstrap_tailscale() {
require_tool just just

case "${1:-all}" in
all) bootstrap_brew; bootstrap_stow; bootstrap_gh; bootstrap_pi; bootstrap_fish; bootstrap_insomnia; bootstrap_tinycast ;;
all) bootstrap_brew; bootstrap_stow; bootstrap_gh; bootstrap_pi; bootstrap_fish; bootstrap_tinycast ;;
brew) bootstrap_brew ;; stow) bootstrap_stow ;; gh) bootstrap_gh ;; pi) bootstrap_pi ;;
fish) bootstrap_fish ;; insomnia) bootstrap_insomnia ;; obscura) bootstrap_obscura ;; tailscale) bootstrap_tailscale ;;
fish) bootstrap_fish ;; obscura) bootstrap_obscura ;; tailscale) bootstrap_tailscale ;;
tinycast) bootstrap_tinycast ;;
*) fail "Unknown setup target: $1. Use all, brew, stow, gh, pi, fish, insomnia, tinycast, obscura, or tailscale." ;;
*) fail "Unknown setup target: $1. Use all, brew, stow, gh, pi, fish, tinycast, obscura, or tailscale." ;;
esac
printf '\n'
if [[ "$skipped" -gt 0 ]]; then
Expand Down
43 changes: 0 additions & 43 deletions swiftbar/.config/swiftbar/plugins/insomnia.sh

This file was deleted.

16 changes: 0 additions & 16 deletions swiftbar/Library/LaunchAgents/com.wu-json.swiftbar-login.plist

This file was deleted.

2 changes: 1 addition & 1 deletion tests/integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def main():
repo = base / 'repo with spaces'
home = base / 'home'
home.mkdir()
for directory in ('scripts', 'homebrew', 'fish', 'gh-dash', 'nvim', 'pi', 'wezterm', 'yazi', 'swiftbar', 'tinycast'):
for directory in ('scripts', 'homebrew', 'fish', 'gh-dash', 'nvim', 'pi', 'wezterm', 'yazi', 'tinycast'):
shutil.copytree(ROOT / directory, repo / directory,
ignore=shutil.ignore_patterns('node_modules', '__pycache__'))
shutil.copy2(ROOT / 'justfile', repo / 'justfile')
Expand Down
Loading