Commit Graph
641 Commits
Author SHA1 Message Date
TRIPandbaiqing e358c20b20 fix(updater): use GitHub atom feed for Beta lookup, dodge API rate limit (#350)
用户报「获取 Beta 版本信息失败」根因:fetch_latest_beta_release 调
api.github.com/repos/.../releases,未认证 60 req/h/IP。多次切 Beta toggle
+ 同 IP 共享配额(公司/家庭网络后),轻易撞 403 rate limit exceeded。
现场实测 IP 已耗尽:x-ratelimit-remaining: 0。

修法:换成 GitHub releases.atom(公开 RSS feed,CDN cache,无 API rate limit)。

具体改动:
- fetch_latest_beta_release 端点从 api.github.com 改成 github.com/.../releases.atom
- 提取一个纯函数 parse_latest_beta_from_atom 做字符串解析(不引 XML 库——
  feed 格式稳定,找 /releases/tag/ 锚点抓 tag 即可),方便单测
- atom feed 不显式标 prerelease,但项目约定 tag 后缀 `-beta-tauri` 就是 Beta,
  过滤后缀已足够
- timeout 从 10s 提到 15s,给跨境网络更多余地
- 加 2 个 unit test:(1) 混合 stable+beta 时返回 Beta entry;(2) 全 stable
  时返回 None。两个 test 都已 pass

不改前端:JS 端调用签名 / 错误展示路径不变,下次 Beta-3 release 出来后用户
装上即生效。

Co-authored-by: baiqing <lbx12309@icloud.com>
2026-05-08 09:47:18 +08:00
TRIPandbaiqing 8b55469d8e feat(ui): drop sidebar version chip; show BETA tag only on beta builds (#348)
用户反馈:左上角 OpenLess logo 旁边的 v1.2.24-2 chip 在窄侧栏下被截断换行
(视觉上读作 "v1.2.24-/2"),太丑且没有信息价值——版本号在底部 footer
和「设置 → 关于」里都已经展示,不需要这第三处。

同时 BETA 标签当前是无条件渲染的,正式版用户也会看到,违反"Beta 不
泄漏到正式版"原则。

改动:
- appVersion.ts:新增 IS_BETA_BUILD 常量。约定:semver prerelease 段
  (含 `-`)= Beta(如 1.2.24-1 / 1.2.24-2);不含 `-` = 正式版
  (如 1.2.23 / 1.2.24)。
- FloatingShell.tsx:
  - 删左上 brand 行里的 version chip <span>(保留 logo + "OpenLess" 文字)
  - BETA 区域用 {IS_BETA_BUILD && (...)} 包条件渲染。正式版 build 直接
    不渲染整块,避免普通用户误以为正式版是 Beta

footer 里的 "版本 v1.2.24-2 检查" 和 设置 → 关于的 AboutUpdateControl
保留不动——那两处是用户主动想看的版本信息,本次只删左上的冗余 chip。

npm run build 干净通过。

Co-authored-by: baiqing <lbx12309@icloud.com>
2026-05-08 09:39:14 +08:00
TRIPandbaiqing b7685cadda docs(release): make macOS xattr workaround discoverable (#347)
发现的真因:v1.2.23 Stable 和 v1.2.24-1 Beta 的 macOS DMG 都是 ad-hoc 签名 + 未经 Apple 公证(仓库没配 APPLE_CERTIFICATE 等 secrets)。macOS 14+ Gatekeeper 默认拒绝运行未公证的 app,弹"OpenLess 已损坏"。
build-mac.sh:40-41 注释已经写明这是已知限制:
  "用户免手工 xattr 的根本方案是 Developer ID 签名 + Apple notarization"

之前 README 只在 brew install 段写了 xattr -cr 指令,DMG 直装路径没写。
用户首次装 Beta 不知道要做这一步,看到"已损坏"以为 release 坏了。

本 PR:
- README.md / README.zh.md 的「下载与安装」段,DMG 直装路径加上 xattr -cr 指令 + 一句解释为什么需要(ad-hoc 签名、未公证)
- release-tauri.yml 的 Create release step 加 body 模板,所有未来 release 自动 prepend 一段:macOS xattr 指令 + Beta/Stable 渠道说明。用 append_body: true 让它放在 generated notes 之前

不在本 PR:配 Apple Developer 证书 + secrets——那是根治方案,需要 $99/年 Apple Developer 账号 + 用户决定要不要走那条路。

Co-authored-by: baiqing <lbx12309@icloud.com>
2026-05-08 09:27:16 +08:00
Chris233 66e0efa7de Merge pull request #343 from H-Chris233/fix/issue-310-history-load-errors
修复 History IPC 失败时无反馈和卡 loading
2026-05-08 09:12:05 +08:00
TRIPandbaiqing 2a99d6bf6e chore: bump version to 1.2.24-2 (Beta-2) (#345)
Co-authored-by: baiqing <lbx12309@icloud.com>
2026-05-08 09:08:23 +08:00
TRIPandbaiqing 58a0ad9e62 fix(release): use tagged URL in beta manifest, not releases/latest (#344)
修复 v1.2.24-1-beta-tauri release verification 时发现的 latent bug:
Beta manifest 里 url 字段指向 https://github.com/.../releases/latest/download/<asset>,
但 releases/latest 永远是最新非-prerelease(即 Stable),Beta 用户按这个 url
auto-update 会拉到 Stable 包:

- macOS Beta: 文件名 OpenLess_aarch64.app.tar.gz 跟 Stable 重名 → 下载 Stable 包,
  装上的是 1.2.23 但 manifest 声称 1.2.24-1,version drift
- Windows/Linux Beta: 文件名带版本号 OpenLess_1.2.24-1_x64-setup.exe / .AppImage,
  releases/latest 路径下没这个文件 → 直接 404

Stable 渠道沿用 releases/latest 是对的(latest = Stable)。

修法:write-updater-manifest.mjs 多读一个 OPENLESS_RELEASE_TAG env,beta 时
url 拼成 releases/download/<tag>/<asset>(指定具体 tag,不被 prerelease 折叠
影响);stable 不变。脚本对 beta 缺 tag 做 fail-fast。

release-tauri.yml 在 manifest step 多注入 OPENLESS_RELEASE_TAG: ${{ github.ref_name }}。

为什么不重发 v1.2.24-1:当前走 Path A 手动下载式 opt-in,前端调
fetch_latest_beta_release 拿 GitHub release 页 html_url,用户跳浏览器手动选包,
不消费 manifest.url。所以 v1.2.24-1 已发布的 manifest 里 url 错也是 dormant。
下一轮 Beta tag(v1.2.24-2-beta-tauri 或 stable cut 后再做 Beta)会用修复后
的脚本产出正确 URL。

本地 smoke test:
- channel=beta + 缺 OPENLESS_RELEASE_TAG → fail-fast 抛 "is required"
- channel=beta + 有 tag → env 检查通过,进入 artifact 解析
- channel=stable + 不传 tag → 维持原行为
- python yaml.safe_load() 解析 release-tauri.yml 通过

Co-authored-by: baiqing <lbx12309@icloud.com>
2026-05-08 09:04:14 +08:00
H-Chris233 f79a8dc089 Avoid restoring stale History snapshots
The History mutation handlers already wait for backend success before changing visible list state, so failure recovery does not need to write back the request-time snapshot. Removing that restoration avoids overwriting a newer refresh result, and delete success now updates from the latest list state instead of the closure captured before the IPC call.

Constraint: PR #343 review identified stale snapshot writes during overlapping refresh and mutation requests.\nRejected: Add action-wide locking | more UI state than needed once failed mutations stop writing stale snapshots.\nConfidence: high\nScope-risk: narrow\nTested: cd openless-all/app && git diff --check && npm run build\nNot-tested: Manual overlapping refresh/delete in the Tauri app.
2026-05-08 08:50:47 +08:00
H-Chris233 1676557a75 Keep History usable after IPC failures
History actions previously assumed list, clear, and delete IPC calls would resolve. A rejected load could leave the page stuck in loading, while failed mutations gave no user-visible feedback. The page now clears loading in finally, shows retryable inline load errors, and reports clear/delete failures while restoring the prior local selection and items.

Constraint: Issue #310 asks for inline card feedback without changing Rust handlers or introducing a toast system.\nRejected: New shared error component | broader UI surface than needed for this single-page failure path.\nConfidence: high\nScope-risk: narrow\nTested: cd openless-all/app && git diff --check && npm run build\nNot-tested: Live Tauri IPC failure injection.\nRelated: https://github.com/appergb/openless/issues/310
2026-05-08 08:06:29 +08:00
Chris233 13937d21fd Merge pull request #342 from H-Chris233/fix/issue-311-overview-load-errors
修复 Overview IPC 加载失败时误显示空数据
2026-05-08 08:02:27 +08:00
H-Chris233 d32da5c36c Expose Overview IPC load failures inline
Overview previously treated rejected history and credential IPC calls like empty data, which made backend read failures indistinguishable from a clean first run. The page now keeps separate error flags, shows provider status as unreadable when credential status cannot load, and replaces history-derived metrics/recent rows with retryable inline failure states.

Constraint: Issue #311 asks for per-card inline feedback without changing backend handler signatures or adding global toast UI.\nRejected: Global error boundary or toast | broader UI behavior than needed for the Overview failure path.\nConfidence: high\nScope-risk: narrow\nTested: cd openless-all/app && git diff --check && npm run build\nNot-tested: Live Tauri IPC failure injection.\nRelated: https://github.com/appergb/openless/issues/311
2026-05-08 07:25:38 +08:00
Chris233 c4a7ebe62c Merge pull request #338 from H-Chris233/fix/issue-315-selectionask-save-feedback
修复划词追问保存失败无反馈
2026-05-08 07:16:52 +08:00
H-Chris233 b0f481c78e Block shortcut recording during Selection Ask saves
The Selection Ask page now disables its card toggles while a save is in flight, but the nested shortcut recorder still accepted new recordings. That left a small overlap window where a second QA hotkey save could race the current setQaHotkey/savePrefs pair.\n\nThis keeps the recorder default behavior unchanged for other pages by adding an optional disabled prop and only wiring it from Selection Ask during its saving state.\n\nConstraint: Review feedback on PR #338 requested preventing overlapping QA shortcut saves without broad settings-queue refactoring.\nRejected: Global serialization inside ShortcutRecorder | unnecessary for pages that already own their own persistence state.\nConfidence: high\nScope-risk: narrow\nTested: cd openless-all/app && npm run build\nTested: git diff --check\nNot-tested: Manual browser interaction against a slow Tauri IPC response.\nRelated: https://github.com/appergb/openless/issues/315\nRelated: https://github.com/appergb/openless/pull/338
2026-05-08 06:47:36 +08:00
Chris233 50cd1ae583 Merge pull request #341 from Cooper-X-Oak/docs/backfill-cooper-developer-entry-beta
docs: add Cooper's circular avatar
2026-05-08 06:44:40 +08:00
cooper e331784b3b docs: add Cooper's circular avatar image
- Add assets/people/cooper.png (circular avatar)
- Replace GitHub API link with local image file
- Match TRIP and Chris233's avatar style
2026-05-08 00:34:48 +08:00
cooper 620e817939 docs: make Cooper avatar circular
Add border-radius: 50% to Cooper's avatar to match TRIP and Chris233's circular style.
2026-05-08 00:32:29 +08:00
cooper dd96d64672 docs: add website URLs back to developer section
- Add website URLs below each developer's name
- Increase cell width from 110 to 140 to accommodate URLs
- Keep circular avatars and table layout
2026-05-08 00:27:31 +08:00
cooper 712e9564f2 docs: refine developer section 2026-05-08 00:02:23 +08:00
H-Chris233 b027d8b210 Expose Selection Ask save failures before state drifts
Selection Ask reused the same QA hotkey and history persistence paths as other settings pages, but the page did not surface pending, success, or failure states. A rejected hotkey registration or settings write could therefore leave users believing the feature or history option was enabled when the backend had not accepted the change.\n\nThis keeps the existing persistence contract and mirrors the Translation page status treatment: register QA hotkeys before saving prefs, stop on registration errors, refresh after write failures, and add localized feedback for all supported UI languages.\n\nConstraint: Issue #315 requests minimal UI feedback and rollback behavior without refactoring the shared settings queue.\nRejected: Refactor HotkeySettingsContext persistence semantics | broader cross-page behavior change than needed for this bug.\nConfidence: high\nScope-risk: narrow\nTested: cd openless-all/app && npm run build\nTested: git diff --check\nNot-tested: Manual Tauri hotkey conflict flow on macOS/Windows.\nRelated: https://github.com/appergb/openless/issues/315
2026-05-07 23:32:41 +08:00
Chris233 fc24d37fdd Merge pull request #331 from H-Chris233/fix/issue-313-style-save-feedback
修复 Style 页保存失败后的状态回滚
2026-05-07 22:57:22 +08:00
TRIPandbaiqing 4962a661a3 chore: bump version to 1.2.24-1 (#337)
将 Beta 版本号从 1.2.24-beta.1 改为 1.2.24-1。

原因:Tauri MSI bundler 对 prerelease 段的限制比 npm/Cargo semver 严格,
要求 prerelease identifier 必须是「numeric-only and ≤ 65535」。
1.2.24-beta.1(含字母 + 多段)会让 windows MSI 构建直接报:
  failed to bundle project: optional pre-release identifier in app version
  must be numeric-only and cannot be greater than 65535 for msi target

实测后果:上次 v1.2.24-beta.1-beta-tauri tag 触发的 CI run 25501471895,
macOS arm64 / macOS x64 / Linux 都成功,只有 Windows MSI 卡在 candle 之前。

修复:
- 1.2.24-1 是合法的 npm/Cargo semver prerelease 写法( id="1" 纯数字)
- Tauri MSI 接受这种格式
- semver 排序仍然 1.2.23 < 1.2.24-1 < 1.2.24,符合渠道隔离要求
- 后续 Beta 迭代版本号: 1.2.24-2 / 1.2.24-3 / ...
- Beta 身份不靠版本字面,靠 tag 后缀 `-beta-tauri`(release-tauri.yml 检测)

5 处版本号同步:package.json、package-lock.json (root + nested)、
tauri.conf.json、Cargo.toml、Cargo.lock。CI 用的同一段 verify 通过。

合入后由维护者删旧 tag/release(已删)+ 推 v1.2.24-1-beta-tauri 触发新 CI。

Co-authored-by: baiqing <lbx12309@icloud.com>
2026-05-07 22:40:18 +08:00
TRIPandbaiqing 2246d8f660 fix(release): merge duplicate jobs.build.env block in release-tauri.yml (#335)
PR #330 在 jobs.build 顶层多加了一个 env: 块来定义 OPENLESS_RELEASE_CHANNEL,
但下面 strategy/runs-on 之后已经有一个 env: 块(TAURI_SIGNING_PRIVATE_KEY 等)。
YAML map 不允许重复 key——GitHub Actions 解析直接 fail,整条 release-tauri.yml
工作流变成 "workflow file issue" 启动失败。

修复:把 OPENLESS_RELEASE_CHANNEL 并到下面那个唯一的 env: 块里,保留完整注释。

校验:
- python -c "yaml.safe_load(...)" 解析成功
- jobs.build.env 现在有 3 个 key: OPENLESS_RELEASE_CHANNEL, TAURI_SIGNING_PRIVATE_KEY,
  TAURI_SIGNING_PRIVATE_KEY_PASSWORD

Co-authored-by: baiqing <lbx12309@icloud.com>
2026-05-07 22:16:27 +08:00
TRIPandbaiqing f4442e52d9 chore: bump version to 1.2.24-beta.1 (#334)
Co-authored-by: baiqing <lbx12309@icloud.com>
2026-05-07 22:04:50 +08:00
H-Chris233 f67e906af1 Prevent silent Style preference save failures
Style page writes previously updated local UI state before awaiting IPC, so rejected handlers left the page showing values that were never persisted. The change keeps the optimistic update, but centralizes rollback to the previous preferences and surfaces the backend error inline near the failing control.

Constraint: Issue #313 asks for minimal frontend-only handling; backend handlers remain unchanged.\nRejected: Global toast framework | outside the issue scope and heavier than an inline page error.\nConfidence: high\nScope-risk: narrow\nTested: cd openless-all/app && npx tsx src/lib/stylePrefs.test.ts\nTested: cd openless-all/app && npm run build\nTested: git diff --check\nRelated: https://github.com/appergb/openless/issues/313
2026-05-07 22:01:40 +08:00
TRIPandbaiqing fd79a051bd feat(updater): manual-download Beta opt-in in Settings → About (#332)
* feat(updater): manual-download Beta opt-in in Settings → About

接入 PR-B-2:客户端「加入 Beta 渠道」开关 + 文档完善。

为什么不走 auto-update 切 endpoint:
  tauri-plugin-updater 2.10 的 Builder 不暴露 endpoints() 运行时 API,
  endpoints 只能从 tauri.conf.json 编译期读,不能跑时切。继续用 plugin
  自带 check 路径意味着 Beta 包会被推到所有用户,违背「Beta 不溢出正式
  版」原则。fork plugin 或自实现 update flow ~500 行高风险,本轮采用
  最稳路径:plugin 永远只读正式版 manifest(旧文件名),Beta 改成手动
  下载——Settings 里展示最新 prerelease 的下载入口,用户点了跳浏览器。

Rust 端:
- types.rs:UpdateChannel enum (Stable | Beta) + UserPreferences::update_channel
  字段;UserPreferencesWire / Default / Deserialize 全套兼容(旧 prefs 反序列化
  默认 Stable,迁移无痛)。
- commands.rs:三个新命令——
  - get_update_channel:读 prefs
  - set_update_channel:写 prefs,复用 persist_settings + emit prefs:changed
  - fetch_latest_beta_release:reqwest 调 GitHub Releases API,过滤
    prerelease=true 且 tag 以 -beta-tauri 结尾的最新一条
- lib.rs:三个命令注册到 invoke_handler

前端:
- ipc.ts:UpdateChannel + LatestBetaRelease 类型 + 三个 invoke 包装
- SettingsModal.tsx:在 AboutMini 末尾加 BetaChannelControl 组件——
  Toggle 切换渠道;切到 beta 时拉一次最新 prerelease 信息,展示
  「最新 Beta:v1.x.x-beta-tauri」+「前往下载」按钮(openExternal 跳
  GitHub release 页面)+ 重新查询按钮。切回 stable 立即清空状态。
- Settings.tsx:把 Toggle 组件 export,让 SettingsModal 复用同一开关样式。
- i18n 五个 locale(zh-CN / zh-TW / en / ja / ko)的 settings.about 都补
  齐 betaChannel* 9 个 key(zh-CN 是 source of truth)。

文档:
- README.md / README.zh.md:把 PR-A 的「opt-in,尚未接入」占位换成
  manual-download 路径的说明 + tag 约定。
- CLAUDE.md:把「Channel distribution (in progress)」整段重写为已接入
  状态,含 tag 约定 / wiring 位置 / 新加的 release verification checklist
  (5 条,发版后一定要走一遍,含 stable/beta 双向 cross-check 与 endpoint
  采样验证)。

cargo check + npm run build 本地都过。本 PR base = chore/branching-workflow
(PR-A),等 PR-A merge 后会自动指向 beta;与 PR-B-1(CI 端)解耦,可独立
review / merge。

* docs(readme): refresh Status / Architecture / Maintainer release checklist

把 README 的产品/发版描述更新到当前真实状态,配合 PR-A / PR-B 系列工作流改造:

Status (v1.2) 章节:
- 把云端 ASR / 本地 ASR / 润色 provider 三类拆开列;本地 ASR 提及内置
  Qwen3-ASR + Windows Foundry Local Whisper 两条线
- 加翻译热键、QA 浮窗、Beta 渠道 opt-in、Homebrew Cask 分发渠道四个要点
- 把「中英双语」改成多语言 UI(实际已支持 zh-CN / zh-TW / en / ja / ko)

Architecture 顶句:
- 由「Auto-updates ride on Tauri updater plugin」改为双渠道描述:Stable
  (v<v>-tauri) 自动推送,Beta (v<v>-beta-tauri) 手动下载

Maintainer release checklist:
- 完全重写为双渠道流程:通用准备(5 处版本号 + 冒烟 + secrets)+
  Beta 流程(在 beta 分支打 v<v>-beta-tauri tag)+ 正式版流程
  (beta→main 后在 main 打 v<v>-tauri tag)
- 把 CI 的 Verify version sync 5-file 校验显式提一次,避免维护者
  漏改 Cargo.lock / package-lock 撞 CI 红灯
- 末尾引用 CLAUDE.md 的 5 步 release verification checklist

Roadmap 章节保持原样(多个项目实际状态我无法在不引入回归的前提下
确认,避免误判)。

* docs: drop reference to non-existent bump-version.sh; describe manual bump

---------

Co-authored-by: baiqing <lbx12309@icloud.com>
2026-05-07 22:00:33 +08:00
TRIPandbaiqing ec9584ea0c feat(release): split updater manifest by channel from tag suffix (#330)
让 release pipeline 根据 tag 名后缀区分 Beta / 正式版渠道,是 opt-in beta
机制的服务端基础。客户端读取的 endpoint 在 PR-B-2 接入。

约定:
- `v<v>-tauri`           = 正式版渠道(stable)
- `v<v>-beta-tauri`      = Beta 渠道(beta)

release-tauri.yml 改动:
- 在 jobs.build 顶层加 OPENLESS_RELEASE_CHANNEL job-env,由
  endsWith(github.ref_name, '-beta-tauri') 决定;workflow_dispatch 与
  非 tag 触发回退为 stable,不改变现有 dispatch 行为。
- Write updater manifest step 把 OPENLESS_RELEASE_CHANNEL 透传给脚本。
- Upload-artifact 的 manifest path 改为 `latest-{tgt}-{arch}*.json` glob,
  让 stable 和 beta 两种文件名(或 mirror 变体)都能被收集,避免
  if-no-files-found 在 beta release 时挂掉。
- Create release 的 prerelease 改为
  `${{ env.OPENLESS_RELEASE_CHANNEL == 'beta' }}`:beta tag 自动标
  GitHub prerelease(UI 折叠 + 默认不算 latest),stable 保持不变。

write-updater-manifest.mjs 改动:
- 读取 OPENLESS_RELEASE_CHANNEL(默认 stable);非 stable / beta 时
  fail-fast,避免拼错 env 静默走错路径。
- beta 渠道时 manifest 文件名加 `-beta` 后缀:
    latest-{tgt}-{arch}-beta.json
    latest-{tgt}-{arch}-beta-mirror.json
  正式版用户的 endpoint 永远指向不带后缀的旧文件名,不会被 beta release 覆盖。

向后兼容:
- 现有 v1.2.23-tauri 等 stable release 行为完全不变(文件名、prerelease=false 沿用旧逻辑)。
- workflow_dispatch 不打 tag 时也照常构建 + 不上传 release。

发版后 checklist(PR-B-2 文档段会写进 CLAUDE.md):
- 推 v<v>-beta-tauri tag → GitHub Release 应标 prerelease 且只含
  latest-*-beta.json
- 推 v<v>-tauri tag → 正式 release 且只含 latest-*.json(不带后缀)

Co-authored-by: baiqing <lbx12309@icloud.com>
2026-05-07 22:00:08 +08:00
TRIPandbaiqing 2fe5f2e0d4 docs: introduce Beta/Stable two-channel branching workflow (#327)
把分支模型从「dev/main」改造为「Beta/正式版」双渠道,渠道语义直接由分支名承载:

- `beta` — Beta 渠道(开发版),默认分支、集成缓冲区,所有 PR 一律打到这里。
  Beta 包不推送给普通用户,只面向主动加入 Beta 渠道的用户。
- `main` — 正式版渠道(Stable),始终可发布。仅由维护者在双端冒烟测试通过后从
  beta 合入;普通用户默认拿到的就是这条线。

文档与 CI 改动:
- README.md / README.zh.md:把「Contributing workflow / 贡献流程」章节
  改写为 Beta/正式版双渠道,含分支流向 ASCII 图、6 条核心规则,
  以及「Beta 不溢出正式版」的隔离要求。
- CLAUDE.md:把 `### Branch & contribution workflow` 改名为
  `### Branch & release-channel workflow`,明确「分支名=渠道名」。
- ci.yml:触发分支从 [main, dev] 改为 [main, beta]。

仓库侧已同步:
- 远端 dev 分支已重命名为 beta(git push origin dev:beta + 删除旧 dev)
- GitHub 仓库默认分支已切到 beta
- release-tauri.yml 用 v*-tauri tag 触发,跟分支无关,发版机制不受影响

Beta 包的 opt-in 分发机制(per-channel updater endpoint + 设置页开关)
将在独立 PR 中接入。在它落地之前,所有 v*-tauri tag 都按正式版对待,
不要从 beta 分支直接打 tag。

Co-authored-by: baiqing <lbx12309@icloud.com>
2026-05-07 21:55:31 +08:00
Chris233 0b8c7b4529 Merge pull request #328 from H-Chris233/fix/issue-314-translation-save-feedback
修复翻译页保存失败无提示
2026-05-07 21:19:31 +08:00
H-Chris233 829fea3c14 Expose translation save failures before users trust stale settings
Translation settings were optimistically updated without awaiting or surfacing write failures, so users could see enabled language and shortcut states that were never persisted. This keeps the fix inside the Translation page: all three save paths now show saving/saved/failed feedback, catch failed writes, and refresh preferences after failed preference persistence to roll back local state.

Constraint: Follow the new beta-first PR workflow from #327.

Rejected: Refactor HotkeySettingsContext queue behavior | issue explicitly excludes queue redesign.

Confidence: high

Scope-risk: narrow

Directive: Keep Translation page save feedback local unless SelectionAsk receives the same treatment in its own issue.

Tested: npm run build

Tested: git diff --check

Related: #314
2026-05-07 20:58:08 +08:00
TRIPandbaiqing 8c0611ff5f fix(homebrew): bump cask to 1.2.23 and drop broken Formula (#326)
- 把 Casks/openless.rb 从 1.2.22 升到 1.2.23 + 对应 SHA256,
  避免新用户首装拿到旧版(依赖 release 后 update-cask.yml 自动维护,
  但合并 PR322 时 cask 已落后一版,先手工补齐)。
- 删除 Formula/openless.rb:作者在 PR322 中已说明 Tauri DMG bundler
  在 Homebrew 沙盒构建里 hdiutil/create-dmg 受限会失败;保留会让
  误用 `brew install openless`(不带 --cask)的用户卡住。

Co-authored-by: baiqing <lbx12309@icloud.com>
2026-05-07 20:40:17 +08:00
kiruno 9543a5a86f feat: Add Homebrew Cask install option (#322)
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.
2026-05-07 20:32:35 +08:00
Hongbro886 32133b3438 关于模型设置-模型下载进度条的若干修复 (#293)
* fix: Various fixes for the model settings - model download progress bar

* fix(local-asr): log partial-size errors and seed redownload progress
2026-05-07 20:21:51 +08:00
Chris233 813d9ec2e9 Merge pull request #324 from H-Chris233/fix/issue-323-llm-providers
增加更多 LLM Provider 预设
2026-05-07 20:19:31 +08:00
Chris233 93dc4b38cd Merge pull request #325 from Cooper-X-Oak/docs/backfill-cooper-developer-entry
docs: backfill developer entry
2026-05-07 20:19:06 +08:00
cooper 188efa7e68 docs: add Cooper to developer list 2026-05-07 19:59:38 +08:00
H-Chris233 336ac9a11c Broaden low-cost LLM provider choices
Issue #323 asks for easier switching to more OpenAI-compatible LLM providers instead of forcing users through a single custom slot. The settings page already stores credentials per active LLM provider id, so the narrow fix is to add practical presets and make provider switching seed the model field only when it is empty.

Constraint: Keep provider storage in the existing system credential vault schema

Rejected: Build named custom profile management | larger UI and persistence surface than needed for the first issue slice

Confidence: medium

Scope-risk: narrow

Directive: New LLM preset ids rely on the generic active LLM credential routing; do not special-case them in backend code unless the provider stops being OpenAI-compatible

Tested: npm run build

Tested: git diff --check

Related: #323
2026-05-07 19:29:51 +08:00
baiqing 5491ef5d33 chore(release): 1.2.23
Hotfix for 1.2.22:
- fix(recorder): macOS 麦克风停录后未释放(cpal Stream::drop 不调
  AudioOutputUnitStop,显式 pause 强制停 callback)
- fix(coord): 录音条等真实开始捕获 PCM 后再弹出,避免短录音漏首字
- fix(localasr): macOS 不再渲染 Windows 专属的 Foundry Local Whisper 卡片
- fix(hotkey): macOS 上 Alt/Meta 键标签显示 Option/Cmd 而非 Alt/Win
2026-05-07 16:57:18 +08:00
baiqing b1a07a4c66 fix(hotkey): macOS 上 Alt/Meta 键标签显示 Option/Cmd 而非 Alt/Win
QA 浮窗(划词追问触发的浮窗)一直在显示 "右Alt" 而不是用户实际按的
"右 Option"。

根因:QaPanel.tsx 用 getHotkeyBindingLabel(prefs.hotkey) → 走
getHotkeyBindingCodes → 把 trigger="rightOption" 通过 legacyTriggerCode
映射成键盘事件 code "AltRight" → getHotkeyCodeLabel("AltRight")
**平台无关**地返回 "右Alt" / "Right Alt"。

而 SelectionAsk 页用 formatComboLabel(prefs.dictationHotkey)(primary
"RightOption" → formatPrimary 走 "rightoption" 分支 → "Right ⌥"),
所以 SelectionAsk 页面是对的,QA 浮窗就显示成了 "Alt"。

同样的平台错配在 MetaLeft / MetaRight:之前一律显示 "Win",macOS
应该是 "Cmd / ⌘";OSLeft / OSRight 同样修复。

修复 getHotkeyCodeLabel:按 currentPlatform().isMac 分流:
- AltLeft  → macOS "左 ⌥" / "Left ⌥",其它 "左Alt" / "Left Alt"
- AltRight → macOS "右 ⌥" / "Right ⌥",其它 "右Alt" / "Right Alt"
- MetaLeft / OSLeft   → macOS "左 ⌘" / "Left ⌘"
- MetaRight / OSRight → macOS "右 ⌘" / "Right ⌘"
- Linux/Windows 路径不变

⌥/⌘ 与 formatPrimary 的输出格式一致,全 app hotkey 标签平台一致。
2026-05-07 16:33:29 +08:00
baiqing 2edaf522cd fix(recorder): 显式 pause cpal Stream 再 drop,释放 macOS 麦克风占用
用户报告:按热键结束录音后麦克风没有被释放(橙色 mic 指示灯不灭、
process_callback 持续打 cb# 日志直到进程退出)。

根因:cpal 0.15 的 Stream::drop 在 macOS coreaudio backend 上不会同步
调 AudioOutputUnitStop,只走 dispose。AudioUnit 的 render callback 仍被
系统调用,process_callback 以 ~5 ms / 帧的速率继续推到 consumer 和
level_handler;macOS 一直认为我们在用 mic,橙点不灭,其它 app 无法独占。

实测日志:
  T=01.786 hotkey 按下 → end_session 启动
  T=02.699 audio-mute released by dictation (rec.stop() 已返回 = 音频
                                              线程已 join 完成 = drop(stream)
                                              已执行)
  T=02.720 cb#750  ← 仍在跑
  T=03.110 cb#800
  …
  T=09.510 cb#2000 ← 直到用户杀进程才停

修复:在 drop(stream) 之前显式 stream.pause()。
StreamTrait::pause 在 cpal coreaudio backend 里直接调 AudioOutputUnitStop,
同步终止 callback;之后 drop 处理 dispose / 资源释放。pause 失败时仅打
warn,不阻塞 drop 路径。

同时在 drop 之后加一行 "cpal Stream dropped (mic released)" 日志,
让以后排查这类问题能直接看到 drop 是否真的执行。
2026-05-07 16:33:12 +08:00
baiqing 43f95a0888 fix(coord): 录音条等真实开始捕获 PCM 后再弹出,避免短录音漏首字
用户报告:说比较短的语音时,开头第一个字偶尔被吞。

根因:start_recorder_for_starting 在 Recorder::start 返回 Ok 后立即 emit
Recording capsule。但 Recorder::start Ok 仅表示 cpal Stream::play 完成,
audio 线程还没开始向 consumer 推 PCM —— macOS CoreAudio AudioUnit 启动到
第一帧 process_callback 中间有 50–200 ms 间隙(Windows 类似)。
用户看到录音条立刻开口,前几个字落在 cpal init 窗口里被吞。

修复:删掉 Recorder::start Ok 之后的立即 Recording emit。
Recording capsule 改由 level_handler 的第一次触发来 emit ——
recorder.rs::process_callback 的执行顺序是 consume_pcm_chunk → level_handler,
所以 level_handler 第一次执行 == PCM 已经真实流到 consumer,从这一刻起
用户说什么都被录到。capsule 自然晚 50–200 ms 出现,但出现 ==
mic 真的在录,匹配「麦先录、UI 再弹」的预期。

短按 / cancel 路径不动:
- stop_recorder_if_pending_start_stop 仍然在 cpal init 期间松键时把 capsule
  切 Transcribing(recorder 已 stop,level_handler 不会再触发)。
- level_handler 内部 phase != {Starting, Listening} 时直接 return,
  不会在 Cancelled / Error 状态上盖回 Recording。
2026-05-07 15:23:38 +08:00
baiqing 95f0b17ff4 fix(localasr): macOS 不再渲染 Windows 专属的 Foundry Local Whisper 卡片
LocalAsr 页面之前无条件渲染 Foundry Local Whisper 区块(标题、模型选择
器、语言 hint、设为默认 / 准备 / 立即释放按钮),macOS 用户进设置 →
模型设置就能看到 Windows 专属的 UI。后端 `foundry_runtime.rs` 早就
按 #[cfg(target_os = "windows")] 把真实实现关在 Win,非 Win 给的是
'only available on Windows' 的 stub —— 前端必须配合,否则一进页面
就发起 status / catalog 拉取并照常渲染整张卡片。

修复方式:用 detectOS() === 'win' 把 Foundry 卡片以及它对应的两个
side effect(refresh() 里的 status/catalog 拉取、prepare-progress
事件订阅)整体 gate 起来。Settings.tsx 的 ASR provider 下拉
(os === 'win' 已过滤 foundry-local-whisper)、allowNonTsfFallback
toggle (capability.adapter === 'windowsLowLevel')、Windows IME 后端
状态行 (windowsIme.state !== 'notWindows') 此前已各自做了 gate,
不需要改动。
2026-05-07 13:27:23 +08:00
baiqing 01aa439686 chore(release): 1.2.22 2026-05-07 13:08:00 +08:00
Chris233 025c23f969 Merge pull request #292 from millionart/codex/windows-local-asr
feat: improve Foundry local ASR setup
2026-05-07 13:00:47 +08:00
millionart e0f7ca2d78 fix: restore frontend Chinese encoding 2026-05-07 12:41:24 +08:00
TRIPandbaiqing 27d42e7303 fix(polish): #305 工作日报场景"清晰结构"无效 + 内置 AI 工具词 (#318)
## 修 #305 polish.rs Structured prompt
- 明确"已结构化 ≠ 不用改":原文是否已有标点 / 编号 / 换行不是判断依据;
  照抄原结构 = 失败
- 重组阈值降到 ≥3 条;即使原文已经是 "1. 2. 3." 也要按主题重新归类成
  双层 (a)(b) 子项,不能扁平照抄
- user_prompt 去掉"它不是问题,也不是任务"这条强 framing —— 旧措辞会
  让 LLM 把书面化输入误判为"已整理好"直接 passthrough(issue #305 截图
  根因)
- 新增 # 示例 3:工作日报场景(已半结构化输入仍要重组)作为回归示例

## 扩充 vocab-presets.json programmer 预设
追加 11 个 AI 工具名:Claude / Codex / Copilot / Cursor / Windsurf /
Anthropic / OpenAI / GPT / ChatGPT / Gemini / DeepSeek。启用 programmer
预设后会同时注入 ASR 热词 bias + polish 提示词的 # 热词 段,覆盖
"cloud → Claude"这类同音误识别。

## 测试
- polish.rs 新增 2 个 #305 回归测试:
  - structured_prompt_forces_regrouping_even_for_already_structured_input
  - user_prompt_no_longer_says_input_is_not_a_task
- cargo test --lib polish: 10/10 passed
- npx tsc --noEmit: clean

Closes #305

Co-authored-by: baiqing <lbx12309@icloud.com>
2026-05-07 12:36:00 +08:00
millionart 70455aa2a1 Merge remote-tracking branch 'upstream/main' into codex/windows-local-asr
# Conflicts:
#	openless-all/app/src-tauri/src/lib.rs
#	openless-all/app/src-tauri/src/types.rs
#	openless-all/app/src/lib/ipc.ts
#	openless-all/app/src/pages/Settings.tsx
2026-05-07 12:23:41 +08:00
millionart 33c253849e fix: address Settings review feedback 2026-05-07 12:19:46 +08:00
Chris233 19f4f64cd5 Restore Intel Mac release coverage (#317)
The release matrix had kept Intel macOS disabled because the old macos-13 pool was deprecated and repeatedly stalled releases. GitHub now exposes an explicit Intel runner label, so the release lane can be restored without returning to the unstable macos-13 runner.

Constraint: Intel Mac release artifacts must be produced separately from Apple Silicon artifacts

Rejected: Re-enable macos-13 | that runner was explicitly disabled due to deprecation and queue instability

Confidence: high

Scope-risk: narrow

Directive: Keep macOS updater artifact names architecture-qualified when multiple darwin lanes are active

Tested: git diff --check

Tested: Parsed release-tauri.yml matrix and verified macOS arm64/x86_64 lanes plus arch-specific updater paths

Not-tested: Full GitHub Actions release run
2026-05-07 12:19:06 +08:00
kaku.ki ec773f08ea feat(settings): add microphone device selection (#306) 2026-05-07 12:15:56 +08:00
millionart 0bb8d3ebcd merge upstream main into windows local asr 2026-05-07 11:48:25 +08:00
millionart a15e6f256e merge main and preserve Foundry selection 2026-05-07 11:44:56 +08:00