Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
3f8bf46
docs: add voice and translation POCs, UX prototypes and composer design
Hongwei-MB Oct 31, 2026
9f1afb4
refactor: remove legacy engines, routing and overlay UI
Hongwei-MB Oct 31, 2026
e650f57
build: retarget coverage and mutation gates to the composer modules
Hongwei-MB Oct 31, 2026
0a28b63
feat(drafting): add draft aggregate with ticketed results and frozen …
Hongwei-MB Oct 31, 2026
8d18130
feat(drafting): add unified text unit segmentation, routing and joining
Hongwei-MB Oct 31, 2026
f848ef6
feat(translation): add protected literals and plain-text prompt
Hongwei-MB Oct 31, 2026
695ee96
feat(inference): add OpenAI-compatible streaming chat client
Hongwei-MB Oct 31, 2026
117700b
feat(drafting): add serial draft session, source revision, staleness …
Hongwei-MB Oct 31, 2026
a8dcbb0
feat(translation): schedule latest-wins translation over the draft
Hongwei-MB Oct 31, 2026
7f66fef
feat(models): require pinned SHA256 per asset and support tar.gz/zip …
Hongwei-MB Oct 31, 2026
5b65c5f
feat(models): add the pinned model and runtime catalog
Hongwei-MB Oct 31, 2026
282963b
feat(inference): host pinned llama-server instances per role
Hongwei-MB Oct 31, 2026
3ed063d
test: add end-to-end translation probe and Nuke target
Hongwei-MB Oct 31, 2026
603822d
feat(composer): add composer view model and window-liveness check
Hongwei-MB Oct 31, 2026
bbda3ff
feat(composer): add localized texts and window placement
Hongwei-MB Oct 31, 2026
8f77082
feat(composer): add composer window and wire it to the global hotkey
Hongwei-MB Oct 31, 2026
98f9ef2
fix(models): remove the automatic hf-mirror fallback
Hongwei-MB Oct 31, 2026
722906c
docs: record M1 progress and deviations in the composer plan
Hongwei-MB Oct 31, 2026
78f070b
fix: address M1 review findings
Hongwei-MB Oct 31, 2026
9ef801b
fix(inference): stop llama-server processes orphaned by a crash at th…
Hongwei-MB Oct 31, 2026
f9963e0
feat(dictation): port the validated dictation session onto the unifie…
Hongwei-MB Oct 31, 2026
6cf453d
feat(cleanup): add the fidelity gate and the cleanup scheduler over t…
Hongwei-MB Oct 31, 2026
f69493e
feat(speech): add LLM cleaner, sherpa adapters and speech model catalog
Hongwei-MB Oct 31, 2026
af3602a
feat(voice): microphone and permission services, speech session facto…
Hongwei-MB Oct 31, 2026
547df7a
feat(composer): voice input, cleanup output and microphone interactions
Hongwei-MB Oct 31, 2026
c619fee
test: add the voice pipeline probe and ProbeVoice target; record M2 r…
Hongwei-MB Oct 31, 2026
438ee0d
fix(composer): center the mic icon, align segment labels, make displa…
Hongwei-MB Oct 31, 2026
5f885fd
feat(composer): no-sound banner and a notice for sentences that kept …
Hongwei-MB Oct 31, 2026
5c9133a
feat(settings): settings window with hotkey, language, translator tie…
Hongwei-MB Oct 31, 2026
f622dd3
feat(cloud): opt-in cloud translation and cleanup via an OpenAI-compa…
Hongwei-MB Oct 31, 2026
6ecc9c8
feat(composer): restore unsent source text on the next summon
Hongwei-MB Oct 31, 2026
1444d7d
feat(transcription): import a WAV recording as a timeline and export SRT
Hongwei-MB Oct 31, 2026
a6137d2
feat(composer): recent drafts menu replaces the single unsent draft
Hongwei-MB Oct 31, 2026
52134bf
feat(settings): migrate schema 2 settings and offer removal of old mo…
Hongwei-MB Oct 31, 2026
d563bba
feat(a11y): accessible names and live regions; fix macOS microphone p…
Hongwei-MB Oct 31, 2026
f6e1408
docs: rewrite README for 2.0, add third-party notices, record S1/S5/S…
Hongwei-MB Oct 31, 2026
61d2a7f
test: make the mutation gate runnable and raise the score above 80%
Hongwei-MB Oct 31, 2026
bab55ce
docs: record packaging and CI gate results
Hongwei-MB Oct 31, 2026
c76e407
build: upgrade Core, build tooling and test packages to the latest st…
Hongwei-MB Nov 1, 2026
7b5b375
feat(desktop): rebuild the composer and settings UI to the v3 prototy…
Hongwei-MB Nov 1, 2026
15acd69
docs: add the web UI design, a feasibility probe and the handoff plan
Hongwei-MB Nov 1, 2026
e8e3e65
docs: state that the web UI uses the system web engine and sets a fea…
Hongwei-MB Nov 1, 2026
a6f5231
docs: record the web shell feasibility results
Hongwei-MB Nov 1, 2026
a640d9f
docs: build the web UI without Node
Hongwei-MB Nov 1, 2026
292220f
build: add the web UI assets, page builder and browser tests
Hongwei-MB Nov 1, 2026
d9bf77a
feat(web): add the bridge, the intents and the view state
Hongwei-MB Nov 1, 2026
0345cc4
feat(web): render the composer from view-state snapshots
Hongwei-MB Nov 1, 2026
77362bf
feat(desktop): host the composer in a web view
Hongwei-MB Nov 1, 2026
47fc9ca
feat(settings): render the settings in the web view
Hongwei-MB Nov 1, 2026
7c6f64a
feat(settings): add the cleanup switch and a status dialog, localize …
Hongwei-MB Nov 1, 2026
8ab4b70
docs: update README, CHANGELOG, CONTRIBUTING and the progress table f…
Hongwei-MB Nov 1, 2026
d52c985
fix: attach the tray icon to the application and never target our own…
Hongwei-MB Nov 1, 2026
1b3b9d5
fix: composer window comes up 0x0 and never measures when parked off …
Hongwei-MB Nov 1, 2026
f7085fa
fix(composer): clean typed text after a typing pause, opaque panel wi…
Hongwei-MB Nov 1, 2026
d95b056
fix(composer): drag the window by its header and keep it inside the s…
Hongwei-MB Nov 1, 2026
9869df9
feat(composer): start every summon empty and offer the unsent draft a…
Hongwei-MB Nov 1, 2026
c43b956
feat(composer): toggle dictation with a shortcut and add shortcuts fo…
Hongwei-MB Nov 1, 2026
52c4e49
docs: design the user preferences (what is remembered per app and wha…
Hongwei-MB Nov 1, 2026
41a6c33
feat(composer): remember the last output and direction per target app
Hongwei-MB Nov 1, 2026
e12f979
fix(cleanup): do not skip the typing pause when a scan sees an edit f…
Hongwei-MB Nov 1, 2026
00f187c
feat(composer): keep the microphone open through pauses
Hongwei-MB Nov 1, 2026
1d05314
chore: release 2.0.0
Hongwei-MB Nov 1, 2026
df956ca
ci: run the tests on macOS with the browsers installed, and make fixt…
Hongwei-MB Nov 1, 2026
c56501e
build: pin WiX back to 6.0.2
Hongwei-MB Nov 1, 2026
7131c8c
chore: remove code, docs and tools that 2.0 does not use
Hongwei-MB Nov 1, 2026
e7a3b99
feat(release): ship the update feeds so installed apps can update the…
Hongwei-MB Nov 2, 2026
f459703
build: stamp the macOS bundle with the version without its pre-releas…
Hongwei-MB Nov 2, 2026
574dcf3
docs: name the update packages as they are published
Hongwei-MB Nov 2, 2026
38ebf1e
feat(speech): prepare the models before they are needed
Hongwei-MB Nov 2, 2026
e9cd2c7
fix(update): make installed apps able to find updates
Hongwei-MB Nov 2, 2026
0d8b51b
test: remove two timing races that failed the pull request build
Hongwei-MB Nov 2, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
45 changes: 25 additions & 20 deletions .cursor/rules/architecture.mdc
Original file line number Diff line number Diff line change
@@ -1,37 +1,42 @@
---
description: LiveLingo architecture boundaries — ViewModel / UI / Platform separation
description: LiveLingo architecture boundaries — state in C#, the page only draws, platform code behind interfaces
alwaysApply: true
---

# Architecture Boundaries

## Core Principle

UI 不测试逻辑,逻辑不依赖 UI。
UI 不测试逻辑,逻辑不依赖 UI。一个功能只由一个服务或组件实现;不为兼容旧行为堆叠分支。

## ViewModel Layer
## State and logic (C#)

- ViewModel **禁止** 引用 `Avalonia.*` 命名空间
- ViewModel **禁止** 使用 `Dispatcher`、`Dispatcher.UIThread` 或任何线程调度 API
- ViewModel 只依赖接口 (`ISettingsService`, `ITranslationPipeline`, `ITextInjector`, `IModelManager` 等)
- ViewModel 使用 `CommunityToolkit.Mvvm` (`ObservableObject`, `RelayCommand`)
- 需要通知 UI 的行为通过事件 (`event Action? RequestClose`) 或属性变更实现
- `ComposerViewModel`、`SettingsViewModel` 和 Core 持有全部状态与逻辑
- ViewModel **禁止** 引用 `Avalonia.*`,禁止使用 `Dispatcher` 或任何线程调度 API
- ViewModel 只依赖接口(`ISettingsService`、`IModelManager`、`IVoiceInput`、`ITextInjector` 等)
- ViewModel 使用 `CommunityToolkit.Mvvm`;需要通知界面时用事件或属性变更

## View Layer (Avalonia)
## The page (Web UI)

- View 只负责绑定和布局
- View 中 `code-behind` 仅处理 Avalonia 特有交互 (窗口定位、焦点、动画)
- Dispatcher 调用只允许出现在 View 或 `App.axaml.cs` 中
- 窗口是包着 WebView 的薄壳;页面(`Web/Assets`,Preact + htm,无 Node 构建)只绘制整份快照,只发送封闭集合的意图
- 页面**不持有逻辑**:是否可用、校验、同意、记忆都在 C# 决定
- 窗口代码只处理 Avalonia 特有的事:定位、焦点、停放;`Dispatcher` 只出现在窗口或 `App.axaml.cs`

## Platform Layer
## Platform layer

- 平台差异通过接口抽象 (`IPlatformServices`, `IClipboardService`, `ITextInjector`)
- 具体实现放在 `Platform/Windows/` 或 `Platform/macOS/`
- 禁止在 ViewModel 中直接使用 P/Invoke 或平台 API
- 平台差异通过接口抽象(`IPlatformServices`、`IClipboardService`、`ITextInjector`、`IWindowTracker`)
- 实现放在 `Platform/Windows/` 或 `Platform/macOS/`
- 禁止在 ViewModel 中使用 P/Invoke 或平台 API
- 产品只支持 Windows x64 与 macOS arm64(llama.cpp 运行时的固定版本)

## Privacy

- 默认语音和文本不离开本机;云端调用必须由用户按功能显式开启,且只发文本
- 凭据只进系统密钥存储,不写入代码、日志或设置文件

## Testing

- ViewModel 测试使用 NSubstitute mock 所有依赖
- Stryker 变异测试 **不测试** Avalonia UI 项目(源生成器不兼容)
- Stryker 只测试 `LiveLingo.Core` 项目
- 代码覆盖率通过 `test.runsettings` 排除平台实现和 View 层
- ViewModel 测试使用 NSubstitute 替换全部依赖;测试不碰真实磁盘、网络或界面框架
- 页面由 `LiveLingo.Web.Tests`(Playwright,WebKit + Chromium)用黄金快照测试;夹具由 `Desktop.Tests` 用 `UPDATE_FIXTURES=1` 生成,且必须与时区、操作系统无关
- Stryker 只测试 `LiveLingo.Core` 的纯逻辑模块(见 `tests/LiveLingo.Core.Tests/stryker-config.json`)
- 代码覆盖率通过 `test.runsettings` 排除平台实现和窗口壳层
19 changes: 16 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ permissions:
contents: read

jobs:
# The product ships for Windows x64 and macOS arm64 (the only pinned llama.cpp runtimes), so its tests run on one of them.
test:
runs-on: ubuntu-latest
runs-on: macos-latest

steps:
- uses: actions/checkout@v4
Expand All @@ -29,7 +30,19 @@ jobs:
- name: Restore tools
run: dotnet tool restore

- name: Test + Coverage + Mutation
- name: Build
run: |
chmod +x build.sh
./build.sh Test
./build.sh Build

# The web tests drive WebKit and Chromium.
- uses: actions/cache@v4
with:
path: ~/Library/Caches/ms-playwright
key: ${{ runner.os }}-playwright-${{ hashFiles('tests/LiveLingo.Web.Tests/*.csproj') }}

- name: Install browsers for the web tests
run: pwsh tests/LiveLingo.Web.Tests/bin/Release/net10.0/playwright.ps1 install webkit chromium

- name: Test + Coverage + Mutation
run: ./build.sh Test
50 changes: 42 additions & 8 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,10 @@ jobs:
- name: Compile
run: dotnet build LiveLingo.slnx -c Release --nologo

# Stage 2: Run tests
# Stage 2: Run tests (on macOS: the product ships for Windows x64 and macOS arm64, the pinned llama.cpp runtimes)
test:
needs: compile
runs-on: ubuntu-latest
runs-on: macos-latest

steps:
- uses: actions/checkout@v4
Expand All @@ -75,10 +75,22 @@ jobs:
- name: Restore tools
run: dotnet tool restore

- name: Test
- name: Build
run: |
chmod +x build.sh
./build.sh Test
./build.sh Build

# The web tests drive WebKit and Chromium.
- uses: actions/cache@v4
with:
path: ~/Library/Caches/ms-playwright
key: ${{ runner.os }}-playwright-${{ hashFiles('tests/LiveLingo.Web.Tests/*.csproj') }}

- name: Install browsers for the web tests
run: pwsh tests/LiveLingo.Web.Tests/bin/Release/net10.0/playwright.ps1 install webkit chromium

- name: Test
run: ./build.sh Test

# Stage 3: Build platform-specific installers
pack:
Expand Down Expand Up @@ -123,25 +135,29 @@ jobs:
shell: bash
run: |
chmod +x build.sh
./build.sh PackMac --skip Test --Runtime ${{ matrix.runtime }} --Version ${{ needs.compile.outputs.version }}
./build.sh Pack --skip Test --Runtime ${{ matrix.runtime }} --Version ${{ needs.compile.outputs.version }}

- name: Upload installers
# The installers and what installed applications update from: the full package and its feed (releases.<channel>.json).
- name: Upload release files
uses: actions/upload-artifact@v4
with:
name: installers-${{ matrix.runtime }}
path: |
releases/*.exe
releases/*.msi
releases/*.pkg
releases/*.nupkg
releases/releases.*.json
releases/RELEASES*
if-no-files-found: error

# Stage 4: Create GitHub Release with only installer files
# Stage 4: Create the GitHub Release with the installers and the update feeds
release:
needs: [compile, pack]
runs-on: ubuntu-latest

steps:
- name: Download all installer artifacts
- name: Download all release files
uses: actions/download-artifact@v4
with:
path: installers
Expand All @@ -151,13 +167,31 @@ jobs:
- name: List release files
run: ls -la installers/

# An application only updates from a release whose feed names a package that is in it, so a release without one is not published.
- name: Check the update feeds
run: |
for channel in win osx; do
feed="installers/releases.${channel}.json"
test -f "$feed" || { echo "Missing $feed"; exit 1; }
jq -e --arg v "${{ needs.compile.outputs.version }}" \
'[.Assets[] | select(.Version == $v and .Type == "Full")] | length == 1' "$feed" > /dev/null \
|| { echo "$feed has no full package for ${{ needs.compile.outputs.version }}"; exit 1; }
for file in $(jq -r '.Assets[].FileName' "$feed"); do
test -f "installers/$file" || { echo "$feed names $file, which was not built"; exit 1; }
done
done

- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ needs.compile.outputs.tag }}
name: LiveLingo ${{ needs.compile.outputs.tag }}
prerelease: ${{ contains(needs.compile.outputs.version, '-') }}
files: |
installers/*.exe
installers/*.msi
installers/*.pkg
installers/*.nupkg
installers/releases.*.json
installers/RELEASES*
generate_release_notes: true
10 changes: 10 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -428,3 +428,13 @@ stryker-run.log
# Nuke temp
.nuke/temp/
.DS_Store

# Local agent scratch space
.superpowers/

# POC data (audio corpora, results, models are not committed)
poc/**/corpus*/
poc/**/results/
poc/**/models/
*.wav
*.gguf
38 changes: 4 additions & 34 deletions .nuke/build.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,9 @@
"Clean",
"Mutate",
"Pack",
"PackMac",
"PackMsi",
"ProbeStt",
"ProbeTranslation",
"ProbeTranslationAll",
"ProbeVoice",
"Publish",
"Restore",
"Run",
Expand Down Expand Up @@ -128,46 +126,18 @@
"description": "Minimum line coverage percentage",
"format": "int32"
},
"EnableSttProbe": {
"type": "boolean",
"description": "Enable sherpa-onnx STT regression probe target"
},
"EnableTranslationProbe": {
"type": "boolean",
"description": "Enable translation regression probe target"
},
"MutationThreshold": {
"type": "integer",
"description": "Minimum mutation score percentage",
"format": "int32"
},
"ProbeCases": {
"ProbeCorpus": {
"type": "string",
"description": "Batch probe cases: source=>expected;source=>expected"
},
"ProbeExpectedContains": {
"type": "string",
"description": "Expected substring in translation result"
"description": "Directory with scenarios.json and audio/<id>.wav used by ProbeVoice (see poc/voice-dictation/corpus)"
},
"ProbeModelPath": {
"type": "string",
"description": "Model path used by translation probe"
},
"ProbeSourceText": {
"type": "string",
"description": "Source text used by translation probe"
},
"ProbeSttExpected": {
"type": "string",
"description": "Expected substring in the STT probe transcription result"
},
"ProbeSttLang": {
"type": "string",
"description": "Optional language hint (ISO-639-1) for the STT probe, e.g. en / zh / ja"
},
"ProbeWavPath": {
"type": "string",
"description": "Path to a 16 kHz mono wav file used by the STT probe"
"description": "Model storage directory used by end-to-end probes (defaults to the app's model directory)"
},
"Runtime": {
"type": "string",
Expand Down
7 changes: 0 additions & 7 deletions .superpowers/brainstorm/19181-1774361145/.events

This file was deleted.

1 change: 0 additions & 1 deletion .superpowers/brainstorm/19181-1774361145/.server-stopped

This file was deleted.

1 change: 0 additions & 1 deletion .superpowers/brainstorm/19181-1774361145/.server.pid

This file was deleted.

44 changes: 0 additions & 44 deletions .superpowers/brainstorm/19181-1774361145/architecture-options.html

This file was deleted.

Loading
Loading