The Mac app showed one server at a time, and moving to another machine
meant Switch Server and a fresh connect. Now every server gets a tab in
the title bar, and every tab stays live.
- Tab strip: a small bundled page (assets/tabs.html) in its own web view
across the top of the window, with the traffic lights inset into it.
Each tab has a colour and a status badge: a red count when sessions
need you, an amber dot when they are waiting, a blue ring while they
work, a dashed circle while the server does not answer.
- The status comes from the app, not from the page: one thread per tab
reads GET /api/sessions every 2 seconds (macOS stalls hidden web
views), backs off for 60 s on a 429 and stops on 401/403, so a wrong
password is never retried in a loop.
- + or ⌘T opens the connect screen in a new tab. A server that is
already open just brings its tab forward instead of opening twice,
also when two connects race (checked again when the probe ends).
- Double-click or the right-click menu renames a tab; the same menu
sets the colour, reloads, reconnects, closes, or closes the others.
Tabs can be dragged. A new Server menu carries ⌘T, ⌘W, ⇧⌘T (reopen
closed tab, last 10), ⌘0, ⇧⌘[ / ⇧⌘] and ⌘1 to ⌘8 (⌘9 is the last
tab once there are nine). Close Window moves to ⇧⌘W. Ctrl+Tab and
Alt+1..9 stay with Codeman's own session switching.
- ⌘0 shows every server at once (assets/overview.html): the ones that
need you first, up to four sessions each with what they ask, and a
click on a session opens its tab and selects it.
- Tabs are saved in desktop.json (tabs, activeTab) and come back at
launch, connecting by themselves when auto-connect is on.
- Logins: each tab keeps its own Basic credentials, and a challenge is
answered only with the login of the tab whose web view asked
(macos.rs binds each WKWebView to its tab).
- Cookies: on macOS 14 and later every server gets its own WebKit data
store (WKWebsiteDataStore dataStoreForIdentifier, with a stable id
hashed from the server URL), so a server on port 3000 and a beta on
5000 of the same host cannot log each other out. Before macOS 14 a
second tab on a host that is already open is refused with a message.
The server used last before this change keeps the default store, so
its per-device settings (font size, skin) survive; every other
server starts those fresh once.
- The lid logo blink watches all open servers, and Keep This Mac Awake
follows the tab that runs on this Mac.
New pure model in src/tabs.rs (names, colours, order, shortcuts, strip
and overview state) with unit tests; agents.rs reads the per-session
detail for the badges and the overview; policy.rs parses the strip and
overview IPC and refuses it from any other frame. Browser tests drive
both bundled pages (test/desktop-tabs-pages.browser.test.ts) and the
connect page's restored-tab path.
Not yet run in a real window: the Mac mini has no screen session. The
owner checks the traffic-light placement, clicks under the transparent
title bar, window drag and zoom from the strip, keyboard focus after
strip clicks, and two logged-in servers side by side.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>