Commit Graph
831 Commits
Author SHA1 Message Date
key 6e2b6025c1 docs(release): register 0.1.13 delivery archive 2026-07-29 12:20:23 +08:00
key cc1865a979 docs(release): register Android 0.1.13 candidate 2026-07-29 12:18:00 +08:00
key af8af2f6dd fix(release): remove completed auth gaps from RC 2026-07-29 12:07:58 +08:00
key 70e5516ff3 fix(release): close fixed-code mobile auth gaps 2026-07-29 11:59:30 +08:00
key 3c92edd23d docs(release): register Android 0.1.12 package 2026-07-29 10:38:06 +08:00
key 6bf365d591 docs(android): adopt login-page legal consent 2026-07-29 10:35:41 +08:00
key b9e0878926 fix(android): share public legal URLs with cloud builds 2026-07-29 10:07:22 +08:00
key 7f3357c7a1 fix(android): use login consent instead of native privacy prompt 2026-07-29 09:59:41 +08:00
key f322f2b21b docs: register enhanced Android operations package 2026-07-29 03:45:16 +08:00
key 71f005c229 fix(android): capture privacy exit states 2026-07-29 03:43:30 +08:00
key 8354e4e9c2 docs: register final August 1 dual-freeze package 2026-07-29 03:40:33 +08:00
key 414af66eed docs: align August 1 dual-commit freeze 2026-07-29 03:39:19 +08:00
key 861fa0ea76 feat(release): package runtime and operations freezes 2026-07-29 03:38:19 +08:00
key 2d5568f94b test(release): verify Android production routes read-only 2026-07-29 03:34:21 +08:00
key 99958f42fc fix(release): protect backend recovery races 2026-07-29 03:30:39 +08:00
key 39476b2244 feat(release): gate backend deploy and rollback 2026-07-29 03:28:10 +08:00
key c3e0789f29 test(android): capture read-only acceptance evidence 2026-07-29 03:22:19 +08:00
key feece9bb74 fix(release): verify frozen backend artifacts 2026-07-29 03:14:26 +08:00
key 771d8552fa docs: record scoped production preflight 2026-07-29 03:10:52 +08:00
key 566f222e82 fix(release): support scoped backend preflight 2026-07-29 03:05:16 +08:00
key ab7d18406f docs: narrow Android production release scope 2026-07-29 03:01:40 +08:00
key 04b35c055f docs: refresh Android 0.1.10 release evidence 2026-07-29 02:53:10 +08:00
key dc20b92061 fix(mobile): recover direct channels after network failure 2026-07-29 02:31:19 +08:00
key 376a7c4b84 docs: record Android 0.1.9 RC evidence 2026-07-29 02:23:06 +08:00
key cb928edafd fix(mobile): handle file picker cancellation 2026-07-29 02:01:45 +08:00
key fd59421574 docs: record Android overlay lifecycle evidence 2026-07-29 01:56:23 +08:00
key 8d291d1483 docs: refresh August 1 RC evidence 2026-07-29 01:52:01 +08:00
key 8764031d4a release: gate August 1 content candidates 2026-07-29 01:36:07 +08:00
key 6a1f672892 docs: record Android 0.1.8 RC evidence 2026-07-29 01:22:57 +08:00
key ba68fc8326 release: harden Android network security 2026-07-29 01:13:18 +08:00
key 9ea5d79a62 release: prepare August 1 Android RC 2026-07-29 00:35:15 +08:00
key 9ae5f750c8 fix: align Windows dev, App compiler, and ASR 2026-07-26 21:27:37 +08:00
admin f57e0a53c6 feat(mobile): expand TTS voices and align App SDK 2026-07-26 17:05:43 +08:00
admin 94ee29f59c fix(speech): write native TTS temp file as binary and clean it up
App-Plus 的 plus.io FileWriter 只接受字符串:write 写文本,writeAsBinary 收
base64。原先传 Blob 会被原生桥接序列化成空内容,落地 0 字节且照样回调
onwriteend,InnerAudioContext 静默播完、不报错,表现为"界面正常但没有声音"。
改用 writeAsBinary 并在 onwriteend 里复核 size > 0,让写盘失败能被暴露。

清理侧同一处存在文件泄漏:播放要 convertLocalFileSystemURL 转出的 file://
绝对路径,而 resolveLocalFileSystemURL 删除只认 `_doc/xxx.mp3` 相对路径。
原先只回传前者,拿它去 resolve 解析不到,remove() 从不执行,且 catch 静默,
临时 mp3 逐句堆积。改为返回 { playbackUrl, plusPath } 两个路径,清理失败加告警。

真机验证(Android 10 / io.dcloud.HBuilder):落盘 80251 字节,ID3+LAME 头,
MPEG layer III 160 kbps 24 kHz 单声道,播完文件自动删除。

顺带把测试里 MP3 头字面量的真实 NUL 字节改为 \x00 转义(运行时字节不变),
此前 git 将该测试文件判为二进制,diff 无法审阅。
2026-07-26 12:10:50 +08:00
adminandClaude Opus 5 3f7f0496f7 docs(changelog): record the App voice-first restore and its tradeoffs
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 02:39:40 +08:00
adminandClaude Opus 5 d84ad87cb6 fix(sop): restore voice-first replies on App without withholding text
73712994 disabled voice-first on native by gating the TTS preload behind
!isNativeAppRuntime(), which left App users with the degraded text bubble
plus a 播报 button. The voice-line, 转文字 toggle and 收起全文 markup were
still present but unreachable.

Re-enable the preload on every platform and open the transcript when the
message is created, so the answer is readable while synthesis runs.

Collapse the transcript when playback starts rather than when synthesis
finishes: on-device synthesis settles in 2-6s, so collapsing on ready
pulled the answer away mid-sentence. transcriptPinned records a manual
toggle so the automatic collapse never overrides the reader.

Bound the preparing bubble at 20s (the upstream DashScope ceiling) so a
stalled synthesis degrades to the plain text bubble instead of showing an
endless placeholder duration.

Replace the tautological assertion that pinned the previous behaviour by
matching source strings with assertions on the behaviour itself.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 02:36:14 +08:00
adminandClaude Opus 5 7096545e82 fix(mobile): translate microphone errors and pre-request permission
实时陪练失败时,getUserMedia 抛出的 Chromium 英文原文会直接透给用户(真机实测见过
"Could not start audio source"),既不可读也不含任何可执行指引。新增
utils/microphone.ts 把权限、设备占用、无设备、非安全上下文四类底层错误翻译成中文
引导;业务层自己抛的中文文案原样透出,未识别的错误回落到原有通用提示。

同时在建会话之前主动申请 RECORD_AUDIO,并在 manifest 显式声明该权限。

需要说明:此权限预申请是防御性的。真机核查 RECORD_AUDIO 已授予、APK 本就声明该权限、
实时链路可正常跑通,先前那次 "Could not start audio source" 是麦克风被其他应用占用
的瞬时故障,不是权限缺陷。未在"权限未授予"的设备上实测过 WebView 是否会自行弹出
Android 运行时授权框,故此调用在已授权设备上为无害空转;若确实不弹,则它是唯一授权入口。
manifest 声明同样只为防未来模块调整导致权限丢失。

新增 6 项单测覆盖错误映射与授权分支(共 168 项通过)。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 00:58:40 +08:00
adminandClaude Opus 5 788a2abbe4 fix(mobile): avoid status bar overlap on custom-nav pages
全局 navigationStyle 为 custom,页面需自行避让状态栏,但四处顶部内容仍被状态栏
压住:练习页标题与对话页标题、我的页顶部卡片、问答页头部。

避让不能走 CSS:env(safe-area-inset-top) 在 Android WebView 恒为 0(该值本是
iOS 刘海概念,Chromium 仅在配置 display-cutout 时才上报),uni-app 注入的
--status-bar-height 实测在 App 端同样取不到,两者都会静默回落成 0,造成"构建产物
里改动存在但运行时无效"。改由 utils/safe-area.ts 读
uni.getSystemInfoSync().statusBarHeight,各页面以内联样式绑定 padding-top。

profile 页同时把 min-height 从 100vh 改为 100%:叠加状态栏内边距后 100vh 会
溢出一屏高度产生多余滚动。

真机(vivo V2443A,720x1600,状态栏 72px)像素验证:修复前状态栏下缘 60-80px 带内
有 872 个文字像素,修复后四处均为 0。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 00:58:18 +08:00
adminandClaude Opus 5 29bb10e1fa docs(changelog): record the App-Plus batch and the build:app false green
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 00:03:06 +08:00
adminandClaude Opus 5 4fc0c1f5f8 chore(mobile): bump App version to 0.1.5 (versionCode 105)
Covers the App-Plus batch in this series: renderjs realtime practice, request
timeout abort, App-Plus date/query API replacements, and on-demand native
voice. Native permissions and plugins are unchanged, so this ships as a normal
cloud rebuild.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-25 23:59:05 +08:00
adminandClaude Opus 5 c9f5271dd9 docs(org): record the incremental employee sync contract
Document the `/api/aihr/org/sync-changes` change feed shipped in 30ef6a8f:
`employee.id` is the stable subject key, the dry-run-then-apply order, and the
fail-closed rules that full `/sync` keeps for masked phone numbers and
duplicate memberships. Adds the endpoint row and a curl example alongside the
existing full-sync entry.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-25 23:58:45 +08:00
adminandClaude Opus 5 7b014765d6 fix(agent): answer follow-up questions instead of asking to clarify
The planner falls back to CLARIFY whenever no keyword matches and the model
plan is unavailable or malformed. Mid-conversation that produced a dead end:
a follow-up such as "如果我要报销,一般需要查哪几个文件?" was answered with a
clarification request even though the previous turn had established context.

When a non-media request carries a conversationId and a contextVersion above
zero (i.e. at least one turn has completed), route CLARIFY to KNOWLEDGE_QA
with a grounded knowledge search.

Tradeoff: this also suppresses the deliberate CLARIFY for explicitly vague
phrasing ("你看着办", "帮我处理一下") from the second turn onward, which will
now run a knowledge search instead of asking back. Blank input is still
rejected earlier by requireQuestion.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-25 23:58:30 +08:00
adminandClaude Opus 5 73712994c6 fix(mobile): stop preloading answer TTS on native App
On native App the eager TTS request delayed the answer bubble: the message was
created in `preparing` state, so the text stayed behind a voice line that was
still waiting on a round trip.

Skip the preload when `isNativeAppRuntime()`, marking the voice `unavailable`
so the text and citations render immediately. The existing `unavailable`
branch already exposes a play button that calls `toggleAnswerSpeech`, so voice
stays reachable on demand instead of being dropped. H5 keeps preloading.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-25 23:58:19 +08:00
adminandClaude Opus 5 5cf7ce5847 feat(practice): run realtime practice on App-Plus through renderjs
App-Plus has no WebRTC or getUserMedia in the logic layer, so realtime
practice was H5-only and the native entry had to advertise a record-then-
transcribe downgrade.

Move the media/WebRTC engine into `realtime-browser-engine.js` and drive it
from `RealtimePracticeAppBridge.vue`, whose renderjs script runs inside the
system WebView where those APIs do exist. The logic layer keeps the
authenticated calls: SDP exchange and `search_knowledge` tool invocation stay
server-proxied, so the access token is never handed to the view layer. Both
sides talk over the renderjs bridge only in session payloads the server
already assembled.

Verified against a real App build (`app-renderjs.js` holds RTCPeerConnection
and getUserMedia; `app-service.js` holds the SDP endpoint, renderjs side has
zero hits). Microphone permission, live transcription, remote playback,
foreground/background switching and disconnect fallback still require Android
and iOS device verification.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-25 23:58:10 +08:00
adminandClaude Opus 5 3055d2bec9 fix(mobile): replace App-Plus unsupported date and query APIs
`URLSearchParams` is absent from the App-Plus JS core, and
`toLocaleDateString('sv-SE', { timeZone: 'Asia/Shanghai' })` depends on full
ICU data that the App runtime does not ship, so the work-result pages built
either a broken query string or the device-local date.

Build query strings with `encodeURIComponent`, and centralise the business day
in `currentShanghaiDate()`, which shifts the epoch by a fixed UTC+8 offset
before slicing the ISO date. Asia/Shanghai has no DST, so the fixed offset is
exact rather than an approximation.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-25 23:57:06 +08:00
adminandClaude Opus 5 27f4cdac70 fix(mobile): abort uni.request when the platform timeout does not fire
Some uni-app platforms ignore the `timeout` option, leaving the returned
promise pending forever and hanging the calling page with no error path.

Drive the deadline locally: keep a single-shot `finish` guard so success,
failure and timeout can only settle once, and on timeout call `task.abort()`
before rejecting so the in-flight request is released instead of leaking.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-25 23:56:56 +08:00
adminandClaude Opus 5 a3a5cf944e build(mobile): declare App platform compiler to stop build:app false green
`@dcloudio/uni-app-plus` was never declared, so `uni build -p app` silently
fell back to an H5 shell: exit code 0, `DONE Build complete.`, but the output
was only `index.html` (still carrying the `/h5/assets/...` base path) with no
`app-service.js`, `app-renderjs.js` or `manifest.json`. Because
`docs/MOBILE_APP_PACKAGING.md` lists that command as a local verification
step, App platform code was reported as built without ever reaching the App
compiler.

Declare the compiler at the same version as the other `@dcloudio` packages,
guard the version alignment in `tests/app-packaging.test.mjs`, and document
that success is judged by the emitted artifacts, not by the DONE line.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-25 23:56:47 +08:00
admin ab3af277c1 fix(speech): convert base64 TTS data URI before playback per platform
后端 TTS 以 data: URI 返回 base64 mp3(生产实证为合法 LAME mp3),但
App-Plus 的 InnerAudioContext 不支持 data: URI,iOS Safari/微信 webview
也常静默失败,统一报"语音播放失败"。播放前按平台转换:H5 转 Blob URL,
App 端经 plus.io 落 _doc/ 临时文件后播放 file:// 路径,播完清理;Blob 不可
用时退回原始 data: URI。竞态守卫与缓存语义保持不变,158 单测全绿。
2026-07-25 20:37:30 +08:00
admin c2358686ce fix(agent): tolerate Jackson int-range decode in Redis draft/session reads
全局 Redisson codec 用 DefaultTyping.NON_FINAL,final 的 Long/record 不写类名:
数字草稿 id 读回 Integer、realtime 会话 record 读回 LinkedHashMap,confirm 与
工具调用路径双双 ClassCastException(生产 19:35 日志实证)。改为 Number/String
防御转换与 ObjectMapper.convertValue 显式还原,补 3 个回归测试,模块 693 全绿。
2026-07-25 19:48:17 +08:00
admin bb8b2dde7e fix(exam): replace unfounded 4-char title rule with explicit validation messages
- 考试名称仅要求非空,移除无依据的至少 4 字限制;保留及格分 1-100、
  至少一题、总分 100、题干/选项/答案完整、至少一名员工的发布校验
- 发布坞展示具体校验失败原因,不再静默禁用按钮
- CHANGELOG/README 同步 2026-07-25 组织姓名定向补齐与生产复核记录
2026-07-25 18:15:32 +08:00