Skip to content

Bundle ID migration: com.herotools.openwispr → com.gizmolabs.openwhispr#669

Merged
gabrielste1n merged 5 commits intomainfrom
feat/bundle-id-migration
Apr 26, 2026
Merged

Bundle ID migration: com.herotools.openwispr → com.gizmolabs.openwhispr#669
gabrielste1n merged 5 commits intomainfrom
feat/bundle-id-migration

Conversation

@gabrielste1n
Copy link
Copy Markdown
Collaborator

@gabrielste1n gabrielste1n commented Apr 25, 2026

What this ships

  • Renames the macOS app bundle ID from com.herotools.openwispr to com.gizmolabs.openwhispr and the Windows AUMID to match — aligning with the legal entity that owns the signing identity (Gizmo Labs Inc., T832773L2J) and fixing the long-standing typo (openwispr was missing the trailing h)
  • Adds a one-time post-migration onboarding modal that walks returning users through re-granting Microphone, Accessibility, and System Audio after macOS resets TCC entries
  • Removes TccResetModal (and its locale keys) — it was added for an unshipped 1.6.10 → 1.6.11 Team ID transition and would have stacked on top of the post-migration modal
  • Bumps the package to 1.7.0 — this is the next public release. 1.6.11 was never published to GitHub; everything that was queued for it has been folded into 1.7.0 in the changelog

Why now

We migrated the macOS signing identity from HeroTools to Gizmo Labs and the bundle ID still carried the old org's reverse-DNS namespace plus a typo. Bundle IDs are baked into Apple's TCC database and the App Store Connect global namespace, so the rename wants to happen now while users are already going through a forced reinstall — the Team ID change broke auto-update from 1.6.10 regardless.

Auto-update cannot carry users across the rename. Squirrel.Mac's SQRLUpdater.updateBundleMatchingCurrentApplicationInDirectory: enforces a hard CFBundleIdentifier match (verified against Squirrel.Mac source). Existing 1.6.10 users are already stranded by the Team ID change anyway — the bundle ID rename adds nothing to their situation. Notification is out-of-band only (Discord, X, email, openwhispr.com banner). No in-app prompt is going out to existing users.

What carries over (zero migration code)

app.getPath('userData') is keyed by productName (OpenWhispr), not bundle ID. After installing the new bundle on top of an existing install:

  • Notes, transcriptions, conversations, folders, voice profiles (SQLite at ~/Library/Application Support/OpenWhispr/transcriptions.db)
  • API keys (.env in same userData)
  • Settings, hotkey config, custom dictionary, language preference (localStorage in same userData)
  • Whisper / Parakeet models, Qdrant vector index, embedding model, diarization models (~/.cache/openwhispr/ — hardcoded literal, not bundle-ID-keyed)

What resets

Permission Why Handled by
Microphone TCC keyed by bundle ID PostMigrationOnboarding modal
Accessibility Same Same — manual toggle in System Settings, live-polled
Screen Recording / System Audio Same Same
Apple Events Same Re-prompts on first paste
Custom URL protocol (openwhispr://) LaunchServices New bundle re-registers on first launch

Modal behavior

Scenario Modal shows?
Truly fresh install of 1.7.0 (no prior data) No — onboarding writes the .bundle-migrated sentinel on completion so the modal never fires for new users
Install of new bundle on top of 1.6.x data Yes on first Control Panel mount (DB exists + sentinel absent + macOS)
Click Done (mic granted) Sentinel .bundle-migrated written → never shown again
Click Remind Me Later / X / Esc Sentinel not written → re-shows next launch
Windows / Linux No (process.platform === 'darwin' gate in main process)
accessibility-missing event fires while modal pending Settings panel auto-open suppressed (modal already handles re-grant)

Implementation notes

  • Reuses the existing Dialog, PermissionsSection, usePermissions, and useSystemAudioPermission primitives — no new UI infrastructure
  • Sentinel is a file (.bundle-migrated in userData), not localStorage — survives if a user nukes their Local Storage dir
  • Detection runs in the main process; the renderer queries via IPC (get-post-migration-state, mark-bundle-migrated)
  • Two false-positive guards: (1) onboarding writes the sentinel for fresh users; (2) main-process detector requires both DB existence and absence of sentinel
  • Adds postMigration.{title,description,done,remindLater} keys across all 10 locale files
  • Strips the obsolete TccResetModal component, its tccResetModalSeen_1_6_11 localStorage key + helper, the mount/dismiss wiring in ControlPanel, and the tccReset.* locale keys (~145 lines deleted)

Related

Plan: Plans/bundle-id-migration-gizmo-labs.md — covers the rationale, what does and doesn't carry over, the Squirrel.Mac research, and the post-release monitoring strategy.

Aligns the macOS app bundle ID with the legal entity that owns the
signing identity (Gizmo Labs Inc., Team T832773L2J) and fixes the
long-standing typo in the previous identifier (com.herotools.openwispr
was missing the trailing h in 'whispr').

Auto-update cannot carry users across the rename — Squirrel.Mac
enforces CFBundleIdentifier matching when unpacking updates. Existing
users on the old bundle must manually re-download. Migration plan and
notification strategy live in
Plans/bundle-id-migration-gizmo-labs.md.

No data migration needed: app.getPath('userData') is driven by
productName ('OpenWhispr'), not appId, so notes, settings, .env, and
model caches all carry over on a fresh install of the new bundle.
Detects when a user installs the new com.gizmolabs.openwhispr bundle
on top of an existing com.herotools.openwispr install (data already in
~/Library/Application Support/OpenWhispr/ but no .bundle-migrated
sentinel) and shows a one-time onboarding modal that walks them
through re-granting Microphone, Accessibility, and System Audio.

Mirrors the TccResetModal structure exactly — same Dialog primitive,
same PermissionsSection, same usePermissions/useSystemAudioPermission
hooks, same Done/Remind Me Later UX. Different copy + different
sentinel-file flag (file-based instead of localStorage so it survives
even if userData/localStorage were nuked).

Suppresses the existing accessibility-missing Settings auto-open while
the post-migration modal is pending so users don't see two prompts.
Platform-gated to macOS in the main-process detector.

Adds postMigration.* i18n keys across 10 locales mirroring the
tccReset.* placement and tone.
- Bump package + lockfile to 1.7.0 (1.6.11 was never publicly released;
  going straight from 1.6.10 -> 1.7.0).
- Rename CHANGELOG section 1.6.11 -> 1.7.0 (2026-04-26) and add entries
  for the bundle ID rename and post-migration onboarding.
- Write the .bundle-migrated sentinel during onboarding completion so
  fresh 1.7.0 installs never see the "Welcome back" modal on relaunch.
  Migrating users skip onboarding (their flag carries over via
  productName-keyed userData) so they still get the modal correctly.
…boarding

TccResetModal was added for a 1.6.10 -> 1.6.11 Team ID transition that
never publicly shipped (1.6.11 was skipped in favor of going straight
to 1.7.0). Every user now goes 1.6.10 -> 1.7.0, where
PostMigrationOnboarding handles the same Mic / Accessibility / System
Audio re-grant walkthrough with the right copy.

Removes the dead component, its localStorage flag and helper, the
mount + dismiss wiring in ControlPanel, and the tccReset.* keys in
all 10 locale files. Also drops the redundant accessibility-missing
suppression check that was guarding against the second modal.
@gabrielste1n gabrielste1n merged commit f60339c into main Apr 26, 2026
6 checks passed
@gabrielste1n gabrielste1n deleted the feat/bundle-id-migration branch April 26, 2026 23:09
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