Add signed release APK builds on v*-tauri tags, minisign manifests per ABI, custom Android in-app updater, and CI cargo check for aarch64-linux-android.
Co-authored-by: Cursor <cursoragent@cursor.com>
Keep the submodule pinned to the reviewed commit while moving the fetch URL to Open-Less/qwen-asr, then document the review checklist future upgrades must follow.\n\nConstraint: #301 identified the personal upstream submodule URL as a supply-chain risk.\nRejected: Updating the submodule commit together with the URL change | would mix provenance hardening with unreviewed upstream code changes.\nConfidence: high\nScope-risk: narrow\nDirective: Do not point .gitmodules back to antirez/qwen-asr; sync upstream into the organization fork and review the diff first.\nTested: gh repo view Open-Less/qwen-asr; git submodule update --init --recursive openless-all/app/src-tauri/vendor/qwen-asr; git diff --check; npm run build; cargo check --manifest-path src-tauri/Cargo.toml\nNot-tested: macOS INSTALL=0 ./scripts/build-mac.sh C-link verification.
Adds Casks/openless.rb + update-cask.yml workflow + README install docs. Closes#254#5.
Note: Formula/openless.rb known to fail in Homebrew sandbox (per author); will be removed in follow-up. Cask version will be bumped to current 1.2.23 in same follow-up.
Provider credentials should follow the platform credential-store threat model instead of continuing normal plaintext JSON writes. The vault now stores the existing multi-provider credentials payload in the OS credential store, migrates the legacy JSON file only when the vault has no entry, removes the legacy file after a successful write, and keeps raw credential IPC restricted to the main settings window.
Constraint: User explicitly chose Keychain/Credential Manager/Linux keyring for issue #230.
Constraint: Preserve the existing provider schema and active-provider routing with minimal frontend churn.
Rejected: Keep plaintext JSON as the documented product choice | user rejected this direction.
Rejected: Split every credential field into separate vault entries | larger migration surface and risks losing active provider state.
Confidence: medium
Scope-risk: moderate
Directive: Security-model and storage-strategy choices must be confirmed with the user before implementation.
Tested: cargo check --manifest-path src-tauri/Cargo.toml; npm run -s build; git diff --check; grep for stale plaintext/Keychain fallback wording.
Not-tested: Manual migration on macOS Keychain, Windows Credential Manager, or Linux desktop keyring.
Related: https://github.com/appergb/openless/issues/230
README updates now place a unified acknowledgement section near the end (before License) in both English and Chinese, explicitly thanking sponsors, developers/contributors, and the LinuxDo community with a neutral non-endorsement disclaimer.
Constraint: Keep existing sponsor/developer showcase blocks intact while adding final acknowledgement wording
Rejected: Put acknowledgement near top profile blocks | user requested end-of-file placement
Confidence: high
Scope-risk: narrow
Directive: Keep acknowledgement wording neutral and avoid implying official affiliation
Tested: Manual README markdown diff review
Not-tested: Render preview in GitHub UI
* Remove fragile space from active app path
The Tauri app lived under a path containing a literal space, which made CI paths and local commands easy to quote incorrectly. Rename the active tree to openless-all and update repository references so scripts, docs, and release workflows use the same space-free path.
Constraint: Preserve the existing app layout and move only the containing directory name.
Rejected: Add compatibility symlinks | would keep two app paths and leave quoting hazards in place.
Confidence: high
Scope-risk: moderate
Tested: npm run build
Tested: cargo clean && cargo check
Tested: git diff --check
Tested: grep -R for old openless -all and openless%20-all references
* Keep Windows build docs aligned with space-free path
The app directory was renamed to openless-all, but the GNU/MinGW route still described the new name as if it contained a space. Update the wording so the rationale matches the current path and keeps the helper-script guidance focused on consistent GNU setup.
Constraint: Documentation-only code review follow-up.
Confidence: high
Scope-risk: narrow
Tested: git diff --check
* feat: add hold-to-talk hotkey mode (closes#1)
OpenLessHotkey now emits explicit .pressed / .released edge events on
the modifier-key trigger; the coordinator interprets them per the new
HotkeyMode preference (toggle stays the default, hold = press-and-hold).
Hold mode rules: .pressed on idle starts the session; .released stops
it from .listening; releasing during .starting cancels (no audio
useful was captured yet). Esc-cancel sets a one-shot suppress flag so
the trailing .released after a cancel does not re-trigger end.
Settings hub gets a "录音方式" segmented picker and a one-line hint
explaining the tradeoff. Bump version to 1.1.0; update README roadmap
and USAGE walkthrough to document the new mode.
* test: update HotkeyEventTests for pressed/released split
* chore: tag hold-to-talk build as 1.0.01 / A1003
* fix: stop window-background drag eating text selection; add eye toggle on secret fields
Settings window had isMovableByWindowBackground = true, so any drag
inside the content view dragged the whole window — making it
impossible to select words inside a TextField. Disable it; the native
title-bar strip (with the traffic lights) still drags the window.
PasteableCredentialField now exposes an eye / eye.slash toggle when
secure: true, so users can verify pasted API keys before saving.
* fix: stop pretending polish ran when it was skipped or errored
When the user removes the Ark API key (or the Ark call errors out),
DictationCoordinator was still showing the green "已插入" capsule and
recording the session in history under the originally-selected polish
mode. From the user's side it looked like polish had succeeded, even
though only the raw transcript reached the cursor.
Track a PolishOutcome (ok / skippedNoCredentials / failed) through
insertText. Capsule now uses a new CapsuleState.warning (orange) state
to surface honest messages — "已插入原文 · 未润色" / "润色失败 · 已用原文" —
and history saves the session as PolishMode.raw whenever polish
didn't actually run. The error capsule + 1.5s artificial sleep that
preceded a fake "success" insert is gone; warning state stays for the
normal 2.5s.
* feat(polish): make Structured mode prompt force a 1./1)/a. hierarchy
Some weaker chat models would emit a single flat list when the user
asked for Structured polish, even when the dictation clearly covered
multiple topics. The mode is meant to produce something pasteable as
an AI prompt or a working doc, not a wall of bullets.
Rewrite the .structured system prompt to be prescriptive: when the
input contains ≥2 themes, emit three explicit levels — top "1./2./3."
sections, "1)/2)/3)" sub-points indented 3 spaces, and "a./b./c."
detail items indented another 3 — and to fall back to a plain
paragraph when the input is short / single-topic. Add a concrete
format example so weaker models have a pattern to copy.
---------
Co-authored-by: baiqing <lbx12309@icloud.com>
Promote the English README to README.md and move the Chinese version to
README.zh.md so the default GitHub view ships in English. Replace the
incorrect "Talk (Talktastic)" reference in the comparison and intro
with Typeless (typeless.com), which is the actual product OpenLess is
positioned against. Update the cross-language switch in both files.