Skip to content

Start at login and open the panel on first launch (1.4.0) - #23

Merged
vimoxshah merged 1 commit into
mainfrom
fix/first-launch-login-item
Sep 16, 2026
Merged

vimoxshah merged 1 commit into
mainfrom
fix/first-launch-login-item

Conversation

@vimoxshah

Copy link
Copy Markdown
Owner

Why

A DMG install had no way back from a restart, and no way to find itself on first launch.

TokenFlow is an LSUIElement app — no Dock icon, no window. Nothing registered it as a login item, so after a reboot there was no sign it had ever been installed. The watcher kept collecting (its LaunchAgent sets RunAtLoad); only the menu bar went missing, which is the confusing half.

And double-clicking it the first time looks like nothing happened. The only sign is two characters — TF — at the right end of the menu bar, which nobody has a reason to look for.

What changed

Launch at login. SMAppService.mainApp.register(), once, guarded three ways:

  • The bundle must sit in /Applications or ~/Applications. A first launch straight off the mounted DMG is App-Translocated to a temporary read-only path, and a login item aimed there breaks the moment the image is ejected — worse than not registering. The attempt flag is written inside that guard, so open-from-DMG-then-drag still registers on the next launch.
  • Only .notRegistered is acted on. .requiresApproval means the user turned it off; re-registering would fight them every launch.
  • Failure is silent. No new UI, no toggle — System Settings → General → Login Items is the off switch.

Panel opens itself once. Written when the panel actually shows rather than when it is attempted, so a menu bar with no room for the status item gets it next launch instead of never.

Docs. docs/getting-started.md said the app "builds and launches everything it needs" — that reads as automatic and never was. README and getting-started now describe the real first launch.

Verification

Neither behaviour can be exercised on a Mac without Xcode, so this leans on CI:

  • test/bundle.test.js now reads otool -L off the built binary and fails if ServiceManagement.framework is not linked.
  • The two macos-latest jobs are the real gate — that is where bundle.test.js compiles main.swift.
  • Locally: swiftc -parse clean, the SMAppService block type-checks and links in isolation, npm run lint clean, 841 tests / 838 pass / 3 skipped (the app-bundle suite skips without Xcode).

Not verified by me: register() actually succeeding at runtime under ad-hoc signing. That needs a real install.

🤖 Generated with Claude Code

A DMG install had no way back from a restart. TokenFlow is an LSUIElement app:
no Dock icon, no window, and nothing registered it as a login item, so after a
reboot there was no sign it had ever been installed. The watcher kept
collecting — its LaunchAgent sets RunAtLoad — and only the menu bar went
missing, which is the confusing half.

SMAppService.mainApp.register() now runs once, guarded three ways. The bundle
must sit in an Applications folder: a first launch straight off the mounted DMG
is App-Translocated to a temporary read-only path, and a login item aimed there
breaks on eject, which is worse than not registering. The attempt flag is
written inside that guard, so open-from-DMG-then-drag still registers next
launch. Only .notRegistered is acted on, because .requiresApproval means the
user turned it off. Failure is silent — starting at login is a convenience, not
something to greet a new user with an error about.

The panel also opens itself once per machine. Double-clicking an accessory app
looks like nothing happened; the only sign is two characters at the right end
of the menu bar. The flag is written when the panel actually shows, not when it
is attempted, so a menu bar with no room for the status item gets it next
launch instead of never.

Neither behaviour can be exercised on a Mac without Xcode, so the app-bundle
suite now reads otool -L off the built binary and fails if
ServiceManagement.framework is not linked.

Also: docs/getting-started.md said the app "builds and launches everything it
needs", which reads as automatic and never was.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@vimoxshah
vimoxshah merged commit 56faf4f into main Sep 16, 2026
9 checks passed
@vimoxshah
vimoxshah deleted the fix/first-launch-login-item branch September 16, 2026 15:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant