Commit Graph
163 Commits
Author SHA1 Message Date
Mohamed Boudra b44bb63cf4 chore(release): cut 0.4.0 2026-08-13 21:31:47 +02:00
Mohamed Boudra 44b9980a70 chore(release): cut 0.4.0-beta.2 2026-08-12 23:18:28 +02:00
Mohamed Boudra 0c6dbefa40 chore(release): cut 0.4.0-beta.1 2026-08-12 20:39:35 +02:00
b7ca1f7502 docs: fix typos across contributing, product, and skill docs (#3153)
Fix spelling and grammar errors found in a full sweep of the
repo's English markdown files.

- CONTRIBUTING.md: "contributing to to it", "accpeted", "wil"
- .github/PULL_REQUEST_TEMPLATE.md: "value provider to" instead
  of "value provided to"
- docs/product.md: "vendor-lock in" instead of "vendor lock-in"
- packages/expo-two-way-audio/CONTRIBUTING.md: "prescreptive"
- packages/expo-two-way-audio/README.md: "can bee added"
- skills/paseo-committee/SKILL.md: "considered and reject"

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 13:53:38 +00:00
Mohamed Boudra bfec7ac3ad chore(release): cut 0.3.1 2026-08-09 13:30:33 +02:00
Mohamed Boudra 7392e1b767 chore(release): cut 0.3.0 2026-08-08 10:56:30 +02:00
Mohamed Boudra a7c7a6e482 chore(release): cut 0.3.0-beta.4 2026-08-07 23:59:18 +02:00
Mohamed Boudra 86ff0a18c4 chore(release): cut 0.3.0-beta.3 2026-08-07 18:09:43 +02:00
Kevin AspesiandGitHub fb5cfb9fb9 Release the audio session when voice capture and playback go idle (#2866)
* Release the audio session when voice capture and playback go idle

Opening Paseo permanently paused music playing in other apps. Once the
mic had been used a single time, every subsequent foreground of the app
killed the user's audio again until the app was force-quit.

iOS AudioEngine.setupAudioSession() takes .playAndRecord/.voiceChat — a
non-mixing category — and calls setActive(true), but the only
setActive(false) was reachable from tearDown(). Nothing handed the
session back after a normal dictation turn, so iOS re-asserted the last
category the app set on every foreground. The iOS module had no
app-lifecycle handling at all, while Android already had a lifecycle
listener; that asymmetry is what made the platforms diverge. Android had
the same leak in a different shape: AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE
was requested per recording and never abandoned.

Add releaseAudioSession() to both platforms and call it once capture
stops and the playback queue drains. iOS pauses the engine, calls
setActive(false, .notifyOthersOnDeactivation) — this is what tells the
other app to resume — then drops to .ambient/.mixWithOthers so any
implicit reactivation mixes instead of interrupting. The session is
re-acquired lazily on toggleRecording(true)/playPCMData, so voice keeps
working; resumeRecordingAndPlayer() re-activates before restarting the
engine, which keeps post-interruption resume intact. Releasing is
guarded on isRecording/isPlaying, and checkEngineIsRunning() now refuses
to start the engine while the session is released, since starting it
would silently re-take the session.

The JS wrapper probes the native module before calling, because a JS
bundle shipped over EAS Update can land on a binary predating this
function.

* Correct the iOS signing diagnosis in mobile-testing docs

The "No Accounts" error does not mean no Apple ID is configured. The
account can be registered in Xcode while its Xcode-Token keychain item is
missing, which Xcode reports as No Accounts and then compounds by falling
back to a stale cached profile — surfacing as a certificate mismatch that
sends you chasing the wrong thing.

Document the DVTDeveloperAccountManager log line that names the real
cause, the two commands that check what is actually configured, and the
build-unsigned-then-sign-manually stopgap.

* Reacquire Android audio focus when playback restarts

releaseAudioSession() abandons the AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE
request and pauses the AudioTrack once capture and playback go idle, but
nothing took either back. The next playback turn therefore ran with no
focus held, so the assistant's response competed with whatever the user
was listening to instead of interrupting it.

Add acquireAudioSessionIfNeeded(), the mirror of the iOS
activateAudioSessionIfNeeded() already called from playPCMData, and use
it from both playPCMData() and resumePlayback(). A null audioFocusRequest
is what "we released" looks like, so it doubles as the guard against
re-requesting focus mid-turn.

Reported by Greptile on #2866.

* Make Android playback focus reacquisition non-fatal

The previous commit dropped PCM data when focus reacquisition did not
return AUDIOFOCUS_REQUEST_GRANTED. That is worse than playing unfocused:
playPCMData is fire-and-forget from JS, and playAudio() settles on a
duration timer rather than a native ack, so the runtime acknowledged and
discarded a chunk that was never queued.

It also broke delayed focus. The request is built with
setAcceptsDelayedFocusGain(true), so AUDIOFOCUS_REQUEST_DELAYED is a
normal outcome, but routing it through handleAudioFocusBlocked() abandoned
the pending request and the later grant could never arrive.

Request focus, then play regardless of the result, and leave the request
outstanding so a delayed grant still lands via the listener.

Reported by Greptile on #2866.

* Track scheduled buffers so iOS actually releases after playback

releaseAudioSession() guarded on !speechPlayer.isPlaying, but
AVAudioPlayerNode.isPlaying stays true from play() until an explicit
stop()/pause() — draining every scheduled buffer does not clear it. The
normal completion path is processQueue() -> releaseSessionIfIdle(), and
stopPlayback() is only reached from the explicit stop() API, so after the
first spoken response the guard blocked every release and the session
stayed active. The music-pausing bug returned in full for anyone using
voice responses.

Count buffers that are scheduled but not yet rendered, decrementing from
the .dataPlayedBack completion handler, and guard on that instead. The
handler runs on an AVAudioEngine-internal thread, so the count is behind a
lock. Both stop() paths reset it, since stop() discards what is scheduled
and a stale count would block every later release.

Found by Codex review on #2866.

* Stop re-taking Android audio focus on every foreground

ExpoTwoWayAudioLifeCycleListener calls resumeRecordingAndPlayer() from
onResume, and that requested AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE before
looking at isRecordingBeforePause. Foregrounding the app while nothing was
recording therefore took exclusive focus back and re-paused the user's
music — the same "every foreground kills my music" symptom this change set
exists to remove, just reached through the Android lifecycle instead of the
iOS category.

Return early unless capture or playback was actually live when we
backgrounded.

Found by Codex review on #2866.
2026-08-05 22:53:23 +02:00
Mohamed Boudra d227ff3e83 chore(release): cut 0.3.0-beta.2 2026-08-05 15:30:50 +02:00
Mohamed Boudra 9916e3d185 chore(release): cut 0.3.0-beta.1 2026-08-04 21:27:12 +02:00
Mohamed Boudra 6fc491e622 chore(release): cut 0.2.5 2026-07-30 13:22:40 +02:00
Mohamed Boudra 2f913736fa chore(release): cut 0.2.4 2026-07-30 01:48:57 +02:00
Mohamed Boudra 43cf858c37 chore(release): cut 0.2.3 2026-07-27 19:46:38 +02:00
Mohamed BoudraandGitHub c9fb31f709 Fix Claude 5 context window selection (#2433)
* fix(claude): select the correct Opus 5 context window

Bare Opus 5 IDs resolve to 200K behind third-party gateways. Expose explicit context variants and require a Claude Code version that recognizes the model.

* fix(claude): add Fable and Sonnet context variants

* test(cli): expect Claude context variants

* test(cli): compose Claude catalog expectations

* fix(claude): preserve catalog on version probe failure

* fix(claude): preserve parsed context variants

* chore(release): cut 0.2.2
2026-07-26 10:03:44 +02:00
Mohamed Boudra 36f38245ca chore(release): cut 0.2.1 2026-07-24 19:40:41 +02:00
Mohamed Boudra d98c5e77f7 chore(release): cut 0.2.0 2026-07-24 13:27:13 +02:00
Mohamed Boudra b02acb882c chore(release): cut 0.2.0-beta.4 2026-07-24 00:16:25 +02:00
Mohamed Boudra 8a1243e8d3 chore(release): cut 0.2.0-beta.3 2026-07-22 23:26:47 +02:00
Mohamed Boudra 89a022e853 chore(release): cut 0.2.0-beta.2 2026-07-22 10:56:55 +02:00
Mohamed Boudra 0bec06c2db chore(release): cut 0.2.0-beta.1 2026-07-17 15:10:06 +02:00
Mohamed BoudraandGitHub 6db7e53b6e Record the 0.1.110 ACP hotfix release (#2150)
Sync the 0.1.110 release metadata and changelog back to main.
2026-07-16 23:01:31 +02:00
Mohamed Boudra 42e101c81e chore(release): cut 0.1.109 2026-07-16 09:46:41 +02:00
Mohamed Boudra 75ea0d4534 chore(release): cut 0.1.108 2026-07-16 00:15:57 +02:00
Mohamed Boudra 9553f4b328 chore(release): cut 0.1.107 2026-07-13 00:27:43 +02:00
Mohamed Boudra a1821d5863 chore(release): cut 0.1.106 2026-07-12 10:42:56 +02:00
Mohamed Boudra e98ba1beb1 chore(release): cut 0.1.106-beta.1 2026-07-11 20:45:30 +02:00
Mohamed Boudra 4c72bf0209 chore(release): cut 0.1.105 2026-07-10 12:58:31 +02:00
Mohamed BoudraandGitHub 251d88a37a Stop Android audio interruptions crashing voice mode (#1941)
* fix(android): handle denied voice audio focus

Android can deny voice-mode audio focus while another system audio owner, such as an incoming call, is active. Treat that as an interruption so resume does not crash the app and JS stops voice mode coherently.

* fix(voice): keep interruption state consistent

Make native interruption handling payload-aware so iOS resume events do not stop the shared JS runtime, avoid ending voice mode for duck-only Android focus changes, and roll host voice mode back if capture fails after startup enabled it.

* fix(voice): avoid duplicate interruption handling

Keep exactly one Android audio-focus request active at a time and leave JS capture state untouched for non-terminal interruption events.

* fix(android): abandon blocked audio focus requests

When Android denies or blocks voice audio focus, abandon the pending focus request so delayed focus gain cannot arrive after voice mode has already stopped.

* fix(voice): handle interrupted dictation capture

Stop Android resume from replaying after recording restart fails, and propagate native blocked interruptions into dictation so users do not remain in a stale recording state.
2026-07-08 19:45:02 +08:00
Mohamed Boudra f3fdeab131 chore(release): cut 0.1.104 2026-07-08 12:47:07 +02:00
Mohamed Boudra a85139c3f3 chore(release): cut 0.1.104-beta.5 2026-07-07 23:01:34 +02:00
Mohamed Boudra 391cf75ece chore(release): cut 0.1.104-beta.4 2026-07-06 09:58:20 +02:00
Mohamed Boudra b3eb77981a chore(release): cut 0.1.104-beta.3 2026-07-04 10:22:14 +02:00
Mohamed Boudra 75b11ac93e chore(release): cut 0.1.104-beta.2 2026-07-03 11:58:21 +02:00
Mohamed Boudra a13fa4e614 chore(release): cut 0.1.104-beta.1 2026-07-03 08:27:07 +02:00
Mohamed Boudra f41dde8c72 chore(release): sync Sonnet 5 stable release to main 2026-07-01 22:36:37 +02:00
Mohamed Boudra e32c50f2d7 chore(release): cut 0.1.102 2026-06-30 12:00:31 +02:00
Mohamed Boudra 8eb9640f28 chore(release): cut 0.1.102-beta.2 2026-06-30 00:02:06 +02:00
Mohamed Boudra c7e27fdd5b chore(release): cut 0.1.102-beta.1 2026-06-27 05:08:20 +00:00
Mohamed Boudra bbde200aa2 chore(release): cut 0.1.101 2026-06-26 00:19:37 +07:00
Mohamed Boudra 119afd7281 chore(release): cut 0.1.100 2026-06-24 17:42:47 +07:00
Mohamed Boudra 7a817774b7 chore(release): cut 0.1.99 2026-06-23 22:47:51 +07:00
Mohamed Boudra fbd86564dd chore(release): cut 0.1.98 2026-06-21 00:30:25 +07:00
Mohamed Boudra 60cf566b79 chore(release): cut 0.1.97 2026-06-19 05:47:43 +07:00
Mohamed BoudraandGitHub df18bbc43a Migrate monorepo to Zod 4 2026-06-18 15:02:42 +08:00
Mohamed Boudra e4da3693e9 chore(release): cut 0.1.97-beta.3 2026-06-18 11:40:27 +07:00
Mohamed Boudra 6fc52d85cb chore(release): cut 0.1.97-beta.2 2026-06-17 17:15:23 +07:00
Mohamed Boudra 8c509017ff chore(release): cut 0.1.97-beta.1 2026-06-17 08:24:25 +07:00
Mohamed Boudra 8ef75c0914 chore(release): cut 0.1.96 2026-06-13 08:46:33 +07:00
Mohamed Boudra 10a556d6a1 chore(release): cut 0.1.95 2026-06-13 00:18:28 +07:00