From 7c38755d6857dbfbc47f3d253a740ee047228e69 Mon Sep 17 00:00:00 2001 From: Haoyu Xi Date: Thu, 22 Oct 2026 19:33:20 +0800 Subject: [PATCH] chore(release): v5.19.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 版本面五件套 + 相关文档: - APP_VERSION / build.gradle fallback / sw.js CACHE_NAME / 顶栏 System · v5.19.0 - README(badge + 亮点 + 下载表 + 版本历史)、CHANGELOG 新增 v5.19.0 条目 - FEATURES / SECURITY / PROJECT_OVERVIEW 当前状态 - 版本守卫测试的字面量同步(51900) 内容:桌面单实例锁 + 端口顺延 + lan-info 真实端口 + 前端 rd-api/rd-syntax/cd-state 解耦。 验证:全量 2584 passed + 2 skipped(578s);ruff 零告警;mypy 三档(119/160/4)零错误; 六道机械闸全 exit 0;index 同步闸 --check 通过。 --- CHANGELOG.md | 25 +++++++++++++++++++++++-- FEATURES.md | 3 ++- README.md | 24 +++++++++++++----------- SECURITY.md | 4 ++-- WORKMEMORY/PROJECT_OVERVIEW.md | 3 ++- android/app/build.gradle | 4 ++-- delector/core/version.py | 2 +- static/index.html | 2 +- static/layout/header.html | 2 +- static/sw.js | 2 +- tests/test_app_version_source.py | 4 ++-- 11 files changed, 50 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ed9ec20..b306c98 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,9 +4,30 @@ > 桌面 / Android 四平台发布资产见 [GitHub Releases](https://github.com/ROM4n2/DeLector/releases); > 开发决策细节见 `docs/plans/archive/` 与 Obsidian Vault `08-Projects/DeLector/01-ADR/`。 -**最新版本:v5.18.0(2026-10-19)** +**最新版本:v5.19.0(2026-10-22)** -### 🏗️ 架构与前端单体彻底解耦 + 交互式智能体闭环 + 六道自动化机械闸(PR #131~#161) +### 🖥️ 桌面单实例锁 + 端口顺延 + 前端继续解耦(PR #172 · #164~#166) + +自 v5.18.0(`4646a67`,2026-10-19)起本版收敛两个主题:**「同一台机器只能有一个 DeLector」成为 OS 级事实**,以及前端单体继续分层。全量测试 2,438 → **2,584 passed + 2 skipped(净增 146)**。 + +**① 桌面单实例(判据从「端口」换成「锁」)** +- **OS 文件锁**:`%LOCALAPPDATA%\DeLector\instance.lock`(POSIX `~/.local/share/DeLector/instance.lock`),同目录 `instance.json` 记 `pid / 版本 / 端口 / 数据目录 / 抢锁时刻`。此前判据是「8000 上有没有东西」——那只说明端口被占,不说明占用者是谁。 +- **锁与元数据分两个文件**:POSIX `flock` 锁的是 **inode**;若对同一文件 `os.replace`,旧 fd 锁着已 unlink 的旧 inode,下一个进程能抢到锁 ⇒ 锁静默失效。故 `instance.lock` 只做锁目标、永不替换。 +- **唯一判定点** `start.claim_instance`:`start.main()`(脚本 / `--server-only`)与桌面壳共用,归因优先级 `unknown > version_mismatch > data_dir_mismatch > same`,杜绝「壳说没有、服务说有两个」。 +- **第二腿**:锁降级时(只读目录 / 无锁原语 / 文件打不开)先对被占候选端口做 `/api/health` 身份探测 —— 否则会为同一个库起第二个服务。真锁在手时一律不探测。 +- 桌面壳退出码 **3** 扩展到六种冲突情形;文案只含人话(版本 / pid / 端口 / 数据目录 / 日志路径),traceback 只进 `launch.log`。 + +**② 端口顺延与真实端口** +- 候选 `8000, 8002–8010`(**8001 是 Go supervisor 保留端口**,显式指定也拒绝);自动模式顺延并留一条含新旧端口的日志,显式 `--port` **不顺延**(已对外承诺的地址不能偷偷换)。 +- `GET /api/wb/lan-info` 改报 `app.state.server_port`(`build_server` 写入的真实端口)。此前写死 8000 —— 顺延后手机会按错端口配对、超时后提示失败,而主机日志一切正常。 + +**③ 前端单体继续解耦(#164~#166)** +- `reader.js` 抽出 `rd-syntax.js`(纯语法层)与 `rd-api.js`(L2 持久化层,14 个端点函数);`cards.js` 的 15 个模块级可变状态收进纯状态容器 `cd-state.js`,视图层顶层 `let` 15 → 0。导出面全程冻结(`reader.js` 40 个具名、`cards.js` 36 个 + 1 条 barrel)。 +- 本批真正的产出是挖出两条**与重构无关的既有静默失效**:`ia_dom_mount_probe.mjs` 有 4 条守卫一直恒真(切片锚点只到函数名);探针静态层已红时仍跑 `node:vm`,空源撞出的 `ReferenceError` 排在真实问题后面。纪律已写进 `docs/agents/architecture.md`「前端模块分层契约」。 + +**回滚**:单实例锁可用 `DELECTOR_DATA_DIR` 指到临时目录隔离验证;如遇异常启动问题,删除 `%LOCALAPPDATA%\DeLector\instance.lock` 无效(锁随进程退出自动释放),应确认是否有残留 `DeLector.exe`。 + +### v5.18.0 · 🏗️ 架构与前端单体彻底解耦 + 交互式智能体闭环 + 六道自动化机械闸(PR #131~#161) 自 v5.17.0(`f359ea6`,2026-10-11)起 **128 个提交、25 个 PR** 汇聚为本里程碑版本。主要涵盖三大维度:**核心业务与架构分层解耦**、**交互式智能体循环与裁判闭环**、以及**六道自动化质量守卫机械闸矩阵**。全量测试规模从 1,768 扩展至 **2,438 passed + 3 skipped(净增 670 个测试)**。 diff --git a/FEATURES.md b/FEATURES.md index ac3f763..4882809 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -8,7 +8,7 @@ --- -## 🌟 核心功能全览(v5.18.0) +## 🌟 核心功能全览(v5.19.0) | 能力域 | 一句话 | | --- | --- | @@ -267,6 +267,7 @@ | v5.6 – v5.7 | 2026-09 | 听力微训(三模式 + 逐字诊断归因)· 长难句精读工坊(7 维难度评分 + CEFR 带估算) | | v5.8 – v5.13 | 2026-09 | 词库单一真相化与富字段回填(ADR-0011~0015)· 遇见区分级短文 i+1 就近选材 + 已读队列 · 全库检索(词条 / 例句 / 搭配 / 语料) | | v5.14 – v5.16 | 2026-10-05 ~ 10-06 | 卡盒去复习化(修掉「白复习」P0)· 前端竞态三修 · TTS 并发闸 · 惰性迁移修复(此前每次 GET 文章都重跑完整 spaCy)· localhost 守卫加固 | +| **v5.19.0** | **2026-10-22** | **桌面单实例锁(OS 文件锁判据 · 锁/元数据分文件 · 降级时的身份探测第二腿)· 端口顺延 8000→8002–8010(8001 留给 Go supervisor)· `lan-info` 上报真实端口 · 前端继续解耦(`rd-syntax` / `rd-api` / `cd-state`)· 2584 passed(净增 146 用例)** | | **v5.18.0** | **2026-10-19** | **单体架构彻底解耦(database/routes 拆解 · index.html/writer.js/reader.js 模块化)· 交互式智能体循环(ADR-0023 / 裁判终审 / AI 润色)· 裁判集扩充与真题回测(ADR-0024)· 六道自动化机械闸矩阵落地 · 2438 passed(净增 670 用例)** | | **v5.17.0** | **2026-10-11** | **首个原生桌面壳(pywebview + 系统托盘 + 统一退出收尸)· 数据落点外置 `%LOCALAPPDATA%\DeLector` · 更新可见性(顶栏 chip + `/api/update/check`)· 发版门守卫(tag == `v`+`APP_VERSION`)· 真启产物闸 / 前端跨边界契约闸 · spaCy 惰性加载(冷启动 3123 → 2128ms)** | diff --git a/README.md b/README.md index ee111ef..cb96e90 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,13 @@ # DeLector · 德语欧标沉浸精读与考点剖析工作台

- Release Version + Release Version Python Version FastAPI spaCy CEFR Ladder AI Model - Pytest + Pytest License

@@ -20,21 +20,22 @@ ## 📦 多平台下载发布包 (Downloads) -> 🚀 **v5.18.0 最新版本亮点(2026-10-19)**: -> - **单体架构彻底分层解耦**:后端核心 `database.py` 拆解为纯 façade 与领域子模块,`routes/main.py` 拆为 6 个领域独立路由;前端 `workbench.html` 模块化,`writer.js`(`wr-format.js` / `wr-api.js`)与 `reader.js`(`rd-syntax.js`)纯逻辑闭包提取并绝对冻结具名导出面。 -> - **零构建 SPA 静态装配**:`static/index.html` 拆解为 `layout/`、`views/`、`modals/` 独立模板组件,由轻量同步机械闸守护,兼顾开发模块化与零打包首屏防闪烁。 -> - **交互式智能体循环与裁判闭环**:接入模型驱动流转、确定性裁判终审、AI 润色与对齐;A1 裁判集扩充至语法层(主谓一致、动词支配格、主句倒装 V2、冠词词形等)并完成 60 局配对真题回测。 -> - **自动化机械闸矩阵**:新增分层契约闸(词法分词器)、反向依赖闸、Mock 漂移闸、禁止静默降级闸等 6 道自动化防线。全量测试扩展至 **2,438 passed + 3 skipped(净增 670 个测试)**,探针 **31/31** 保持零漂移。 +> 🚀 **v5.19.0 最新版本亮点(2026-10-22)**: +> - **桌面单实例锁**:同一台机器只允许一个 DeLector —— 判据是 OS 文件锁(`%LOCALAPPDATA%\DeLector\instance.lock`)而不是「端口上有没有东西」。双击第二次会直接告诉你「已在运行(版本 / 进程 / 端口)」,不再出现两个窗口抢同一个学习数据库。 +> - **端口自动顺延**:8000 被其它程序占用时自动落到 8002–8010(8001 留给 Go supervisor),并在日志里写明换了哪个端口;显式 `--port` 仍按你指定的来,不顺延。 +> - **手机配对拿到真实端口**:`/api/wb/lan-info` 改为上报真实监听端口 —— 顺延后手机端不再按错的 8000 去连。 +> - **前端单体继续解耦**:`reader.js` 抽出 `rd-syntax.js`(纯语法层)与 `rd-api.js`(持久化层),`cards.js` 的 15 个模块级可变状态收进纯状态容器 `cd-state.js`;导出面全程冻结。 +> - 全量测试 **2,584 passed + 2 skipped(净增 146 个测试)**,探针 **31/31** 零漂移,六道机械闸全绿。 > > 📱 **Android 用户注意**:改动含 `static/` 的版本需**覆盖安装**才生效。 > 📜 完整版本变更细节见 [CHANGELOG.md](CHANGELOG.md)。 | 平台 | 版本 | 说明 | 下载通道 | | ------------------ | ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- | -| 🪟 **Windows x64** | `v5.18.0` | 原生桌面窗口 + 系统托盘,免装 Python,解压双击 `DeLector.exe`;**需 Win10+ 与 WebView2 运行时**(Win11 自带;Win10 装不上时的表现见「已知限制」);首次启动把数据放到 `%LOCALAPPDATA%\DeLector` | [下载 ZIP 包 (GitHub Releases)](https://github.com/ROM4n2/DeLector/releases/tag/v5.18.0) | -| 🍎 **macOS** | `v5.18.0` | 解压运行 `start` 脚本,全自动启动服务与默认浏览器 | [下载 TAR.GZ 包 (GitHub Releases)](https://github.com/ROM4n2/DeLector/releases/tag/v5.18.0) | -| 🐧 **Linux x64** | `v5.18.0` | 全发行版通用,解压运行 `start` 即可使用 | [下载 TAR.GZ 包 (GitHub Releases)](https://github.com/ROM4n2/DeLector/releases/tag/v5.18.0) | -| 📱 **Android** | `v5.18.0` | 内嵌 Python 运行时与 spaCy 离线模型,单机独立运行;**支持 arm64-v8a**,CI 钉死签名 keystore 并验签(可覆盖升级)。 | [下载 APK 安装包 (GitHub Releases)](https://github.com/ROM4n2/DeLector/releases/tag/v5.18.0) | +| 🪟 **Windows x64** | `v5.19.0` | 原生桌面窗口 + 系统托盘,免装 Python,解压双击 `DeLector.exe`;**需 Win10+ 与 WebView2 运行时**(Win11 自带;Win10 装不上时的表现见「已知限制」);首次启动把数据放到 `%LOCALAPPDATA%\DeLector` | [下载 ZIP 包 (GitHub Releases)](https://github.com/ROM4n2/DeLector/releases/tag/v5.19.0) | +| 🍎 **macOS** | `v5.19.0` | 解压运行 `start` 脚本,全自动启动服务与默认浏览器 | [下载 TAR.GZ 包 (GitHub Releases)](https://github.com/ROM4n2/DeLector/releases/tag/v5.19.0) | +| 🐧 **Linux x64** | `v5.19.0` | 全发行版通用,解压运行 `start` 即可使用 | [下载 TAR.GZ 包 (GitHub Releases)](https://github.com/ROM4n2/DeLector/releases/tag/v5.19.0) | +| 📱 **Android** | `v5.19.0` | 内嵌 Python 运行时与 spaCy 离线模型,单机独立运行;**支持 arm64-v8a**,CI 钉死签名 keystore 并验签(可覆盖升级)。 | [下载 APK 安装包 (GitHub Releases)](https://github.com/ROM4n2/DeLector/releases/tag/v5.19.0) | --- @@ -165,6 +166,7 @@ DeLector/ | 版本 | 发布日期 | 里程碑概要 | | :--- | :--- | :--- | +| **v5.19.0** | 2026-10-22 | 桌面单实例锁(OS 文件锁判据,双击第二次不再起第二个进程)· 端口自动顺延 8000→8002–8010(8001 留给 supervisor)· `lan-info` 上报真实端口 · 前端 `reader.js`/`cards.js` 继续解耦(`rd-syntax`/`rd-api`/`cd-state`)· 2584 passed | | **v5.18.0** | 2026-10-19 | 单体架构与前端视图全面解耦(database/routes 拆解 · index.html/writer.js/reader.js 模块化)· 交互式智能体循环(ADR-0023 / 裁判终审 / AI 润色)· 裁判集扩充与真题回测(ADR-0024)· 六道自动化机械闸矩阵落地 · 2438 passed(净增 670 用例) | | **v5.17.0** | 2026-10-11 | 首个原生桌面壳(pywebview + 系统托盘 + 统一退出收尸)· 数据落点外置 `%LOCALAPPDATA%\DeLector` · 更新可见性(顶栏 chip + `/api/update/check`)· 发版门守卫(tag == `v`+`APP_VERSION`)· 真启产物闸 / 前端跨边界契约闸 · spaCy 惰性加载 | | **v5.16.0** | 2026-10-06 | 惰性迁移性能缺陷根治(消除单篇 GET spaCy N+1 重算)· CI 必需运行时清单显式化 · localhost 守卫加固 | diff --git a/SECURITY.md b/SECURITY.md index d4d3958..77ace24 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -11,7 +11,7 @@ DeLector 项目高度重视系统的安全性、个人数据隐私与离线优 | 版本 | 是否支持安全更新 | | :--- | :--- | | **v5.18.x** | :white_check_mark: 支持中 | -| < v5.18.0 | :x: 不再维护(请升级至最新版本) | +| < v5.19.0 | :x: 不再维护(请升级至最新版本) | --- @@ -41,7 +41,7 @@ DeLector 项目高度重视系统的安全性、个人数据隐私与离线优 发送详细的安全分析报告至维护者邮箱:`beianderen@gmail.com`。 ### 报告时请包含以下信息: -- 受影响的版本号(如 v5.18.0); +- 受影响的版本号(如 v5.19.0); - 漏洞类型(如 XSS、越权、SSRF、内存破坏等); - 详细的概念验证(PoC)或复现步骤; - 潜在的危害分析与建议的修复方案(若有)。 diff --git a/WORKMEMORY/PROJECT_OVERVIEW.md b/WORKMEMORY/PROJECT_OVERVIEW.md index 33022f3..ddd6586 100644 --- a/WORKMEMORY/PROJECT_OVERVIEW.md +++ b/WORKMEMORY/PROJECT_OVERVIEW.md @@ -23,7 +23,8 @@ ## 当前状态 -- **最新发布 v5.18.0(2026-10-19)** —— **单体架构与前端视图全面解耦**(`database.py` 拆解为领域模块、`routes/main.py` 拆为 6 个领域路由;`workbench.html` 模块化、`index.html` 拆解为 layout/views/modals 并由轻量同步闸守护;`writer.js`/`reader.js` 纯逻辑闭包提取并冻结导出面)**+ 交互式智能体闭环**(ADR-0023 / 确定性裁判终审 / AI 润色与对齐)**+ A1 裁判集扩充与真题配对回测**(ADR-0024 / 60 局真跑标定真 token 与轮次分布)**+ 六道自动化机械闸矩阵落地**(分层契约闸 · 反向依赖闸 · Mock 漂移闸 · 禁止静默降级闸等)。全量测试从 v5.17.0 的 1,768 增长至 **2,438 passed + 3 skipped**(净增 670 条测试),探针 **31/31** 零漂移。 +- **最新发布 v5.19.0(2026-10-22)** —— **桌面单实例锁 + 端口顺延 + 前端继续解耦**。判据从「端口上有没有东西」换成 OS 文件锁(`%LOCALAPPDATA%\DeLector\instance.lock` + `instance.json` 分离,避免 POSIX `os.replace` 让锁静默失效);唯一判定点 `start.claim_instance`,`start.main()` 与桌面壳共用;端口候选 `8000, 8002–8010`(8001 留给 Go supervisor),自动顺延 / 显式 `--port` 不顺延;锁降级时以 `/api/health` 身份探测作第二腿;`/api/wb/lan-info` 报真实端口。桌面壳退出码新增 3 = 端口或实例冲突(六种 `reason` 各有获批文案)。同版含 `reader.js`→`rd-syntax`/`rd-api` 与 `cards.js`→`cd-state` 的前端解耦。全量 **2584 passed + 2 skipped**。详见 `CHANGELOG.md` 与 `docs/agents/architecture.md`「桌面单实例与端口顺延」。 +- **历史发布 v5.18.0(2026-10-19)** —— **单体架构与前端视图全面解耦**(`database.py` 拆解为领域模块、`routes/main.py` 拆为 6 个领域路由;`workbench.html` 模块化、`index.html` 拆解为 layout/views/modals 并由轻量同步闸守护;`writer.js`/`reader.js` 纯逻辑闭包提取并冻结导出面)**+ 交互式智能体闭环**(ADR-0023 / 确定性裁判终审 / AI 润色与对齐)**+ A1 裁判集扩充与真题配对回测**(ADR-0024 / 60 局真跑标定真 token 与轮次分布)**+ 六道自动化机械闸矩阵落地**(分层契约闸 · 反向依赖闸 · Mock 漂移闸 · 禁止静默降级闸等)。全量测试从 v5.17.0 的 1,768 增长至 **2,438 passed + 3 skipped**(净增 670 条测试),探针 **31/31** 零漂移。 - **历史发布 v5.17.0(2026-10-11)** —— **首个原生桌面壳**(`pywebview` 走系统 WebView2 + `pystray` 托盘 + splash + 统一退出收尸;`v5.16.0` 里 `desktop.py` 根本不存在)**+ 首次数据落点外置**(默认 `%LOCALAPPDATA%\DeLector` + 一次性迁移,修掉唯一真会丢东西的摩擦「升级时解压覆盖 = 学习记录全空且零提示」)**+ 更新可见性上桌面端**(chip + `/api/update/check`)**+ 发版门守卫**(tag 必须 == `v`+`APP_VERSION`)**+ 真启产物闸 / 前端跨边界契约闸**(PR #111~#129,111 个提交;完整条目见 `CHANGELOG.md` 含回滚段)。已装用户拿不到那 6 条可感知修复(`static/` 内嵌在产物里),随本版到达。**known-issues 已明文进发行说明**:~2s 端口/身份校验(本版新引入,不当提速卖点)、`launch.log` 已知整行丢失(≈3%,整行非半行)、Android `versionCode` 不可回滚(`51700`)、Win10 需先装 WebView2。 - **上一版 v5.16.0(2026-10-06)** —— **修掉长期潜伏的性能缺陷 + 三处守卫加固**(PR #108/#109/#110)。**每次 GET 文章都重跑完整 spaCy**(Fog 2 根因:判据写死 `"3.4.0"` 而写入端两条路径都写 `"3.5.0"` ⇒ 判据恒真 ⇒ 惰性迁移退化成每次迁移;修法=`PROCESSED_JSON_VERSION` 单一真相源,语义完整保留)。**CI 必需运行时清单显式化**(`rm` 全仓不存在、`bash` 判为平台相关,两者均不进清单)。**localhost 守卫加固**(关掉三个「将来会漏」的洞:字面 `router` 变量名、per-router prefix、闸调用别名;allowlist 20 条逐字未动)。**安全 posture:内网可信**(不加固 LAN 写端点)。Fog 3 的 16 处形式统一经裁决不做(其收益论证已被实测推翻)。 - **测试 / 门禁基线(截至 v5.17.0)**:全量 **1768 passed + 2 skipped**(分半:非 server **1471** + `test_server` **297**);`ruff check .` 零告警;`mypy --follow-imports=skip tests`(**121** files)、`mypy --strict delector tools`(**87** files)、入口面 `--platform win32 --strict`(**4** files:`desktop.py package_windows.py conftest.py start.py`)零错误;`tools/*.mjs` 探针 **29/29** 零漂移;`test_writer_mobile.py`(发版守护)**30 passed**;**六条守卫**:`test_probe_wiring_guard.py`(防漏接线 5)、`test_probe_json_contract.py`(契约冻结 5)、`test_localhost_guard.py`(受保护路由集合 20 条 allowlist 7)、`test_get_endpoints_with_writes.py`(带写 GET 白名单 7)、`test_ci_hardening.py`(CI 必需运行时清单 33)、`test_app_version_source.py`(发版门 tag↔`APP_VERSION` 等 21)。 diff --git a/android/app/build.gradle b/android/app/build.gradle index 32953f5..e866dc6 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -5,8 +5,8 @@ plugins { // 版本号只维护一个源头:git tag。CI 从 tag 推导后通过环境变量注入, // 本地构建无环境变量时用 fallback 默认值。 -def releaseVersionName = System.getenv("DELECTOR_VERSION_NAME") ?: "5.18.0" -def releaseVersionCode = (System.getenv("DELECTOR_VERSION_CODE") ?: "51800").toInteger() +def releaseVersionName = System.getenv("DELECTOR_VERSION_NAME") ?: "5.19.0" +def releaseVersionCode = (System.getenv("DELECTOR_VERSION_CODE") ?: "51900").toInteger() // 钉死的签名 keystore。CI 把它从 secret 解到 $RUNNER_TEMP(永不进工作树), // 本地开发与 fork 没有这个环境变量,签名配置整段不生效、回落到 AGP 自动生成的 diff --git a/delector/core/version.py b/delector/core/version.py index 0092d70..ff67629 100644 --- a/delector/core/version.py +++ b/delector/core/version.py @@ -12,7 +12,7 @@ __all__ = ["APP_VERSION", "version_code"] # 与 android/app/build.gradle:8 的 versionName fallback 同口径:不带 'v' 前缀。 -APP_VERSION: str = "5.18.0" +APP_VERSION: str = "5.19.0" # 每段版本号只有两位空间(minor/patch < 100),故步进 100 / 10000。 _MINOR_STEP = 100 diff --git a/static/index.html b/static/index.html index 76ad612..7c5165a 100644 --- a/static/index.html +++ b/static/index.html @@ -37,7 +37,7 @@ title="点击检查更新" role="button" tabindex="0" - >System · v5.18.0System · v5.19.0