6 Commits
Author SHA1 Message Date
rzen a21dd62f17 Refresh app icon artwork across iOS, macOS, and watchOS
Claude-Session: https://claude.ai/code/session_014esDWi42URLEC6Cj17hGQ3
2026-07-16 13:29:50 -04:00
rzen c5c90e9441 Decouple transcripts from note text; end-to-end watch transfer acks
Schema v3: transcription attempts accumulate on AudioInfo (text, locale,
confidence, forced flag) — latest attempt is displayed, payload.text is
purely user writing, v2 notes migrate at read time. Editor shows the
transcript in its own live-updating section with insert-into-note; search
matches transcripts weighted by confidence. Watch recordings are now
deleted only on the phone's durable-ingest ack (transferUserInfo), closing
every phone-side loss window; failed sidecar writes unstage instead of
orphaning, and unreadable inbox recordings are surfaced in logs.

Claude-Session: https://claude.ai/code/session_014esDWi42URLEC6Cj17hGQ3
2026-07-16 12:29:49 -04:00
rzen c29d25748a Fix silent watch recordings: async session activation, encoder settings, error surfacing
Watch recordings arrived on the phone as 28-byte header-only m4a files
(record() reported success but no audio was ever captured). Activate the
audio session via watchOS's async activate(options:), drop the .spokenAudio
mode experiment, match the phone recorder's proven AAC settings
(44.1 kHz / 48 kbps), and surface silent failures: an AVAudioRecorderDelegate
catches encode errors mid-take, and a stop-time guard detects a dead
header-only file, deletes it, and shows the failure on the watch instead of
shipping an unplayable note to the phone.

Claude-Session: https://claude.ai/code/session_014esDWi42URLEC6Cj17hGQ3
2026-07-15 19:42:24 -04:00
rzen 798abf3b90 Watch: show version/build on screen, surface recording errors in UI
A tester on real hardware has no console, so a failed start looked like
a dead button and there was no way to tell which build the watch had
actually installed. Show the stamped version/build under the record
button, display the last start error in place of the hint text, and
fall back to the default audio session mode if .spokenAudio is rejected
with the .record category.

Claude-Session: https://claude.ai/code/session_01GKfAiKiQKLDTmbiGva4FGE
2026-07-15 16:07:32 -04:00
rzen 3a9c36d843 Fix dead record button after mic permission denial
The watch app's permission-denied state was a computed property reading
AVAudioApplication.shared.recordPermission — external state Observation
cannot track — so after a denied prompt the UI never flipped to the
'Microphone access is off' screen and the record button silently did
nothing. Store the denied flag as a tracked property instead, updated
on every permission request.

Also: log (instead of swallow) recorder start failures, drop phantom
recordings when no file was written (the watch simulator has no audio
input device), sweep orphaned metadata sidecars on reconcile, and add a
DEBUG-only 'autorecord' launch argument for CLI-driven testing.

Claude-Session: https://claude.ai/code/session_01GKfAiKiQKLDTmbiGva4FGE
2026-07-15 14:58:57 -04:00
rzen 86d74806c9 Add voice notes: on-device transcription, multi-language, watch capture
- Schema v2: Note.AudioInfo, .m4a sidecar next to the note JSON in iCloud
- AudioRecorderService (iOS/macOS) + SpeechAnalyzer transcription pipeline
  with enabled-language set and confidence-based auto-pick, re-transcribe menu
- Settings > Transcription > Languages with asset download/reserve handling
- watchOS app + accessory complication: one-button recorder, WCSession
  transferFile to phone, WatchInbox staging, direct-upsert ingestion
- Player UI, transcription status chips, quick-capture mic in notes list
- Version 0.2, changelog + README updated
2026-07-15 13:30:43 -04:00