Compare commits

...

184 commits

Author SHA1 Message Date
Kit Langton
3e300721b8 docs: point to the Rust rewrite at anomalyco/hex 2026-10-14 14:42:37 -07:00
Kit Langton
f58d52c4cc Release 0.8.5 2026-08-26 23:47:08 -04:00
Kit Langton
df37c99b7c feat: point legacy Hex users to the Rust beta
Add a dismissible Settings banner and a persistent About link to hex.kitlangton.com, without installing or migrating anything. Keep the announcement limited to supported Macs and add isolated native screenshot coverage.

Update the legacy repository README to direct new development to anomalyco/hex while preserving Swift history and downloads. Closes #291.
2026-08-26 23:35:40 -04:00
Kit Langton
881c46f236 Release 0.8.4 2026-07-19 17:00:33 -04:00
Kit Langton
9c597cb77d Prevent first-launch crash during hotkey setup
Hex 0.8.3 added a stale-TCC fallback that synchronously read KeyEventMonitor state while the first handler registration barrier already owned the same dispatch queue. When Input Monitoring was not yet granted, libdispatch trapped on the recursive sync and crashed fresh installs during launch.\n\nMake monitor state reads detect queue re-entry, keep external reads synchronized against barrier writes, and snapshot event handlers only after entering the queue. Inject the system permission probes so the denied-permission registration path has a deterministic regression test.\n\nFixes #254\nFixes #258\nFixes #265
2026-07-19 16:13:13 -04:00
Kit Langton
ca96427990 Harden audio lifecycle changes after review: quit deadlock, lock-state tracking, rebuild gating
Review fixes for the audio engine lifecycle overhaul (8739929), addressing
findings from a three-way simplification/correctness/efficiency review.

Correctness:

- applicationWillTerminate pumps the main run loop while waiting for
  recording.cleanup() instead of blocking on the semaphore outright.
  cleanup() hops to the main actor (media-key resume) and the main queue
  (Core Audio listener removal), so the blocking wait would have
  deadlocked and hit its 3s timeout in exactly the quit-after-recording
  scenario the #245 fix targets, exiting with teardown incomplete.
- Warm-capture suspension is now tracked as a Set<CaptureSuspensionSource>
  (systemSleep / displaySleep / screenLock) instead of one bool. This
  fixes two leaks of the warm mic at a locked screen: wake notifications
  fire while the screen is still locked (the bool version resumed
  immediately; now capture stays suspended until unlock removes the last
  source), and locking during an active recording previously never set
  the flag (now the fact is always recorded and
  finalizeCaptureStateAfterRecording re-suspends once the recording
  stops).
- Mid-recording engine rebuilds are gated on the input device actually
  changing or the engine having died (configuration change). Output-only
  device changes (plugging in headphones) previously triggered
  restartPreservingRecording and caused an avoidable audio gap in active
  dictations.
- startRecording cancels any pending environment-change debounce task;
  a device event within 250ms of the hotkey press would otherwise fire
  into the new recording and force a pointless mid-recording rebuild.

Efficiency:

- Idle rebuilds are skipped when the engine is already running on the
  resolved input device. Bluetooth connects fire 3-5 notifications over
  1-2 seconds (devices-changed, default-input-changed,
  default-output-changed, ...); the first rebuild settles the engine and
  the rest now no-op instead of causing repeated teardown+rebuild cycles.
  This also absorbs the wake+unlock double-resume.

Simplification:

- Shared tearDownWarmCapture() replaces two divergent suspend branches.
- handleCaptureEnvironmentChange is synchronous (no awaits), documenting
  that its recording-state snapshot cannot go stale via actor reentrancy.
- SuperFastCaptureController.stop() does one processingQueue hop via
  detachEngine(clearingRecordingState:) instead of two.
- SoundEffect drops the isEngineRunning flag that shadowed
  engine.isRunning, logs shutdown honestly, and no longer prewarms an
  engine on enable that the idle timer would stop 10 seconds later.
2026-07-09 16:22:50 -04:00
Kit Langton
8739929294 Overhaul audio engine lifecycle: route-change recovery, sleep suspension, teardown fixes
Addresses the audio-engine bug cluster (#209, #218, #226, #245, #246,
#251, #252) while keeping Super Fast Mode's warm-microphone design intact.

Root problems, all variations of 'the engine outlives the world it was
built for':

1. Route/device changes while idle only *deferred* the engine rebuild to
   the next recording, leaving the stale engine running against the old
   route indefinitely. That kept coreaudiod churning while idle (#209)
   and made the first post-change recording unreliable.
2. Route/device changes *during* a recording deferred entirely: the
   recording kept 'running' while the dead engine captured nothing,
   producing empty transcripts after Bluetooth connects, A2DP<->HFP
   switches, and AirPods handoffs (#251, #252, #218, #226).
3. App-quit teardown was a fire-and-forget Task racing process exit,
   with SuperFastCaptureController.deinit as a second competing teardown
   path - the EXC_BAD_ACCESS in AVAudioEngine teardown (#245).
4. The sound-effects output engine (isAutoShutdownEnabled = false) ran
   forever once started, keeping an output IOProc alive even in standard
   mode.

Fixes:

- SuperFastCaptureController gains restartPreservingRecording(reason:),
  which rebuilds engine/tap/converter while keeping the active
  AVAudioFile open, so mid-recording route changes resume capture onto
  the same file (small gap) instead of silently losing the rest of the
  take. startIfNeeded/stop are refactored around shared
  armEngine/detachEngine helpers; detachEngine bumps the capture
  generation so in-flight tap callbacks from the old engine are ignored.
- RecordingClient rebuilds the engine immediately (debounced 250ms) on
  idle environment changes instead of deferring; failures fall back to
  the previous deferred-restart marker.
- The warm engine is suspended on screen lock / display sleep / system
  sleep and rearmed on unlock/wake. Nobody dictates at a locked screen,
  the mic indicator no longer glows while locked, and a whole class of
  stale-engine-across-sleep states disappears. Active recordings are
  never interrupted; an explicit recording request overrides suspension.
  The pre-roll ring buffer is cleared on suspend so no pre-lock audio is
  retained.
- applicationWillTerminate now blocks (3s bound) on recording.cleanup()
  via a detached task + semaphore, making teardown deterministic.
- The sound-effects engine stops 10 seconds after the last play;
  restarting on the next play costs milliseconds.

The persistent mic indicator while unlocked-and-idle (#246) remains
by design when Super Fast Mode is on - that is what keeps the 0.45s
pre-roll available - but it now clears whenever the screen is locked
or asleep.
2026-07-09 14:31:36 -04:00
Kit Langton
2c5d8aea4d Add Whisper Large v3 Turbo to model library, use honest Whisper size names
Adds openai_whisper-large-v3-v20240930_turbo_632MB to the curated model
list (#185): near large-v3 accuracy at several times the decode speed, in
632MB instead of 1.5GB. It slots between Base and Large v3 as the best
accuracy-per-second Whisper option.

Also renames the Whisper entries to their real model sizes: Tiny and Base
were previously displayed as "Whisper Small (Tiny)" and "Whisper Medium
(Base)", which misrepresented which checkpoints they actually are. With
the model library now showing honest install state, the names should be
honest too. Display names are UI-only (selection is stored by
internalName), so existing selections are unaffected. Large v3's accuracy
rating is bumped to 5 stars so the Turbo tradeoff (slightly lower
accuracy, much faster) reads correctly in the list.
2026-07-09 13:18:10 -04:00
Kit Langton
2840b0f511 Release 0.8.3 2026-07-09 12:39:23 -04:00
Kit Langton
224822d51e Fix hotkeys dying from stale permission checks and sleep cycles
Fixes #250, where four reporters on 0.7.6 hit dead hotkeys with symptoms
that fingerprint a stale Input Monitoring TCC grant: modifier-only hotkeys
kept working while keyed hotkeys and the hotkey recorder went dead, often
after sleep or MDM re-login, and toggling the permission in System
Settings did not help.

Root cause was Hex trusting cached permission checks over reality, in two
compounding places in KeyEventMonitorClient:

1. The tap callback dropped events whenever the cached
   IOHIDCheckAccess/AXIsProcessTrusted flags said permissions were
   missing - even for events macOS was demonstrably delivering.
2. desiredMonitoringState() required inputMonitoringTrusted, so the 100ms
   permission watchdog tore down a *working* tap as soon as
   IOHIDCheckAccess returned a stale denial.

macOS withholds keyDown/keyUp from taps lacking Input Monitoring but
still delivers flagsChanged to Accessibility-granted taps, which is why
victims saw modifiers work while keys died.

The fix treats event arrival as the authoritative permission signal:

- A keyDown/keyUp reaching the tap proves Input Monitoring is granted;
  noteEventDelivered() self-heals the cached flag and
  currentInputMonitoringTrust() honors that proof over a stale denial
  (which also keeps the settings permission indicator honest).
- The tap is no longer torn down when the Input Monitoring check reports
  denied; without the permission macOS simply withholds key events, and
  keeping the tap alive is also what triggers the permission prompt.
- The tap is recreated on NSWorkspace.didWakeNotification and
  sessionDidBecomeActiveNotification (matching the reporter whose
  hotkeys died after sleep/MDM logout), and the watchdog re-enables taps
  macOS silently disabled via CGEvent.tapIsEnabled.
2026-07-09 12:31:54 -04:00
Kit Langton
9531c0bbe4 Release 0.8.2 2026-07-09 10:58:06 -04:00
Kit Langton
eae358bbdb Overhaul model library UX and harden model selection state
Model library rows now have explicit Download buttons, a visible menu for
Show in Finder / Remove Download (with confirmation), and clear In Use /
Installed status labels. Row clicks select installed models only.

State hardening behind the UX:
- Availability scans can no longer clear selectedModel to "" on false
  negatives (this hit users after FluidAudio 0.15.5 moved its cache dir:
  the scan came back empty, 0.8.0 wiped the setting, and push-to-talk
  silently did nothing afterward).
- Selection matching is pattern-aware (ModelPatternMatcher.namesMatch)
  instead of exact-ID, so legacy/glob selections resolve correctly.
- downloadModel resolves glob selections to concrete names up front so
  completion updates rows and settings consistently.
- Stopping a recording with no model selected now discards the audio and
  flashes model setup instead of handing an empty model name to the
  transcriber (which produced junk like "[BLANK_AUDIO]").
- The summary card shows an honest orange "Not downloaded" state with an
  inline Download button when the selected model is missing on disk.

Also trims per-tick re-renders of non-downloading rows and redundant
settings writes on repeated scans.
2026-07-09 10:49:57 -04:00
Kit Langton
72e6398b2d Release 0.8.1 2026-07-08 22:25:17 -04:00
Kit Langton
cd971a36ce Reuse Parakeet downloads after FluidAudio upgrade
FluidAudio 0.15.5 changed Parakeet's canonical cache directory by dropping the -coreml suffix. Atomically migrate complete legacy caches into the new location, replacing interrupted partial downloads while preserving both directories if validation fails.
2026-07-08 22:18:07 -04:00
Kit Langton
f5dcba3ea1 Release 0.8.0 2026-07-08 22:03:46 -04:00
Kit Langton
2b5fb1548b Restore downloaded models after restart
Use FluidAudio's version-aware cache APIs instead of guessing its directory layout. Keep a previously completed selection visible while availability loads, and cover the restart state with a regression test.
2026-07-08 14:31:00 -04:00
Kit Langton
10e75b99a6 Simplify output transforms and model suggestions
Restructure the transforms page around a compact preview, word-rule editor, and separate output formatting controls. Suggest English Parakeet for Auto or English output, while retaining multilingual Parakeet for explicitly non-English output.
2026-07-08 14:15:37 -04:00
Kit Langton
8e6e04189f Harden recording and refresh model settings
Make recording stops explicit, reject stale capture callbacks, and clean up captured audio reliably. Replace the old model list with the model library, preserve valid selections across failures, gate download updates by session, and add reducer coverage. Refresh stable dependencies, migrate FluidAudio 0.15.5, restore Xcode test linking, and polish update, changelog, and transform behavior.
2026-07-08 13:30:07 -04:00
Kit Langton
db31b0a31e wip: recording stop-result hardening and model download UI improvements 2026-07-08 12:17:03 -04:00
Ryan Vogel
276da69864
Add lowercase and punctuation paste transforms (#253)
* Add configurable paste formatting transforms

Add independent settings to lowercase pasted transcripts and remove Unicode punctuation. Persist both options, include them in the transforms preview, and apply them after existing word modifications before paste and history storage.

Cover formatting combinations and legacy settings migration with tests.

Opencode-Session: ses_0bd949d00fferT6nCF6ntO80Mp
Opencode-Message: msg_f42760e83001l5zbmkL7mxckWu
Opencode-Agent: build

* Reference PR in paste transforms changeset

Opencode-Session: ses_0bd949d00fferT6nCF6ntO80Mp
Opencode-Message: msg_f4276da02001R7u6klN4JoUXT7
Opencode-Agent: build
2026-07-08 12:07:04 -04:00
Kit Langton
71878b72de
fix(audio): defer capture rebuilds during route changes (#236) 2026-06-04 11:41:15 -04:00
Kit Langton
c00a91d01c
fix: harden microphone and recording reliability (#235)
* fix: harden microphone and recording reliability

* refactor: simplify reliability fixes
2026-06-04 11:35:12 -04:00
Kit Langton
f988cb78c5 Release 0.7.6 2026-05-06 09:03:26 -04:00
Kit Langton
f4cecbbf30 Quiet login launches and reveal Parakeet caches correctly
Two small first-experience fixes that surfaced after 0.7.5 shipped:

- Launching at login no longer pops the Settings window unless the user opens it explicitly. The previous policy only suppressed when the dock icon was hidden, so most 'Open on Login' users got a settings panel in their face every boot. Closes #222.

- 'Show in Finder' on a Parakeet model now opens FluidAudio's on-disk cache at ~/Library/Containers/com.kitlangton.Hex/Data/Library/Application Support/FluidAudio/Models instead of the WhisperKit-only models folder, which made users think their Parakeet download had silently failed. Closes #205.
2026-05-06 08:53:28 -04:00
Kit Langton
f4764d5867 Release 0.7.5 2026-05-03 18:58:19 -04:00
Kit Langton
b5a19b4870 Restore Sonoma support and faster first capture 2026-05-03 18:52:05 -04:00
Kit Langton
67d187d6d9 Release 0.7.4 2026-05-03 13:25:27 -04:00
Kit Langton
5a4af9bdb6 Fix silent recordings from call audio devices
Multichannel input devices and video-call apps can expose the microphone as a multi-channel stream. Explicitly route channel 0 into Hex's mono converter and restart the capture engine when AVAudioEngine reports a configuration change, avoiding all-zero capture buffers and hallucinated transcripts like "Thank you."

Fixes #204. Related to #206.
2026-05-03 13:05:28 -04:00
Kit Langton
d4c45d5233
Merge pull request #200 from fitchmultz/fix/sound-effects-engine-lifecycle
Avoid priming sound effects when disabled
2026-04-01 14:42:10 -04:00
Mitch Fultz
f31e8972fe Use shared settings for sound effect gating 2026-04-01 11:36:20 -06:00
Mitch Fultz
b78f049ce3 Avoid priming sound effects when disabled
Hex currently preloads and starts its sound-effects AVAudioEngine on launch, even when sound effects are disabled. That keeps an unnecessary Core Audio output assertion alive for the app lifetime.

This change keeps the low-latency path for users who have sound effects enabled, but avoids starting the engine when the feature is disabled and shuts it back down if the setting is toggled off.

Validation:
- cd HexCore && swift test
- xcodebuild -scheme Hex -configuration Release CODE_SIGNING_ALLOWED=NO build
- xcodebuild -scheme Hex -configuration Debug CODE_SIGNING_ALLOWED=NO build
- runtime check: patched debug app launched with sound effects disabled did not create a new audio-out sleep assertion

Note: xcodebuild test still fails in this repo because HexTests TEST_HOST resolves to Hex.app while Debug builds produce Hex Debug.app.
2026-04-01 10:29:00 -06:00
Kit Langton
bafb19a864 Release 0.7.3 2026-03-26 15:15:38 -04:00
Kit Langton
b290fe6b8d Update settings bindings for current TCA
The Xcode 26.4 toolchain no longer accepts mutating shared settings directly through view bindings in these settings and remapping screens. Route those controls through explicit reducer actions so the release archive can compile cleanly with the newer TCA/runtime combination.

Verified by producing a fresh Release archive at build/Hex.xcarchive.
2026-03-26 15:08:10 -04:00
Kit Langton
dcc9d317ef Pin TCA to the Xcode 26.4 fix
Release archives were failing in swift-composable-architecture because the current pinned revision still used non-sendable writable key paths under this Xcode toolchain. Pin to upstream commit 055ca45, which contains the Xcode 26.4 compatibility fix, alongside the existing Pow pin so release builds can complete again.

Verified by resolving packages and producing a fresh Release archive at build/Hex.xcarchive.
2026-03-26 14:53:21 -04:00
Kit Langton
c2e9a4dad2 Pin Pow to the .pi archive fix
Release archives started failing inside Pow 1.0.5 with an ambiguous use of .pi in Anvil.swift on the current Xcode toolchain. Pin the package to upstream commit 1b4b1dd, which contains the minimal fix, so Hex can archive again without changing app behavior.

Verified by resolving packages and producing a fresh Release archive at build/Hex.xcarchive.
2026-03-26 14:37:52 -04:00
Kit Langton
7340d1eb31 Restore double-tap lock after stale stop races
Double-tap lock could leave the UI recording after a short-recording cleanup from the first tap arrived after the second tap had already started a new session. Cancel stale cleanup work, ignore delayed capture-engine stops once a newer session exists, and add regression coverage around the reducer/client boundary. Fixes #193.

HexCore swift tests pass. App-level xcodebuild remains blocked locally by the IDESimulatorFoundation plugin failure in this Xcode install.
2026-03-26 14:21:42 -04:00
Kit Langton
7b58a077cb Release 0.7.2 2026-03-23 21:37:02 -04:00
Kit Langton
55249a691b Prevent clipped endings in super fast recordings
Base capture-engine stop finalization on the observed callback cadence so Hex can keep the last in-flight audio without always paying the full worst-case delay. Also move the stop chime until after capture finishes so the grace window does not risk recording Hex's own feedback.
2026-03-23 21:21:00 -04:00
Kit Langton
d9e40cc778 Stabilize capture startup and microphone selection
Use the capture engine for standard recordings so both recording modes share the same restart and telemetry path while keeping AVAudioRecorder only as a fallback.

Also keep the microphone picker visible, add a stable unavailable-device fallback row, and refresh the device list on wake, app activation, and Core Audio device changes so dock and interface swaps stop leaving the menu blank or stale.
2026-03-16 19:48:35 -04:00
Kit Langton
c661ab8c8a Release 0.7.1 2026-03-16 11:17:58 -04:00
Kit Langton
ed6983618b Keep hidden login launches out of the foreground
Detect when Hex starts as a login item and skip opening windows or activating the app when the Dock icon is hidden.

This also limits app-mode updates to the Dock Icon setting itself so ordinary settings edits stop bouncing the settings window out of the active state.
2026-03-16 11:07:23 -04:00
Kit Langton
9de41846ff Release 0.7.0 2026-03-16 09:49:39 -04:00
Kit Langton
53b4d40689 Recover warm capture after wake and route changes
Restart the warmed recording path when the Mac wakes or the active audio route changes, and defer that rebuild until stop if a take is already in progress.

This also adds startup and first-buffer telemetry so we can see idle time, device selection, restart reasons, and capture latency in the unified logs while tuning the fast-start path.
2026-03-15 22:07:57 -04:00
Kit Langton
62002472cc Simplify settings hotkey and model storage logic
Unify settings hotkey capture, remove duplicate model refresh work, and centralize Hex storage paths in HexCore so settings, history, and model management reuse the same helpers.

This trims repeated file-management code, makes Parakeet checks typed instead of string-based, and keeps cleanup behavior consistent without touching the in-flight recording changes.
2026-03-15 22:07:22 -04:00
Kit Langton
3e325fc8ed Reduce super fast buffer carryover between recordings
Tighten the warm capture window and clear the in-memory ring buffer when a recording finishes so the previous tail does not leak into the next take.

This keeps the fast-start path while reducing repeated last-word artifacts during local testing.
2026-03-15 14:06:29 -04:00
Kit Langton
c5d5162bf7 Keep the microphone warm for faster recording starts
Add an opt-in Super Fast mode that keeps live capture warm with a short in-memory preroll and falls back to the existing recorder path when needed.

This targets the first-word clipping that shows up after Hex has been idle for a while, and exposes the tradeoff clearly in Settings so users can choose instant capture when they want it.
2026-03-15 13:39:35 -04:00
Kit Langton
f29125dd71 Release 0.6.10 2026-02-26 14:26:12 -05:00
Kit Langton
7c573eab79 Update localization strings for double-tap lock setting 2026-02-26 12:34:06 -05:00
Kit Langton
7af7cd91b3 Add changeset for dependency updates 2026-02-26 12:33:49 -05:00
Kit Langton
4b72d7b9bc Update dependencies (TCA 1.23, Sparkle 2.8, swift-dependencies 1.11)
Bump minimum versions:
- Sparkle: 2.6.4 → 2.8.1
- swift-composable-architecture: 1.17.1 → 1.23.1
- swift-dependencies: 1.6.3 → 1.11.0
- swift-log: 1.8.0 → 1.10.1
- xctest-dynamic-overlay: 1.8.1 → 1.9.0

Removed unused transitive deps from lockfiles and fixed
HexCore/Package.swift indentation.
2026-02-26 12:26:05 -05:00
Kit Langton
1ffead716e
Merge pull request #175 from dmmulroy/feat/double-tap-lock-setting
Add toggle to disable double-tap lock mode
2026-02-26 12:25:47 -05:00
Dillon Mulroy
c018c408af
Add toggle to disable double-tap lock mode
Adds a settings switch to disable double-tap lock behavior while keeping press-and-hold recording available. Also normalizes persisted settings so double-tap-only cannot remain enabled when lock is off, with regression tests for migration and decode paths.
2026-02-25 15:38:34 -05:00
Kit Langton
8fff3328fa
Update README.md 2026-01-15 09:00:47 -05:00
Kit Langton
badf1ecf10 Release 0.6.9 2026-01-13 11:53:27 -05:00
Kit Langton
74893ab860 Support escape sequences in word remappings (#140)
Users can now use \n, \t, \r, and \\ in replacement strings to insert
newlines, tabs, carriage returns, and literal backslashes. This enables
voice commands like "new line" → \n without requiring UI changes.

Adds 10 tests covering escape sequence processing and edge cases.
2026-01-13 11:49:09 -05:00
Kit Langton
12fa77ac32
Merge pull request #150 from ruseel/issue-122-pr-2
Fix #122 -
2026-01-13 11:20:42 -05:00
r
bfb9fb2ee8 Fix hotkey unresponsiveness by improving task cancellation handling (#122)
`Task.sleep(nanoseconds: .max)` returns immediately instead of sleeping
indefinitely. This broke the cancellation handler mechanism, causing hotkeys to hang.

Demonstration of sleep(.max) that returns immediately.

```bash
    % swift -e '
      import Foundation

      func timestamp() -> String {
        let formatter = DateFormatter()
        formatter.timeStyle = .full
        return formatter.string(from: Date())
      }

      Task {
        // Test 1: Normal sleep
        print("=== Task.sleep(for: .seconds(5)) ===")
        print("Before: \(timestamp())")
        do {
          try await Task.sleep(for: .seconds(5))
          print("After:  \(timestamp())")
        } catch {
          print("Error: \(error)")
        }

        // Test 2: Max sleep
        print("\n=== Task.sleep(nanoseconds: .max) ===")
        print("Before: \(timestamp())")
        do {
          try await Task.sleep(nanoseconds: .max)
          print("After:  \(timestamp())")
        } catch {
          print("Error: \(error)")
        }
      }

      RunLoop.main.run()
      ' 2>&1

    === Task.sleep(for: .seconds(5)) ===
    Before: 9:55:53 PM Korean Standard Time
    After:  9:55:59 PM Korean Standard Time

    === Task.sleep(nanoseconds: .max) ===
    Before: 9:55:59 PM Korean Standard Time
    After:  9:55:59 PM Korean Standard Time
```

The solution: Replace the problematic sleep pattern with a proper cancellation loop that
polls every 60 seconds, ensuring the cancellation handler is actually invoked when the
task is cancelled.

commented out 'defer { token.cancel() }' is now revived.
2026-01-13 22:27:59 +09:00
r
6ae4136005 delete token.cancel in handleInputEvent callback from TransacriptionFeature.swift 2026-01-13 16:54:56 +09:00
Kit Langton
2348e8ced8 Release 0.6.8 2026-01-12 16:11:00 -05:00
Kit Langton
e2000d8e49 Add changeset for icon fix 2026-01-12 16:06:39 -05:00
Kit Langton
b162998893 Fix Icon Composer app icon not displaying
The icon from PR #148 wasn't showing because:
1. ASSETCATALOG_COMPILER_ICON_NAME should be ASSETCATALOG_COMPILER_APPICON_NAME
   (the APPICON variant tells Xcode to pass --app-icon to actool)
2. The .icon file was in Copy Bundle Resources but should only be compiled by actool
3. Info.plist needed CFBundleIconFile and CFBundleIconName entries

Fixes the Icon Composer integration so the app icon renders correctly on macOS Tahoe.
2026-01-12 16:06:24 -05:00
Kit Langton
66058dec0b
Merge pull request #148 from ropl-btc/tahoe-app-icon
Use Icon Composer app icon for macOS Tahoe (#145)
2026-01-12 12:59:34 -05:00
ropl.btc
494f07d26d Wire Icon Composer app icon
Add the AppIcon.icon bundle to the Hex target resources and update the asset catalog compiler setting to use the Icon Composer file name.
2026-01-12 17:48:45 +01:00
ropl.btc
318e47ba8f Merge remote-tracking branch 'origin/main' into tahoe-app-icon 2026-01-12 17:30:49 +01:00
ropl.btc
a4b611b186 Drop missing HexCore resources
Remove the unused Resources entry from HexCore’s package target so builds no longer fail when the directory is absent.
2026-01-12 16:48:50 +01:00
Kit Langton
f93c9a5c3c
Merge pull request #135 from ropl-btc/patch-1
Update README with macOS version notes
2026-01-12 08:44:41 -05:00
ropl.btc
75bc323616 Use Icon Composer app icon (#145)
Replace the AppIcon asset catalog with the Icon Composer .icon bundle so macOS uses the Tahoe-optimized layers and styling.

Refs #145.
2026-01-12 10:56:30 +01:00
Robin | Liquidium
681ab57d0c
Merge branch 'main' into patch-1 2026-01-12 10:18:59 +01:00
Kit Langton
511bacdfe0
Merge pull request #141 from ropl-btc/patch-2
Update README with Homebrew installation instructions
2026-01-10 19:12:25 -05:00
Kit Langton
27fa2c7a01 Release 0.6.7 2026-01-10 18:52:40 -05:00
Kit Langton
cc9965096f Add release changeset
Add changeset so release tooling can proceed for 0.6.6.
2026-01-10 18:48:33 -05:00
Robin | Liquidium
be23314541
Specified language for code snippet
Fixed formatting for the installation command in README.
2026-01-11 00:30:20 +01:00
Robin | Liquidium
25ecbd1038
Update README with Homebrew installation instructions
Added installation instructions for Homebrew since it's now available as a cask on homebrew.

The PR to add Hex to homebrew got merged: https://github.com/Homebrew/homebrew-cask/pull/243464#event-21890253748
2026-01-11 00:26:00 +01:00
Kit Langton
85a67d98bf Release 0.6.6
Apply changeset versioning, update changelogs, and bump build metadata for the 0.6.6 release.
2026-01-10 13:29:42 -05:00
Kit Langton
3b6c966719 Improve transcript transforms and remove log export
Reworks the remappings screen into a scrollable, tabbed layout with clearer rows, applies word removals in transcription, and removes the broken log export settings. Includes new defaults, tests, and changeset.
2026-01-10 12:46:22 -05:00
Robin | Liquidium
927d9b894c
typo
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-01-07 02:51:08 +01:00
Robin | Liquidium
cb0dcf6ad4
Update README with macOS version notes
Added notes about version stability for macOS.
2026-01-07 02:47:24 +01:00
Kit Langton
a90465c170 Release 0.6.5 2026-01-02 20:13:07 -05:00
Kit Langton
140c205295 Fix Sparkle auto-update for sandboxed apps
- Add mach-lookup entitlements for Sparkle XPC services
- Add SUEnableInstallerLauncherService to Info.plist
- Add disable-library-validation entitlement

The 0.6.3 release broke Sparkle updates by enabling sandboxing without
the required XPC entitlements. Users on 0.6.3 will need to manually
download this update, but future updates will work automatically.
2026-01-02 20:05:09 -05:00
Kit Langton
4ad74f44cd Release 0.6.4 2026-01-02 19:30:10 -05:00
Kit Langton
658a7554c5 Add changeset for microphone mute fix 2026-01-02 19:18:07 -05:00
Kit Langton
50708359b3 Fix silent recordings caused by device-level microphone mute
Discovered that macOS can have microphones muted at the Core Audio device
level (kAudioDevicePropertyMute) without any UI indication. This caused
recordings to be completely silent, and only a system restart would fix it.

Added detection and auto-fix:
- isInputDeviceMuted() checks device-level mute state
- unmuteInputDevice() fixes it via Core Audio API
- ensureInputDeviceUnmuted() called before each recording

Also fixed Swift 6 Sendable warnings in KeyEventMonitorClient by marking
handler closures as @Sendable.
2026-01-02 19:17:56 -05:00
Kit Langton
c00f79ee3d Reduce code duplication across the codebase
- Add ModelPatternMatcher utility in HexCore for fnmatch pattern matching
- Add FileManager extensions (migrateIfNeeded, removeItemIfExists)
- Add settingsCaption() Text extension for consistent UI styling
- Add NSNotification.Name.updateAppMode constant in shared Notifications.swift
- Add audioPropertyAddress helper in RecordingClient (reduces 8 boilerplate sites)
- Consolidate processEvent in KeyEventMonitorClient
- Extract modelDirectories helper in ParakeetClient
- Extract stopAudioPlayback helper in HistoryFeature
- Remove unused commented code from PasteboardClient
- Remove unused Darwin imports from TranscriptionClient and ModelDownloadFeature

Net reduction of ~157 lines while improving maintainability.
2025-12-31 09:12:02 -05:00
Kit Langton
be30efb2f0 Document release process in CLAUDE.md 2025-12-30 21:19:24 -05:00
Kit Langton
c3bb17a445 Release 0.6.3 2025-12-30 21:15:25 -05:00
Kit Langton
34d80f1443 Update lockfile 2025-12-30 21:07:14 -05:00
Kit Langton
5217d3f5db Remove LLM text transformations, add word remappings
- Delete LLMExecutionClient, ToolServer, and all provider code
- Remove TextTransformationFeature and related UI
- Add simple WordRemapping model and settings UI
- Clean up 3800+ lines of unused experimental code
2025-12-30 20:56:55 -05:00
Kit Langton
bbd0b80ad5 Show default mic name and clean up paste flow
- Display actual device name in "System Default (MacBook Pro Microphone)" picker
- Fix Parakeet polling cleanup with defer
- Refactor paste strategies using CaseIterable enum
- Encapsulate pasteboard state in PasteboardSnapshot struct
2025-12-30 19:57:45 -05:00
Kit Langton
2e42f2f168 fix entitlements 2025-12-30 11:48:13 -05:00
Kit Langton
b4c54ce7a3 Fix recording session media races 2025-12-30 11:46:32 -05:00
Kit Langton
4d38708ceb Fix microphone freezing and speech cutoff with custom mic
Root cause: setInputDevice() was called on every recording start,
even when the device was already set correctly. This caused:
1. coreaudiod instability over time (mic freezing system-wide)
2. Primed recorder becoming stale (speech cutoff at start)

Changes:
- Add getDefaultInputDevice() to query current input device
- Track lastPrimedDeviceID to know what device recorder was primed for
- Only call setInputDevice() when target differs from current default
- Invalidate primed state when device changes, forcing re-prime
- Add cleanup() method and call it on app termination

Now custom mic users get fast recording on 2nd+ recordings (device
already set), and system stays stable over extended use.
2025-12-14 20:51:41 -05:00
Kit Langton
3413d68bbc Rename transformations to modes. 2025-11-22 09:50:28 -05:00
Kit Langton
ab002092ab fix space hotkey 2025-11-21 11:11:32 -05:00
Kit Langton
37ec2573ab Release 0.6.2 2025-11-21 09:32:22 -05:00
Kit Langton
7e325adbbc Fix Sequoia hotkeys, add model UX improvements, remove preferred provider
Sequoia hotkey fix:
- Remove Input Monitoring guard blocking CGEventTap creation
- Tap creation triggers permission prompt naturally on macOS 15
- Re-add "force quit Hex now" voice escape hatch (#122 #124)

Model missing UX:
- App activates and switches to settings when no model available
- Blue "Download a model" banner flashes to draw attention
- Added logging for debugging model missing flow

Settings improvements:
- Hide Permissions section when all permissions granted
- Add "BEST FOR ENGLISH/MULTILINGUAL" badges to Parakeet models
- Update Parakeet TDT v2 display name (remove parenthetical)
- Fix unused provider variable warning

LLM provider simplification:
- Remove "Preferred Provider" picker from Settings UI
- Remove preferred provider fallback logic in backend
- Transformations now strictly use configured providerID
- Throw error if provider not found instead of silent fallback
- Simplify LLMExecutionClient by removing ProviderResolution

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-21 09:24:22 -05:00
Kit Langton
fb92051700 Release 0.6.1 2025-11-19 13:25:10 -05:00
Kit Langton
804651c1ed Ensure LLM processing is interruptible by Escape key 2025-11-19 11:32:17 -05:00
Kit Langton
04593f67e4 Release 0.6.0 2025-11-18 21:57:17 -05:00
Kit Langton
9474ff72f0 Improve LLM provider auto-detection 2025-11-18 21:40:41 -05:00
Kit Langton
eab07f21b3 Gate LLM UI behind developer flag 2025-11-18 20:40:57 -05:00
Kit Langton
d583372a13 Add auto-send keyboard command to transformation modes (#119) 2025-11-18 20:05:26 -05:00
Kit Langton
3bf2fb0779 Fix voice prefix matching with punctuation
The voice prefix matcher now properly handles common punctuation marks
(.,;:!?) that may appear after spoken prefixes. Previously, only commas
and whitespace were recognized, causing transcriptions like "Shakespeare,
I have to take out the trash" to fail matching when "Shakespeare" was
configured as a voice prefix.

Updated the regex pattern in modeByVoicePrefix to accept any combination
of common punctuation and whitespace after the prefix word. Added
comprehensive test coverage for various punctuation scenarios.

The fix ensures natural speech patterns with pauses (transcribed as
punctuation) don't break voice prefix detection, improving the user
experience for mode activation.
2025-11-18 19:13:03 -05:00
Kit Langton
154238e619 MCP tooling now configurable per transformation
Adds optional `tooling` field to `LLMTransformationConfig` so each LLM transformation can specify its own MCP tool groups. LLMExecutionClient prefers transformation-level tooling, falls back to provider-level. Migrated Hex Command mode to use transformation-level tooling (app-control, app-discovery, context), removed global provider tooling.
2025-11-18 18:45:41 -05:00
Kit Langton
56d4dd79b0 refactor 2025-11-18 17:25:00 -05:00
Kit Langton
e7971945c5 add transformations 2025-11-18 17:02:07 -05:00
Kit Langton
5c0d689a0d rebased 2025-11-18 15:07:25 -05:00
Kit Langton
9cb34aba12 modes 2025-11-18 13:49:41 -05:00
Kit Langton
5017fd45d6 Release 0.5.13 2025-11-18 13:31:46 -05:00
Kit Langton
083513cdff Document HotKeyProcessor & extract timing constants to HexCoreConstants 2025-11-18 13:15:11 -05:00
Kit Langton
4a68188443 Release 0.5.12 2025-11-18 12:48:11 -05:00
Kit Langton
adebaf64ab update status panel level 2025-11-18 12:43:46 -05:00
Kit Langton
6ca3a3de05 Warm up recorder after each recording completes for instant subsequent startup 2025-11-18 12:43:32 -05:00
Kit Langton
f77e7cd114 Release 0.5.12 2025-11-18 12:32:10 -05:00
Kit Langton
471310c9dd Fix Input Monitoring permission enforcement for hotkey reliability
- Stop monitoring when Input Monitoring missing instead of continuing with Accessibility-only
- Track permission state via shared HotkeyPermissionState model
- Add UI banner in Settings when Input Monitoring denied with button to open System Settings
- Check both accessibility AND input monitoring before starting event tap
2025-11-18 12:26:18 -05:00
Kit Langton
8f3a77dd29 Release 0.5.11 2025-11-18 11:27:37 -05:00
Kit Langton
1deda2acdb use swift logging 2025-11-18 11:21:48 -05:00
Kit Langton
756d7fd4f7 Release 0.5.10 2025-11-18 10:39:03 -05:00
Kit Langton
3560bdb1aa add log export 2025-11-18 10:35:02 -05:00
Kit Langton
9246e529f2 Release 0.5.9 2025-11-18 10:26:58 -05:00
Kit Langton
6c2f1bdb38 changeset 2025-11-18 10:22:56 -05:00
Kit Langton
dbf38eef86 add comprehensive permissions logging 2025-11-18 10:22:47 -05:00
Kit Langton
82139c4340 Release 0.5.8 2025-11-18 10:10:51 -05:00
Kit Langton
03b81c7b2e attempt to fix hotkey cruelty 2025-11-18 10:06:57 -05:00
Kit Langton
5668bf9dd3 Reorganize README: move Instructions before Contributing, remove auto-download note 2025-11-17 19:16:51 -05:00
Kit Langton
2cb4d44e2e Release 0.5.7 2025-11-17 19:15:14 -05:00
Kit Langton
686e3927a3 update claude 2025-11-17 19:07:30 -05:00
Kit Langton
14eca40d26 bump version 2025-11-17 19:07:18 -05:00
Kit Langton
539b0a45ff Pad short Parakeet clips 2025-11-17 19:06:36 -05:00
Kit Langton
74e2c530cc Release 0.5.6 2025-11-17 18:45:55 -05:00
Kit Langton
a1eb1d0a39 attemtp to fix regression 2025-11-17 17:12:34 -05:00
Kit Langton
786a23b740 Document AI changeset tool in README 2025-11-17 16:01:21 -05:00
Kit Langton
1ee452aad7 Add non-interactive changeset tool for AI agents 2025-11-17 16:00:38 -05:00
Kit Langton
68475f5ff8 Fix clipboard restore timing for slow apps 2025-11-17 15:59:04 -05:00
Kit Langton
96f4ad53ca Release 0.5.5 2025-11-17 14:52:11 -05:00
Kit Langton
4c7e17b5a4 update tool 2025-11-17 14:20:37 -05:00
Kit Langton
1b537d5c2e update lock files 2025-11-17 14:17:18 -05:00
Kit Langton
f27a9b9ed4 upupdaet bun 2025-11-17 14:14:27 -05:00
Kit Langton
eda4210a03 updaet CLAUDE 2025-11-17 14:14:24 -05:00
Kit Langton
0ffc87b837 Release 0.5.4 2025-11-17 14:09:36 -05:00
Kit Langton
7f6c5dbd6b Request Input Monitoring permission and expose status 2025-11-17 14:03:11 -05:00
Kit Langton
0045f2824b Fix recording chime latency
- Replace AVAudioPlayer cache with single AVAudioEngine using pre-loaded buffers
- Eliminates delayed playback after idle periods
- Re-encode startRecording.mp3 for new playback graph
- Maintain user volume scaling
2025-11-17 11:17:44 -05:00
Kit Langton
07008f841a release 0.5.4 2025-11-17 09:52:22 -05:00
Kit Langton
b99f5c700a Update version to 0.5.3 2025-11-17 09:22:06 -05:00
Kit Langton
9cd275796b Fix hotkey monitoring on macOS Sequoia (fixes #122, #124)
Use AXIsProcessTrustedWithOptions throughout event-tap lifecycle to properly
handle macOS 15's split Accessibility/Input Monitoring permissions. Add
NSInputMonitoringUsageDescription so system shows dedicated Input Monitoring
dialog. Trust watchdog now polls same API Settings UI uses, ensuring runtime
checks stay aligned with Sequoia 15.7.1.
2025-11-17 09:21:50 -05:00
Kit Langton
9edd595c12 update version 2025-11-16 21:54:26 -05:00
Kit Langton
1b9bd52c44 Optimize recorder startup by keeping AVAudioRecorder primed between sessions 2025-11-16 21:29:36 -05:00
Kit Langton
55fb4f8bd1 Add sound effects volume slider
Add soundEffectsVolume setting with slider UI in SoundSectionView:
- Add baseSoundEffectsVolume constant (0.2) as 100% reference
- Slider shows 0-100% relative to baseline volume
- Update SoundEffect client to use configurable volume
- Add migration test coverage for new setting
- Include changeset documenting the feature (#000)
2025-11-16 21:00:35 -05:00
Kit Langton
2261cf9428 Change default recording audio behavior to doNothing
Users reported that auto-pausing media is disruptive. Default to
doNothing for a less intrusive experience.
2025-11-16 20:53:56 -05:00
Kit Langton
94530556ec Remove unused 'Recommended' localization string 2025-11-16 20:50:21 -05:00
Kit Langton
09a15b8005 Simplify model picker and prioritize English Parakeet
- Remove variant-specific recommendation badges (simpler UI)
- Reorder models.json to show English v2 before multilingual v3
- Keep preferredParakeetIdentifier logic for language-based defaults
2025-11-16 20:50:12 -05:00
Kit Langton
049592c8c1 Add changesets for recent improvements
Document user-facing changes:
- Menu bar rendering fix
- KeyEventMonitor reliability improvements
- MediaRemote API integration
- Parakeet model variants (minor bump)
- Hotkey UI polish
2025-11-16 20:48:08 -05:00
Kit Langton
82f8f20630 Add technical plan for Parakeet short-audio padding
Document implementation strategy for handling clips shorter than
Parakeet's minimum chunk duration, including research tasks,
touchpoints, and validation approach.
2025-11-16 20:46:54 -05:00
Kit Langton
aca9ad5f33 Add changeset for microphone release fix 2025-11-16 20:46:52 -05:00
Kit Langton
f5aa3f84bf Add variant-specific recommendation badges to model picker
CuratedRow:
- Display custom recommendation text for Parakeet variants
- Show primary badge (filled) for preferred variant based on language
- Show secondary badge (outlined) for non-preferred variant
- Fall back to generic "Recommended" for other models

Localizable.xcstrings:
- Add new localization strings for updated UI
- Remove unused strings ("English only", "Multilingual")
2025-11-16 20:46:46 -05:00
Kit Langton
8fb5fb95a2 Improve Parakeet recommendation logic and settings UX
ModelDownloadFeature:
- Add recommendation badge system for Parakeet variants
- Prefer English v2 when output language is English
- Default to multilingual v3 for other languages
- Ensure all Parakeet variants appear in available models list
- Add preferredParakeetIdentifier computed property

SettingsFeature:
- Clear currentPasteLastModifiers when starting hotkey capture

SettingsView:
- Minor whitespace cleanup
2025-11-16 20:46:28 -05:00
Kit Langton
6fc9d9785a Add support for multiple Parakeet model variants
Introduce ParakeetModel enum to manage v2 (English) and v3 (Multilingual):
- Add ParakeetModel.swift with variant metadata and capabilities
- Update ParakeetClient to accept model name and load correct variant
- Map ParakeetModel to AsrVersion (v2/v3) for FluidAudio
- Refactor isModelAvailable/ensureLoaded/deleteCaches to be variant-aware
- Extract candidateRoots helper for cache detection
- Update TranscriptionClient to iterate all Parakeet variants
- Add Parakeet TDT v2 (English) to curated models list
- Use ParakeetModel.multilingualV3 constant in HexSettings default

Enables users to choose between English-only (v2) and multilingual (v3)
Parakeet models based on their transcription needs.
2025-11-16 20:46:07 -05:00
Kit Langton
8f1f4d92e7 Polish paste-last-transcript hotkey UI and simplify modifier display
HistorySectionView:
- Redesign layout to vertical stack for better readability
- Use HotKeyView component instead of custom text rendering
- Add instructional text when setting hotkey
- Improve clear button with label and borderless style
- Show "Not set" placeholder when no hotkey configured

HotKey.swift:
- Remove L/R suffix from modifier stringValue (cleaner display)
- Simplify modifier display logic
2025-11-16 20:45:38 -05:00
Kit Langton
0b37ee531b Improve app lifecycle and event handler cleanup
AppFeature changes:
- Remove .task modifier from AppView (now in HexAppDelegate)
- Add proper token-based cleanup for paste-last-transcript hotkey
- Use matchesExactly for hotkey modifier comparison
- Remove unused hasRequiredPermissions computed property
- Add modelStatusEvaluated action placeholder
- Code formatting fixes

TranscriptionFeature changes:
- Add token-based cleanup for input event handler
- Stop recording properly on cancel (release microphone)

ModelBootstrapState:
- Remove unused isAutoDownloading field
- Simplify state structure
2025-11-16 20:45:08 -05:00
Kit Langton
9d9aeb20e7 Add MediaRemote commands for reliable media control
Enhance RecordingClient with direct MediaRemote framework integration:
- Add MRMediaRemoteSendCommand function binding
- Implement play/pause/toggle commands via MediaRemote API
- Prefer MediaRemote over simulated key presses when available
- Track pause method separately (MediaRemote vs key press)
- Fall back to media key if MediaRemote fails during resume

Improves media pausing reliability, especially with system media players
and reduces dependency on simulated keyboard events.
2025-11-16 20:43:10 -05:00
Kit Langton
df540e871d Improve KeyEventMonitor reliability with trust watchdog and tap recovery
Major refactor to handle accessibility permission changes and tap failures:
- Add accessibility trust monitoring task polling every 100ms
- Detect and recover from tap disabled events (timeout/user input)
- Implement token-based handler lifecycle for proper cleanup
- Track monitoring intent separately from actual tap state
- Gracefully suspend/resume tap when permissions change
- Remove modifier diagnostics logging (no longer needed)

Fixes long-standing issues with hotkeys stopping after permission revocation
or system tap disablement (#89, #81, #87).
2025-11-16 20:42:36 -05:00
Kit Langton
54f435b1d7 Refactor ModelDownload into focused components
Split monolithic ModelDownloadFeature.swift into directory structure:
- ModelDownloadFeature.swift: core reducer logic (428 lines)
- CuratedList.swift: curated model list view
- CuratedRow.swift: individual model row UI
- ModelDownloadView.swift: main view wrapper
- StarRatingView.swift: rating display component

Reduces total code by ~150 lines through better separation of concerns.
2025-11-16 20:41:13 -05:00
Kit Langton
0b2186781f Fix menu bar rendering and history order
- Revert to declarative MenuBarExtra (removed broken programmatic approach)
- Fix paste-last-transcript to use .first (history is reversed)
- Start app lifecycle task to enable hotkeys and permission monitoring
- Remove Help menu
2025-11-16 20:39:31 -05:00
Kit Langton
3ac91f3e78 Bump version to 0.4.0 2025-11-16 20:33:28 -05:00
Kit Langton
9f55f9026b update 2025-11-15 22:43:48 -05:00
Kit Langton
f1bc807d92 Hide language picker for Parakeet (multilingual by default) 2025-11-15 22:42:56 -05:00
Kit Langton
ea42b5bacd Migrate HexSettings to HexCore with backward compat
- Move HexSettings from Hex to HexCore
- Make HotKey Sendable
- Add custom Codable for backward compatibility
- Add fixtures & tests for v1 migration
- Update Package.swift to copy test fixtures

https://github.com/claude.com/claude-code
2025-11-15 22:37:01 -05:00
Kit Langton
2fbbe7a3fc update changeset 2025-11-15 22:19:37 -05:00
Kit Langton
582c7f06e2 Complete logging migration and document pasteboard reliability fix 2025-11-15 22:19:03 -05:00
Kit Langton
769cb13f61 Modernize logging infrastructure with structured os.Logger and privacy annotations 2025-11-15 22:16:58 -05:00
Kit Langton
1b400ca635 Harden pasteboard writes 2025-11-15 21:57:09 -05:00
Kit Langton
ae773e4e0e Remove unnecessary async from sound effects API
Sound play/stop methods are now synchronous at call sites but preserve actor isolation internally via Task spawning. Cleaner API, same behavior.
2025-11-15 21:47:18 -05:00
Kit Langton
a8ce5c19a6 refactor: redesign permissions UI to compact cards
Replace vertical list with side-by-side cards showing mic + accessibility status—cuts height by ~40% and surfaces Grant buttons more prominently
2025-11-15 21:41:36 -05:00
Kit Langton
1783ee86bb perf: cache installed media players on launch
Compute media player list once at startup instead of scanning on every recording session—cuts ~50-100ms from pause/resume cycle
2025-11-15 21:41:34 -05:00
Kit Langton
8677ef5d30 dev: integrate InjectionNext for hot reload
Add @ObserveInjection + .enableInjection() to all Settings views and ModelDownloadFeature so SwiftUI changes apply instantly during debug builds
2025-11-15 21:41:33 -05:00
Kit Langton
e50478dcba feat: add changeset workflow for release automation
- Adopt @changesets/cli for SemVer + changelog management
- Add sync script to mirror CHANGELOG.md into bundled resources
- Update docs with contributor workflow + CI integration notes
- Preload 2 changesets for v0.4.0 (Parakeet + workflow tooling)
2025-11-15 21:41:31 -05:00
Kit Langton
6fb209f762 chore: add node tooling to .gitignore 2025-11-15 21:41:14 -05:00
Kit Langton
3239f31bb2 Track active window for UI placement 2025-11-15 21:05:08 -05:00
Kit Langton
6d854ae724 Improve recording responsiveness and sound feedback
- Play start sound immediately before recording setup
- Make media pause/resume non-blocking (run in background)
- Remove cancel sound from transcription errors (UI error msg sufficient)

Recording now starts ~200-700ms faster, sound feedback is instant.
2025-11-15 20:56:47 -05:00
Kit Langton
4949e058b9 Add per-modifier side selection for hotkeys
- Modifier model tracks kind + side (either/left/right) instead of simple enum
- HotKeyProcessor matches events by side preference
- KeyEventMonitorClient captures left/right state via NX_DEVICE masks, tracks Fn separately to eliminate phantom fn on arrow keys
- Settings UI: segmented controls for modifier side, arrow glyphs (←→↑↓)
- Menu bar respects new modifier model
- Diagnostic logging gated behind HEX_DIAG_MODIFIERS=1
2025-11-15 20:54:23 -05:00
Kit Langton
f5d19d39d2 Remove double-tap recommendation text 2025-11-15 20:20:04 -05:00
Kit Langton
b1196956ea Use PasteboardClient in HistoryFeature
Replace direct NSPasteboard calls with existing PasteboardClient.
Consistent with established client pattern and improves testability.
2025-11-15 17:45:12 -05:00
Kit Langton
dfc7262a30 Add SleepManagementClient
Extract IOKit sleep prevention into SleepManagementClient in HexCore:
- Create SleepManagementClient with named arguments for clarity
- Actor-based live implementation manages assertion lifecycle internally
- Update TranscriptionFeature to use client instead of direct IOKit calls
- Remove IOKit imports and assertion state from TranscriptionFeature
- Remove 26 lines of private sleep prevention functions

Benefits: testable, no state leaks, cleaner feature code, encapsulated IOKit complexity
2025-11-15 17:45:02 -05:00
Kit Langton
9b90c2cf56 Add PermissionClient architecture
Extract permission handling into clean PermissionClient in HexCore:
- Create PermissionClient with async API for mic/accessibility permissions
- Implement live actor-based implementation with app activation monitoring
- Integrate into AppFeature with reactive permission updates
- Refactor SettingsFeature to use PermissionClient directly (no delegation)
- Update views to receive permission state as props

Benefits: testable, decoupled from platform APIs, eliminates feature coupling
2025-11-15 17:44:47 -05:00
Kit Langton
e042c3d9bf Update README: highlight Parakeet as default transcription engine, remove CI workflow 2025-11-14 20:07:21 -05:00
113 changed files with 10626 additions and 2570 deletions

6
.gitignore vendored

1
AGENTS.md Symbolic link

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 539 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 260 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 259 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

Some files were not shown because too many files have changed in this diff Show more