5 Commits
Author SHA1 Message Date
Claude Opus 5andbdeshi 1d3a539edd Add the window identification overlay
Every profile launches the same Claude Desktop binary with the same icon
and title, so with two or more open there was no way to tell which window
belonged to which profile at a glance. WindowOverlay pins a small tag —
profile name, in that profile's own dot colour — to each running managed
profile's window, tracked live via AXObserver notifications rather than
polling. Only a persistent process can hold a watcher like that, which is
exactly the gap the old one-shot CLI could never close.

Shown for every running managed profile, not just when two or more are
up: the tag is an identity marker, not merely a disambiguator. Never
shown on "default", which isn't a shannoncoat profile at all.

Positioned top-right, since top-left is where a window's close/minimize/
zoom controls live. Draggable in case that still obstructs something in a
particular layout, on a .nonactivatingPanel so dragging it doesn't steal
focus from the window underneath, with the offset persisted.

Attachment retries for ~3s rather than requiring the target's first
window to already exist: a cold Electron launch can take a second or more
between the process starting — which is what triggers the update, via
NSWorkspace's launch notification — and its first window existing. Losing
that race previously meant the tag silently never appeared at all.

Also ignores CHECKPOINT.md, a local session-handoff note.
0.0.5
2026-08-05 11:40:56 +06:00
Claude Opus 5andbdeshi 9673dc2792 Redesign the Manage window and fold About into it as a tab
The previous layout was a fixed 460x360 window regardless of tab or
state, with a plain unbordered table and text +/- buttons — it read as a
generic cross-platform port rather than something native. Several rows
also had no real width anchor at all, so they floated: flush against the
window's left edge with no margin, and in the add form's case wide enough
to overflow past the right edge.

- The window is no longer manually resizable. Each tab reports its own
  preferredContentSize, recomputed in viewDidLayout and after every state
  change, and NSTabViewController resizes the window to match. That is
  what actually fixes the large empty areas: a tab with less content gets
  a smaller window rather than sitting inside a fixed larger one.
- Every row now anchors its width to the one element with a real absolute
  width, fixing both the edge-touching and the overflow.
- Table gains a bezel border and alternating rows; form labels get a
  fixed trailing-aligned width so fields line up; the error label wraps
  instead of truncating; tab padding is consistent.
- About moves out of a separate panel into a third tab, with the app icon
  centred and enlarged to 96px.

Verified visually with a standalone harness that drives the real window
and screenshots it, rather than simulating input — scripting clicks into
the app itself needs an Accessibility grant this environment lacks.
0.0.3
2026-08-04 23:54:56 +06:00
Claude Opus 5andbdeshi c6a7da54ca Show profile paths, report the build version, and colour each profile
- Selecting a row in the Profiles tab shows its Claude Desktop and Claude
  Code dirs inline and selectable, instead of requiring a right-click
  "Reveal in Finder" to find out where a profile actually lives.
- build.sh stamps Contents/Resources/COMMIT with the short HEAD SHA, left
  empty when HEAD sits exactly on a tag (how a real release is built),
  since the version number alone is unambiguous there. About appends it
  when present, so two dev builds off the same VERSION are
  distinguishable. The update checker still compares plain semver.
- Profile dot colours are picked per NSApp.effectiveAppearance at render
  time: same hue either way, but full saturation with brightness split
  per background (1.0 dark, 0.55 light), so they read as bold hues rather
  than washing out on white or muddying against a dark menu.
0.0.2
2026-08-04 22:44:21 +06:00
Claude Opus 5andbdeshi 135db9b308 Rewrite shannoncoat as a native Swift menu-bar app
Replaces the original shannoncoat.sh entirely with in-process Swift. The
script stopped earning its keep once the rest went native, and being a
persistent process rather than a one-shot CLI is what later makes live
window tracking possible at all.

- ProfileStore: JSON config at ~/.shannoncoat/<name>.json (was hand-rolled
  YAML), with ~ expansion, paths relative to the config dir, and
  name/dir-collision validation in one place.
- ProcessInspector: sysctl(KERN_PROC_ALL/KERN_PROCARGS2) enumeration
  instead of shelling out to pgrep.
- ClaudeControl: launch via Process, focus via direct Accessibility calls
  (unhide, un-minimize, poll-for-window, AXRaise) instead of AppleScript,
  and a quit that respects Claude's own termination handling rather than
  unconditionally SIGKILLing after a flat 5s timeout.
- LiveState: NSWorkspace notification-driven state with no polling timer,
  so the menu bar reflects reality within about a second — including
  changes made outside the app entirely.
- ManageWindow: one non-modal window replacing what would otherwise be a
  string of separate popup alerts, with inline add/remove and directory
  pickers.
- LaunchAtLogin / UpdateChecker: SMAppService login-item toggle, and a
  minimal VERSION-file update check that alerts on a manual check and
  posts a quiet notification on the automatic one.

Also drops the standalone CLI in favour of GUI-only, and adds a
placeholder app icon drawn from vector shapes rather than composited on
top of Claude's own icon assets.

Claude Desktop is located at runtime rather than assumed: a path the user
picked previously, then /Applications, then a per-user ~/Applications
install, each accepted only if it actually contains the executable. If
none match, launching a profile asks the user to locate it once and
remembers the answer — a launch that silently does nothing gives them no
way to work out what's wrong.
0.0.1
2026-08-04 21:56:22 +06:00
bdeshi 815f0306c7 dump script 0.0.0 2026-08-04 20:32:14 +06:00