Introduce a standalone macOS menu-bar app (OSGKeyboardMac) that reuses the
platform-agnostic OSGKeyboardShared core: record -> cloud/local ASR -> polish
-> insert. Local mode uses Qwen3-ASR via mlx-swift-asr (macOS 15+, Apple
Silicon); iOS targets stay zero-SPM.
Harden iCloud sync for multi-device correctness:
- Per-field settings merge (appSettings.v2) so concurrent edits no longer
clobber each other's unrelated fields.
- Per-device usage statistics (G-Counter) that sum instead of max().
- Tombstoned dictionary/history merge so deletes propagate and entries can't
resurrect.
- API keys replicate via iCloud Keychain, never iCloud KVS JSON; pulling a
legacy blob without key fields no longer wipes local Keychain entries.
- Add a low-risk "Sync Now" action in Settings.
Fix Flow keyboard mic state: stay orange until the host publishes a real ready
contract, share a single MicVoiceAvailability gate, and self-heal stale
cross-process heartbeat jitter instead of getting stuck.
Extract shared storage (SpeechHistoryStore/UsageStatisticsStore,
ConfigurationStore) into OSGKeyboardShared and add tests for the new
sync/merge logic.
Mirror the personal dictionary through iCloud Key-Value Store with
deterministic merge rules, main-app-only sync UI, and App Group as the
keyboard runtime cache. Add cloud-engine ASR with dictionary bias and
expand the bundled custom language model lexicon.
- fix(keyboard): drop unusable extensionContext.open; report the real
result of UIApplication.open and cancel the start watchdog immediately
on failure with clear "open OSGKeyboard" guidance instead of a 30s spin
- feat(capture): recover from audio route changes (AirPods/wired headset
plug-unplug) and phone-call interruptions by rebuilding the engine/tap
against the live hardware format
- feat(home): add a "Start" button in the Home footer when a session is
inactive and permissions are granted (no-jump manual restart)
- feat(hostapps): expand the return whitelist to 46 apps (Signal, Zoom,
Instagram, X, Douyin, Zhihu, Bilibili, Things, Firefox, ...) with
en/zh-Hans names and synced LSApplicationQueriesSchemes
- feat(island): use a "ready" checkmark instead of a mic glyph while idle
and set a staleDate so an orphaned Live Activity fades after a force-quit
- feat(coldstart): use the template OSG brand mark instead of a system
waveform glyph in the cold-start overlay
- perf(keyboard): rely on Darwin notifications as the primary session
signal and drop the fallback poll from 1s to 3s
- fix(keyboard): remove the redundant "Start" text button next to the
inactive-session hint on the keyboard
- docs: correct the per-take cap to 210s (3.5 min) and document that
force-quitting no longer resurrects the session (tracker + READMEs)
- Add OSGKeyboardLiveActivity widget extension (ActivityKit) with branded
compactLeading mark in the Dynamic Island during Flow sessions
- Wire FlowLiveActivityController into FlowSessionManager lifecycle
- Set keyboard PrimaryLanguage to mis in project.yml, Info.plist, and at runtime
- Enable NSSupportsLiveActivities on main app and widget extension targets
Co-authored-by: Rocky <hkgood@users.noreply.github.com>
- P0/P1: tail-drain state machine in FlowContinuousCapture with converter
flush; FlowSessionManager awaits drain before finalize
- P2: FlowCaptureTailDrain policy/tracker, pipeline diagnostics, unit tests
- P3: short final chunk merged re-transcription in ChunkedUtterancePipeline
- P4: UtteranceTranscriptStitcher composedSafely fallback; preview path parity
in LiveDictationController
Co-authored-by: Rocky <hkgood@users.noreply.github.com>
Reduce perceived latency from key release to final text:
- Adaptive chunking: 2.5s first chunk + 5s follow-ups so short
utterances start on-device recognition while still recording.
- Session-level ASR warmup and audio-format cache reuse to remove
per-utterance cold-start of SpeechAnalyzer.
- Mirror live pipelined partials to the keyboard transcript line via
a new flow.transcriptionPartial App Group key + Darwin ping.
Also commits the accumulated custom language model, Flow session,
keyboard extension restructure, and Xiaomi MiMo provider work in
progress on this branch.
Rework the marketing site with a cleaner, more restrained layout, replace emoji with Material Symbols monochrome icons, and add full SEO (Open Graph, Twitter cards, JSON-LD, canonical, robots.txt, sitemap.xml).
Rework the marketing site with a cleaner, more restrained layout, replace emoji with Material Symbols monochrome icons, and add full SEO (Open Graph, Twitter cards, JSON-LD, canonical, robots.txt, sitemap.xml).
Build a first-version SFCustomLanguageModelData for on-device ASR
customization, generated offline on macOS (no app code dependency).
- Scripts/lexicon: Python builders for Sogou-derived phrases (scel +
SogouPopularDict) and a curated bilingual AI/tech/brand seed lexicon
- export_clm.swift / prepare_clm.swift: macOS CLI tools that export the
.bin training asset and compile it into LM + Vocab via the Speech
framework
- Resources/CustomLanguageModel: generated phrases.tsv, manifests, the
129k-phrase .bin, and compiled LM/Vocab assets (zh_CN)
- .gitignore: ignore lexicon build cache and Python bytecode
Note: Sogou-derived data is for internal experimentation only; the
curated AI/tech seed is MIT and safe to ship.
Batch of in-progress app work from the working tree.
- feat(keyboard): CursorNavigation + CursorDragPad for caret movement;
KeyboardSoundFeedback for system key click sounds
- feat(dictionary): DictionaryAliasGenerator + PersonalDictionaryEntrySheet;
TranscriptPostProcessor quality gate; retire DictionaryLearner
- feat(ui): TabBarVisibility handling; drop PageHeaderRow /
PageHeaderConfirmButton; refresh views and localizable strings
- fix(security): move the hardcoded DeepSeek key out of
PreconfiguredKeys.swift into a gitignored PreconfiguredKeys.local.swift
(seeded from .example by generate-xcodeproj.sh)
- docs(agents): add Conventional Commits versioning + bilingual changelog rules
- chore(gitignore): ignore PreconfiguredKeys.local.swift, .cache/, pycache
Custom language model / lexicon work stays on
feature/custom-language-model-asr. Changelog bullets added under
[Unreleased]; no version bump.
Track dictation duration, dictation/translation character counts, and
personal dictionary size. Record metrics when Flow finalizes utterances.
Co-authored-by: Rocky <hkgood@users.noreply.github.com>
- Remove polish intensity and personal dictionary description subtitles
- Use consistent surface background on personal dictionary page
- Change empty state icon to library (menuBook) style
- Remove polish scenario and translation rows from onboarding
Co-authored-by: Rocky <hkgood@users.noreply.github.com>
XcodeGen 2.45 writes AppIcon.icon as a one-line PBXFileReference with
lastKnownFileType = wrapper.icon. Add a fast in-place upgrade to
folder.iconcomposer.icon before the generic brace-matching fallback.
Co-authored-by: Rocky <hkgood@users.noreply.github.com>
Remove fileTypes icon override and explicit type:file so XcodeGen 2.37+
emits folder.iconcomposer.icon directly. Skip patch when native output is
valid; otherwise run patch v3 with broader PBX discovery and validation.
Fixes persistent 'AppIcon.icon entry has unexpected shape' on Xcode 26.
Co-authored-by: Rocky <hkgood@users.noreply.github.com>
Brace-match the AppIcon.icon PBX object instead of relying on fixed
regex shapes. Fixes 'AppIcon.icon entry has unexpected shape' when
XcodeGen/Xcode 26 emits a different PBXFileReference format.
Co-authored-by: Rocky <hkgood@users.noreply.github.com>
- Remove polish scenario and ASR locale chips from keyboard top bar
- Fix polish intensity labels via SharedL10n (Shared.strings table)
- Merge polish intensity and personal dictionary into preferences card
- Personal dictionary: no list icon; detail view uses nav bar + back
Co-authored-by: Rocky <hkgood@users.noreply.github.com>
languageAndModelsSection and systemPromptLinkSection were renamed/
merged into languageAndPolishSection in v0.3 polish scenarios work,
but body still referenced the old symbols after intelligent-polish
changes were merged.
Co-authored-by: Rocky <hkgood@users.noreply.github.com>
Use ThemedRoot in preview instead of inaccessible ThemePalette().
Add setPersonalDictionary(_:) for let AppGroupStore bindings; use
it from PersonalDictionaryView and DictionaryLearner.
Co-authored-by: Rocky <hkgood@users.noreply.github.com>
AppGroupStore is a struct; property setters are mutating and cannot
be called on a let binding. Add setOnboardingPage and
setHasCompletedOnboarding helpers (like setDetectedAppContext).
Co-authored-by: Rocky <hkgood@users.noreply.github.com>