Home

dev / tinycast

publicthedavidweng/tinycast· sync paused
Overview Code History Branches Pull requestsIssuesInsights
main
HomeOverview Code PRsIssues

Add custom commands (#82)

2 months ago

4ff42b1
Authored
Jason Underhill7/29/2026, 5:04:56 PM
* Add custom launcher commands

* Add shell environment and confirmation options to custom commands

zsh reads ~/.zshrc only for interactive shells, so the runner's `zsh -lc`
never sees the user's aliases, functions or PATH and exits 127. Two reviewers
hit this with a .zshrc alias. Add a per-command "Load shell environment" flag
that switches to `zsh -ilc`, off by default so the fast path stays the default
and nobody pays for a slow shell config they didn't ask for.

Measured with no controlling terminal and stdin on /dev/null, as a GUI app
spawns a child: 9 ms for -lc, ~65 ms for -ilc against a real .zshrc (~11 ms
against a minimal one, so the interactive shell itself is ~2 ms and the rest is
the user's own config). Interactive prompts still cannot block -- a read gets
EOF and /dev/tty fails with "device not configured" -- and TINYCAST=1 is now
exported so a shell config can skip slow sections via
`[[ -n $TINYCAST ]] && return`. When a run exits 127 with the flag off, the
failure alert names the likely cause and offers to open Settings.

Add a per-command "Needs confirmation" flag, gated in runCustomCommand(id:) --
the single funnel both palette activation and the global hotkey reach, so
neither path can bypass it. The palette hides before the alert (floating panel
would cover it) and Return is bound to Cancel, as in confirmQuitAll: the
command is one Return away in the palette. NSAlert.runModal spins a nested run
loop where Carbon hotkeys keep firing, so a re-entrancy flag stops a held
shortcut stacking alerts.

Move the blocking waitUntilExit off the Swift cooperative pool onto a private
concurrent queue; a long `brew upgrade` would otherwise hold a pool thread for
minutes while the app scan and image decode compete for the same pool.

Take a CustomCommand draft in the store's add/update rather than a parameter
per field, and normalize a copy in validated/sanitized instead of rebuilding
from fields, so a future option cannot be silently dropped on backup import.

---------

Co-authored-by: abue-ammar <iabueammar@gmail.com>

Parentac15afe

25 files changed
  • AGENTS.md+4−0
  • README.md+2−1
  • Tinycast.xcodeproj/project.pbxproj+12−0
  • Tinycast/Core/AppCore.swift+120−2
  • Tinycast/Core/AppIndex.swift+44−12
  • Tinycast/Core/Backup/BackupActions.swift+24−0
  • Tinycast/Core/Backup/SettingsBackup.swift+18−1
  • Tinycast/Core/CommandRegistry.swift+1−1
  • Tinycast/Core/CustomCommand.swift+155−0
  • Tinycast/Core/FavoritesStore.swift+8−0
  • Tinycast/Core/HotKey/KeyShortcut.swift+3−0
  • Tinycast/Core/HotKeyManager.swift+29−1
  • Tinycast/Core/ShellCommandRunner.swift+107−0
  • Tinycast/Core/VisibilityStore.swift+8−0
  • Tinycast/Features/Launcher/LauncherView.swift+1−1
  • Tinycast/Features/RootPaletteView.swift+1−1
  • Tinycast/Features/Settings/BackupSettingsView.swift+2−1
  • Tinycast/Features/Settings/CustomCommandsSettingsView.swift+247−0
  • Tinycast/Features/Settings/SettingsRootView.swift+6−1
  • Tools/custom-command-test.swift+134−0
  • docs/architecture.md+3−2
  • docs/custom-commands.md+93−0
  • docs/development.md+11−0
  • docs/hotkeys.md+2−1
  • docs/launcher.md+10−0