Two independent causes for the stuck-label / only-refreshes-on-click
behaviour, both fixed here.
1. NSStatusItem button defers the status bar paint for accessory apps
that are not foreground, so after refreshStatusButton sets the new
attributed title the menu bar visually froze until the user opened
the popover (which triggers NSApp.activate and a forced redraw
cycle). Explicit needsDisplay + display() forces the paint every
cycle.
2. The codeburn subprocess inherited the accessory app's default QoS,
which macOS background-throttles. That could stretch a sub-1-second
parse into tens of seconds on large corpora and overrun the 15s
refresh cadence. Set .userInitiated so the CLI runs at the same
priority it does from a user-interactive terminal.
The Plan pane previously told users to "run claude login in your
terminal, then retry" with no way to start the flow from the app.
Added a primary Connect Claude button on both the no-credentials and
failed states that launches Terminal.app with `claude login`, so the
OAuth flow is one click away.
TerminalLauncher.openClaudeLogin() uses a hardcoded literal, so no
user input reaches AppleScript. Refactored the common path into
runInTerminal(command:preValidated:) which re-validates any non-
literal input against CodeburnCLI.isSafe as defense-in-depth.
On machines without Terminal.app (iTerm/Ghostty/Warp), the button
surfaces an inline instruction to run `claude login` manually instead
of failing silently.