Add Initial Dir field to SSH bookmarks#292
Open
nathandale wants to merge 12 commits intofitztrev:masterfrom
Open
Add Initial Dir field to SSH bookmarks#292nathandale wants to merge 12 commits intofitztrev:masterfrom
nathandale wants to merge 12 commits intofitztrev:masterfrom
Conversation
… via NSTask - Update deployment target to macOS 12.0 across all build configs - Add ARCHS=$(ARCHS_STANDARD) for arm64 + x86_64 Universal Binary - Remove all AppleScript .scpt files and infrastructure - Replace openHost: with NSTask-based terminal dispatch: - "ghostty" → ghostty -e <cmd> - "iterm" / "iterm2" → osascript tell iTerm - "terminal" (default) → osascript tell Terminal.app - Set terminal via "terminal" key in ~/.shuttle.json Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Replace all AppleScript/.scpt infrastructure with NSTask-based terminal dispatch supporting Ghostty, iTerm2 (osascript one-liner), and Terminal.app - Universal Binary: ARCHS=$(ARCHS_STANDARD), deployment target 12.0 - New JSON schema: servers[] + categories[] replaces recursive hosts tree - ServerManagerWindowController: programmatic Contacts-style manager window with NSOutlineView sidebar (category group headers + server rows), detail form pane (name, hostname, user, port, SSH key picker, category, terminal overrides), Save/Delete/Add Category actions persisted to JSON - LAN SSH scanner: async /24 port-22 sweep via GCD, shown as Local Network submenu with Scan Now action and age display - Manager... item inserted into Settings submenu at runtime Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Import fixes:
- Replace deprecated NSOKButton with NSModalResponseOK
- Call loadMenu after successful import so menu refreshes immediately
- Properly clear stale backup before move; restore backup on copy failure
- Add allowed file type filter (json) to open panel
Export fixes:
- Replace deprecated NSFileHandlingPanelOKButton with NSModalResponseOK
- Set default filename to shuttle.json in save panel
- Remove pre-existing file at destination before copy (prevents silent failure)
LAN scanner hostname support:
- IP scan now calls reverseResolve: (getnameinfo) for each discovered host,
storing {ip, hostname} dicts instead of bare IP strings
- Add NSNetServiceBrowser scanning _ssh._tcp. on local. domain for
Bonjour/mDNS hosts (finds .local hostnames without needing an IP sweep)
- rebuildLanSubmenu merges both sources, deduplicates by hostname,
shows "hostname (ip)" label and SSHes to hostname when available
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- NSVisualEffectView sidebar with Sidebar material (translucent, auto dark mode) - NSOutlineView with source-list highlight style; group headers in uppercase semibold 11pt secondary-color text, server rows at 28pt row height - NSSegmentedControl (+/−) replaces individual Add/Remove buttons; lightweight font for +/− glyphs - NSGridView form with right-aligned 12pt secondary-color labels and 13pt fields, perfectly pixel-aligned via column width/xPlacement settings - Name field uses 15pt font; hostname placeholder updated to include .local hint - Save button set as key equivalent (Return = blue/default); Delete button uses hasDestructiveAction for system styling - Form centered (slightly above vertical midpoint) inside resizable detail pane - Wipe legacy hosts from ~/.shuttle.json, reset to clean servers/categories schema Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Terminal.app double-window fix: the previous one-liner caused Terminal to open its startup window when not running, then do script created a second window. New approach: activate Terminal first (so its startup window exists), then run do script in front window — always results in exactly one terminal session. LAN scan sort: replaced hostname alphabetical sort with numeric sort by last octet of IP address. Bonjour-only entries (no IP) sort to the end. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Each scanned host now shows a submenu instead of a direct connect action:
- Connect — launches SSH as before
- Save to Address Book… — prompts for a display name (pre-filled with
the detected hostname) and a category picker, then writes the host
into servers[], persists to JSON, and reloads the menu
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
buildMenuFromServers now encodes the server's terminal key as a 6th field in the representedObject string. openHost: reads it and uses it if set, falling back to the global terminalPref, then to "terminal". This means a server with "terminal":"ghostty" will open in Ghostty even if the global setting says otherwise. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- installedTerminals: queries NSWorkspace URLForApplicationWithBundleIdentifier: for Terminal, iTerm2, Ghostty, Alacritty, kitty, Warp, Hyper, Rio — only returns what is actually installed on the machine - executableForBundleID: resolves the real binary path via NSBundle, no more hardcoded /Applications/Ghostty.app/... paths - openHost: dispatches per terminal using dynamic binary lookup; Warp uses its URL scheme; unknown terminals fall back to Terminal.app - Manager terminal popup rebuilt from installedTerminals at open time; stores/restores the JSON identifier (e.g. "ghostty") not the display name Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two root causes of the launch failure: 1. Tilde not expanded: identity_file stored as ~/.ssh/id_ed25519 was passed literally to Ghostty which doesn't shell-expand it. Fix: call stringByExpandingTildeInPath in sshCommandForServer:. 2. Command passed as single string: ghostty -e expects separate argv entries, not one blob. Ghostty was receiving the whole ssh command as a single argument and failing with "No such file or directory". Fix: use sh -c <sshCmd> so the shell interprets it correctly. 3. App Management privacy prompt: NSTask accessing another app's internal binary (Ghostty.app/Contents/MacOS/ghostty) triggers macOS Sequoia's App Management entitlement check on every launch. Fix: replace NSTask with NSWorkspace openApplicationAtURL:configuration: which is the proper API for launching apps — macOS does not flag it. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Covers: address book, Manager window, multi-terminal detection and dispatch, per-server SSH key and terminal override, LAN scanner (Bonjour + port sweep + reverse DNS), import/export, full JSON schema reference, build instructions, and a comparison table vs the original. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
openApplicationAtURL:configuration: only passes arguments when launching a new process; if the terminal was already running macOS silently focused it and dropped the SSH command. Setting createsNewApplicationInstance=YES forces a fresh process each time so every bookmark click opens a new terminal window with its own SSH session. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds an optional "Initial Directory" field to each server in the Manager. When set, the SSH command becomes: ssh host -t 'cd <dir> && exec $SHELL -l' The -t flag forces a pseudo-TTY and exec $SHELL -l replaces the subshell with a proper login shell, preserving prompt and aliases. Stored as "initial_directory" in ~/.shuttle.json. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
ssh host -t 'cd <dir> && exec $SHELL -l'so you land in the specified directory with a full login shellinitial_directoryin~/.shuttle.json; leaving it blank preserves existing behaviorTest plan
~/bin, save~/bin-tflag)~/.shuttle.jsoncontains / omitsinitial_directorycorrectly🤖 Generated with Claude Code