Repository navigation
feat(desktop): #1794 基于 Viva 的跨平台工作台迁移(进行中) - #1799
Draft
xiaoyumuxi wants to merge 82 commits into
Draft
xiaoyumuxi wants to merge 82 commits into
xiaoyumuxi wants to merge 82 commits into
Conversation
新目录 desktop/ 是 Viva v0.4.0 的 Go 客户端,业务规则全部调用 Lithe-core-rust 的 C ABI,Go 侧只做 I/O 和绘制。 - internal/core:内核桥接,类型化的最近项目、Git、外框布局(workbench.chromeLayout.reduce)和日志命令 - internal/logstore:统一日志 v2 写入端,编码、去重、查询、保留、收集都由内核计算 - internal/logwindow:一比一复刻 macOS 日志与诊断窗口(工具栏、通道、直方图、记录表、详情与调用链) - internal/workbench:欢迎页、工作台外框、六个工具窗口锚点、按钮拖放插入线、齿轮菜单、设置对话框、只读 Git 工具窗口 - internal/monogrid:把等宽文字放上 Viva 的格子,并按格子宽度断行 - internal/i18n:类型化的 Go 中英文案 - internal/term、localshell、shellkind:从 motty 搬入的终端,尚未接线 - scripts/desktop/:固定内核提交的构建入口和 go 包装脚本 - CI 分类、资源复用清单、docs/ci-builds.md 和 develop-lithe 目录表同步登记 desktop/ Refs #1794
- logwindow:export.go 实现导出状态机(范围、通道、环境信息选项;打开或改选项即暂存,确认后只打包暂存目录),exportsheet.go 按 DiagnosticsExportSheet 绘制面板;工具栏“导出”和详情“导出诊断包…”启用 - 暂存目录在用户缓存目录 Lithe Desktop/diagnostics-export/<id>,重新规划、取消、完成和关窗时删除;失败记录 app.diagnostics.export_failed 并带 stage - core:diagnostics.redactText 与 diagnostics.buildManifest 的类型化调用 - logstore:Collect 按内核解释的导出条件收集记录并按文件分组 - sysinfo:系统名称与版本、CPU 核数、常驻内存、磁盘剩余空间(macOS/Linux/Windows) - i18n:导出面板中英词条 - 尚未收集系统崩溃报告(macOS 在非当前会话范围会附带)
- 终端:每个项目可开多个终端,标签可拖进编辑区加入分组或向边缘分屏、在分组间移动、拖回终端工具窗口;分屏可嵌套,分隔条支持鼠标与键盘调整。分组状态由内核 editor.workbenchState.reduce 计算,Go 侧只保存分屏布局 - termview:从 motty 搬入终端视图(行缓存、按帧预算解析输出、选择、输入、滚动条、光标闪烁),出处见 NOTICE - 标题栏:项目头像、分支按钮、项目菜单(新建/打开/克隆/打开的项目/最近项目) - 设置:独立设置窗口(搜索侧栏、分类树、面包屑、卡片、恢复默认/取消/好),目前只有“通用”页有内容 - 日志:新增 terminal.session.start_failed 事件(固定的内核目录尚未收录) - localshell 测试改为带期限等待 Done(),不再轮询
- 提交工具窗口:变更列表(逐文件勾选暂存/取消暂存、全选、按状态着色、重命名显示 旧 → 新)、可拖动的分隔条、提交信息多行输入(⌘Enter 提交)、修改上一次提交(amend)、提交与提交并推送按钮 - 执行流程由内核 git.workspaceCommitPrepare/Step 计算:需要确认的计划、提交并推送和重试都先弹出审查框,逐仓库列出步骤、分支与暂存文件;推送目标有分歧时让用户选择发布到新分支还是推到上游 - 中途失败保留执行结果,可查看每个仓库的状态并重试剩余步骤;失败按 app.notification.operation_failed 记录 operation 与 error - core:WorkspaceCommitPrepare/Step、GitStage/GitUnstage/GitStageAll 的类型化调用 - i18n:提交窗口与审查框中英词条 - 暂未提供:嵌套仓库发现、变更列表分组、回滚与右键菜单、差异预览、AI 生成提交信息、半选复选框样式
- 分支弹窗:搜索框、新建分支、检出标签或修订;最近、本地、远程、标签四组可折叠,搜索时不显示“最近”;每行显示上游与 ↑/↓ 计数,右侧子菜单提供检出、从此处新建、重命名和删除 - 分支名由内核 git.branchNamePreview 清理与校验,输入时实时替换空格和非法字符,重名、与远程冲突、目录冲突等给出提示 - 检出前由 git.checkoutPreflight 找出会被覆盖的本地改动,弹窗列出文件并提供智能检出(暂存后恢复)与强制检出 - 删除前确认,删除后通知显示原提交;失败按 app.notification.operation_failed 记录 operation 与 error - core:GitCheckoutPreflight/GitCheckout/GitCheckoutRevision/GitCreateBranch/GitRenameBranch/GitDeleteBranch/GitBranchNamePreview 的类型化调用 - i18n:分支弹窗与对话框中英词条
- 删除 rust/(lithe-core 等 crate)、macos/、windows/、frontend/、Plugins/、shared/、third_party/,以及 Package.swift、bun 配置和只服务这些目录的脚本与工作流(ci-macos/windows/plugins/remote、release-*、verify-i18n/logging/platform-feature-matrix/host-language-specifics)和 .github/actions - 内核改由 Lithe-IDEA/Lithe-core-rust 提供:scripts/desktop/build-desktop-core.sh 克隆固定提交并构建静态库;界面库来自 github.com/vivaui/viva v0.4.0 - .gitignore 忽略已删除的顶层目录,避免旧工作树里的构建产物(windows/、frontend/ 的 node_modules 等)变成未跟踪文件 - 应用图标从 macos/Resources/AppIcon.png 移到 desktop/assets/icon.png;Agent Notes 看板改用这个图标,并去掉生成功能矩阵的步骤 - core/errors.go 的注释改指 Lithe-core-rust 中的错误码定义 - 没有改动 .agents/(Skill、Agent Note)、docs/、README、AGENTS.md、CLAUDE.md 和 PR/Issue 模板;其中仍指向已删除路径的内容另行处理
- desktop/Makefile:make run/dev、build、core、test、vet、fmt、fmt-check、check、package、release、clean;所有 Go 命令都经过 scripts/desktop/desktop-go.sh 链接内核。make dev 等同 make run:viva dev 的热重载进程不转发原生文本输入事件 - desktop/viva.toml:应用名 Lithe Desktop、包标识 app.lithe.viva(不与 SwiftUI 客户端的 app.lithe.desktop 冲突)、版本 0.7.0、最低 macOS 13.0 - scripts/desktop/package-desktop.sh:构建 release 内核,用 -X main.version 写入 viva.toml 的版本,再用 viva package 生成 .app、zip 和 dmg;--arch amd64 在 Apple 芯片上交叉构建 x86_64 - build-desktop-core.sh:支持 LITHE_CORE_TARGET 交叉编译,暂存目录按 Rust target 分开;release 构建关闭 build-override 的 strip,否则 macOS 上 proc-macro 动态库被剥离后报 can't find crate;标准输出只输出暂存目录 - desktop-go.sh:按 GOARCH 选择内核 target - 版本只保留 main.version 一个来源:欢迎页和设置窗口改用 Options.Version,删除 workbench 中写死的 0.1.0-dev - Desktop CI:Linux 检查 gofmt、脚本语法和脚本测试;macOS 运行 make check,Draft PR 跳过 - Desktop Release:desktop-v*.*.* 标签或手动触发;校验版本与 viva.toml 一致、发布说明 docs/releases/desktop-v<版本>.md;arm64、amd64 各自打包并检查版本、架构、签名和 dmg;以 prerelease 发布,避免旧客户端的更新器读到它。签名沿用 MACOS_SIGNING_CERTIFICATE / MACOS_SIGNING_PASSWORD / MACOS_SIGNING_IDENTITY,未配置时不签名,配置不完整时失败;暂不公证
- desktop-go.sh、build-desktop-core.sh、package-desktop.sh 改为 bash,按宿主 GOOS/GOARCH 选择内核 target(Windows 用 x86_64-pc-windows-gnu),Windows 路径经 cygpath 转换, CGO_LDFLAGS 把 liblithe_core.a 放在 rustc 报告的系统库之前 - 打包交给 viva package 构建程序(--exec 传入 cgo 环境),viva 工具固定 v0.4.0, 安装到 .artifacts/desktop/tools/;macOS app/zip/dmg、Windows nsis/zip、Linux tar.gz/deb - 版本只有一个来源:desktop/version.go 嵌入 viva.toml,去掉 -X main.version - viva.toml 增加 [windows]、[linux] 元数据 - Desktop CI:shellcheck;Linux vet/test;Windows vet/test(Draft 不跑) - Desktop Release:darwin arm64/amd64、windows amd64、linux amd64/arm64 五个任务, package-release.sh 按平台检查版本、架构、签名和校验和;Windows 签名沿用原有 secrets
- internal/editor/rope:带快照和撤销的 rope 文本缓冲 - internal/editor/textmate:vscode-textmate 9.3.2 算法的 Go 移植,Java、Makefile、CMake、 Groovy 四个样例与 vscode-textmate + vscode-oniguruma 逐 token 一致;每行约 16 µs (同一样例上 vscode-textmate 约 29 µs) - internal/editor/textmate/internal/regexp2:regexp2 v1.12.0 的修改副本,字符集 ASCII 位图、 必含字面量预筛、确定性回溯上限代替超时、无分配的 FindRunesSpans;改动见 NOTICE.md - internal/editor/syntax/grammars:随客户端提供的四个语法及其许可证 - scripts/desktop/generate-textmate-goldens.mjs:用参考引擎重新生成 token 金样
Lithe-core-rust#1(workbench.chromeLayout.reduce)已合入 main,固定版本从 PR 头部提交改为合并提交。
- 新增 C/C++、CSS、dotenv、Go、HTML、INI、JavaScript/JSX、JSON/JSONC、Markdown、Rust、TOML、TypeScript/TSX、XML、YAML 的语法文件,每个上游各附许可证,NOTICE.txt 列出来源与版本。 - CMake 与 Groovy 语法只用作引擎测试样例,移到 textmate/testdata/grammars,并附带许可证与 NOTICE。
- ParseGrammar 按内核校验插件语法的规则读取(plugins/grammar.rs):键名精确匹配,重复键取最后一个,未读的键当作注释;捕获组编号上限与内核一致,flag 接受 true、1 和 "1"。 - 正则翻译支持 Oniguruma 的字符类交集(&&)、子表达式调用和码点写法,无法翻译的写法明确报错。 - 黄金样例覆盖全部内置语言(samples.json 列出样例与 scope),生成脚本同时读取内置语法与测试专用语法。
- 语言注册表按文件名和扩展名找语言;语法在打开对应文件时才解析,外部 include 按需加载。 - 增量高亮在后台分词,按检查点只重算改动之后的行,结果按行缓存并限定内存。 - 主题把 TextMate scope 和语义 token 映射到 Lithe、IDEA、VS Code、GitHub、One 配色(附许可证),支持亮色/暗色、注释斜体和自定义规则。
- 侧栏按钮拖离侧栏后进入脱离状态,幽灵按钮跟随指针并保留按下位置;回到任一侧栏时重新吸附,脱离与吸附边界之间留有缓冲带。 - 脱离状态下按左、底、右三个停靠区(打开的窗格或记住的位置)判定落点:来源停靠区优先,可见的侧栏按钮优先于停靠区,并以高亮框和“移到左侧上方”等标题预览落点。 - 侧栏的分组区改为紧贴底部分组之上,三组的视觉顺序与落点一致。 - 落点判定只依赖几何和指针位置,新增不依赖时钟和动画的单元测试,以及中英文的拖放流程测试。
- 用等宽网格绘制行号、当前行、选区、按语法着色的文本和闪烁光标;制表符按 4 列展开,中日韩等宽字符各占两列,横向和纵向滚动条按内容显示。 - 编辑基于 rope:方向键、Home/End、PageUp/PageDown 移动,⌥ 按词移动,⌘ 到行首/行尾或文档首尾,Shift 扩展选区;单击、双击、三击按字符、词、行选择并支持拖动。 - 回车沿用缩进,在括号之间把右括号放到新行;Tab/Shift-Tab 缩进或反缩进选中的行,退格按缩进单位删除。 - 撤销按词合并连续输入、合并连续删除;⌘Z/⇧⌘Z、⌘A/⌘C/⌘X/⌘V、⌘S 保存;输入法组字通过 Viva 的文本输入接口显示。 - 修改状态与保存时的文本比较,撤销回保存时的内容即为未修改。
- 新增 documents.go:后台读取文件(16 MiB 上限、二进制嗅探),只为打开的文件按语言注册表取语法 - 文件作为 "file:N" 成员进入内核的编辑器分组,与终端标签共用分组、关闭和激活逻辑 - 文档标签页显示完整文件名、未保存圆点与关闭按钮;⌘S 后台写回并保留文件权限 - 关闭标签或项目时保存未保存的文件,保存失败时保留标签并写日志、提示用户 - 键盘、快捷键、滚轮、输入法和指针事件路由到获得焦点的编辑器视图 - 新增中英文案:关闭标签、打开失败、保存失败、非文本文件、文件过大
- 新增 core.ListDirectories,通过 Core 的 workspace.listDirectories 按需列出展开的目录 - Project 工具窗口显示项目文件树:单击打开文件、展开/折叠目录、方向键导航 - 文件名不再用省略号截断:内容宽度按最宽的行测量,横向滚轮或 Shift+滚轮横向滚动,底部显示滚动条
一行文字原来画成一个标签,对应一张纹理。压缩成一行的 JSON 有几十万点宽, 超过 macOS 渲染器 16384 像素的纹理上限,渲染器报 "failed to rebuild text label textures" 后程序退出。 现在每行只画可见列,并按固定网格切成不超过 2048 点宽的块;块的起点对齐网格, 滚动时未变的块文本相同,纹理可以复用。语法着色的列号改为从块起点计。
项目树、编辑器标签页、提交视图和 Git 日志的文件与文件夹行,按名称显示 IntelliJ 风格的彩色文件类型图标,浅色和深色外观各用对应版本。匹配规则逐条 移植自旧 macOS 客户端的 LitheIcons.swift;构建输出目录(target、build、 node_modules 等)显示排除目录图标。 - internal/fileicons:svg/ 是旧客户端 IDEAIcons 的 76 个 SVG 原文件, NOTICE 和 Apache 2.0 许可证注明来源;icons.go 由脚本生成。 - scripts/desktop/generate-desktop-file-icons.sh:先用固定版本的 picosvg 把彩色描边转成同色填充(Viva 图标编译器只保留填充颜色),再用 viva icons 编译;CI 增加该脚本的 zsh -n 语法检查。
编辑器
- 行号裁剪到编辑区内,滚到一半的行号不再画到标签栏上;行号放到等宽格子上
右对齐,9、10、100 的数位在同一列。
- 自动换行:编辑器分组标签栏最右侧加开关(RoleSwitch,读屏可读开/关),
开启后长行按分组宽度折行,所有打开的文件一起切换,只在本次运行内有效。
- 在空格、制表符之后和中文等宽字符前后断行,超过一行宽度的单词在词内断开;
制表符保持整行的制表位。
- 折行的行只在第一行显示行号;上下键、点击和选区高亮都按显示行计算。
- 窗口变宽变窄时只重排比可见列更宽的行;只有可见行会拆成具体的显示行,
缓存最多 512 行。300 KB 的单行折行约 6 ms。
- 开关自动换行时,原来在顶部的行(包括滚出视口的部分)保持在顶部。
- 新增 Lucide 的 wrap-text 图标,中英词条“自动换行 / Soft Wrap”。
Viva
- 升级到 v0.5.1-0.20261108113640-16ca40bd07ab(上游 b357903,含
roundPosition 修复),图标生成脚本和打包脚本同步改成这个版本。
- monogrid 的注释改成新版的等宽排版方式。
应用图标
- 窗口图标(主窗口、设置、日志与诊断)改用 Lithe 图标,取自
desktop/assets/icon.png(assets.Icon,通过 go:embed 嵌入)。
- make build / run / dev 带 dev 构建标签(internal/buildinfo),Dock 图标上显示
“Dev”角标,做法同 motty(SetDockBadge)。make package 和发布构建不带这个标签。
文件图标
- 补齐旧客户端图标目录里还没映射的图标:类型和符号(class、variable)、目录
标记(源码根、资源根、模块、包,由显式标记决定,不按目录名猜)、四种断点状态。
- 生成脚本把文件名里的所有下划线换成连字符,db_set_breakpoint.svg 生成
DbSetBreakpoint;NOTICE 补上新增 SVG 的来源。
日志存储写入时开启目录校验,级别或字段和目录声明不一致的事件会被丢弃。下面这些失败原来都没有写进日志。 - 打开、保存失败改用目录声明的 error 级别和字段:打开失败带 reason(not_text、too_large、not_found、permission_denied、read_failed),保存失败带 document、revision 和 stage=write;去掉目录里没有的 extension。 - 文件树列目录失败改用内核已有的 app.workspace.directory_skipped,每个没有列出的文件夹记一条,根目录记为“.”。原来用的 workspace.tree.list_failed 不在目录里。 - 分支名预览失败时,app.notification.operation_failed 的级别从 warn 改为目录声明的 error,并和其他 Git 操作失败共用 gitOperationFailed。 - 编辑器视图新增 Revision,编辑、撤销和重做都会让它加一,保存失败的日志用它区分同一个文件的多次保存。 - 新增测试:用真实内核开启目录校验,编码这些事件。
恢复共享契约与本地化资源;接入 Core 搜索及增量索引、文件外部变更与受保护保存,并展示插件市场目录。插件安装和完整跨平台验收仍待后续完成。
保留迁移前的能力清单与历史证据,明确区分 Viva 已核对与待盘点的状态,并将桌面客户端纳入矩阵变更检查。恢复发行目录静态检查,继续要求安装包运行时哈希验收。
验证隔离程序包中的工作台打开、编辑、保存和搜索不会改变包内文件;修复大型迁移差异导致稳定性扫描缓冲溢出,并核对 Agent、构建、调试和语言服务能力。
复用 Core 分页、排序和项目搜索的文件监听,支持结果打开、取消和输入法组合;类、符号、操作及完整原版交互仍待接入。
1 task done
前面几次提交把语言服务器从启动到诊断画完,但 Declared 仍只声明 languages, 所以任何声明语言服务器的插件都在安装阶段被 Core 拒绝——代码在跑,功能进不去。 现在声明基础版本,理由是它们真的实现了: - serverProcess 1 的两种启动都支持:包内程序,以及宿主在 PATH 上解析的 裸命令(上一提交补的)。 - languageServers 1 支持:宿主解析 Core 的启动计划、起进程、把打开文档按 版本同步给服务器、接收并呈现它发布的诊断。 仍不声明更高版本,注释里写明三处缺口: - languageServers 3 的 requestMethods / commands / serializedCommands / forwardNotifications / state / remote 还没有转发实现,插件后端无法驱动 自己的服务器。 - 只有诊断有呈现面;补全、悬浮、跳转、重命名、格式化还没有编辑器入口。 - 工具发现只查 PATH,依赖项目工具链或用户覆盖的计划会被拒绝而不是凑合。 验证:gofmt、go vet、pluginhost / pluginservice / plugininstall / pluginbackend / workbench 测试通过、i18n 与资源只读门禁。 Refs #1794 Co-Authored-By: AtomCode (deepseek-v4.1-flash) <noreply@atomgit.com>
诊断原来只有编辑器里的下划线一个出口。状态栏的 LSP 项现在显示问题总数, 没有诊断时保持原来的「语言服务未启动」文本。 - 新增 desktop.status.problems(带 count 参数)与 desktop.status.oneProblem: 一个问题是自己的说法,否则会显示成「1 problems」。 - 两个语言包都接上访问器:只接英文会让中文界面在调用时 panic。 - pluginProblemCount 汇总各严重度计数;计数为 0 时不显示,避免把「没有问题」 写成一条看起来像故障的状态。 验证:gofmt、go vet、i18n / workbench 测试通过、i18n 生成一致性与资源只读门禁。 Refs #1794 Co-Authored-By: AtomCode (deepseek-v4.1-flash) <noreply@atomgit.com>
lsp.request 已经在 core 里包好,但没有任何调用方,语言服务器起来后宿主 无法问它任何问题。补上两层入口: - pluginbackend.Kernel 增加 RequestPluginSemantics;Runner.Request 填上 Core 的会话标识并校验操作名。空操作名在本地拒绝,因为 Core 会回一个 看起来像服务端故障的协议错误。 - pluginservice.RequestLanguageSession 让调用方只需要一个语言会话。 - 请求是异步的:返回的 operationId 就是之后 requestCompleted 事件携带的 那个,调用方要留着它把答案对回来。 验证:gofmt、go vet、pluginbackend / pluginservice 测试通过。 Refs #1794 Co-Authored-By: AtomCode (deepseek-v4.1-flash) <noreply@atomgit.com>
Windows 与 Linux 的最小化、最大化/还原、关闭按钮由 Viva 画在自定义标题栏里。 没有样式时,Viva 按窗口清屏色推字形颜色;Lithe 没设清屏色,Viva 的默认值是深色, 于是字形是白色,浅色标题栏上看不见。 新增 windowcontrols.Style:字形用标题栏文字色,悬停和按下底色用同一颜色的 10% 和 18% 透明度,关闭按钮保留 Viva 的红色;按钮名称取共享 i18n 的 window.minimize/maximize/restore/close(该四条词条加入 desktop 平台)。 工作台、设置窗口和日志窗口都接上这个样式,随外观和语言切换。 功能矩阵 window-controls 的 Windows 状态改为部分实现:命令面板的窗口操作 尚未接入,原生窗口中的按钮行为待在 Windows 与 Linux 验证。
17 of 20 tasks
- editorperf:确定性生成 Go、Java、JSON、Markdown、日志、混合六类文档, 小文件 100 KiB,大文件默认 10 MiB,可用 LITHE_EDITOR_PERF_LARGE_BYTES 配置 - rope、syntax、editorview 三层的 BenchmarkEditor* 基准:绘制、输入、撤销、 光标、翻页、滚动、粘贴、打开、重新加载、重新折行、内存,以及染色的冷热视口、 行内输入、追赶和整篇分词 - desktop/benchmarks/editor-budgets.json:每项预算附理由,只报告不阻塞 - scripts/desktop/perf/editor-bench.sh:run、record(空闲检查后写入 perfhistory 历史)、 compare、report;editor-perf-report.mjs 生成预算报告 - CI 只检查脚本语法、ShellCheck 和报告生成器测试,不跑基准
- 修改标记改用 rope.Equal 比较当前文本与已保存文本:共享节点直接跳过, 不再每次按键把整篇文档复制成字节再比较 - 最宽行只重新扫描受编辑影响的行(widestLine),撤销、重做取快照里记下的宽度, 不再整篇扫描 - 新增 editorview.Prepare/Content:建 rope、量缩进和最宽行都在 worker 上完成, 窗口线程只拿结果;View 不再通过 cfg 持有打开时的原始字节, Reload、ResolveWithDisk、Snapshot 也改收 Content 同一台机器(Apple M4)改动前后对比,count 6: | 基准 | 改动前 | 改动后 | | --- | ---: | ---: | | ViewType/go/10MiB | 678 µs,10 MiB/op | 62.5 µs,8.3 KiB/op | | ViewEnter/go/10MiB | 706 µs,10 MiB/op | 43 µs,6.5 KiB/op | | ViewUndoRedo/go/10MiB | 225 ms | 2.82 ms | | ViewPaste/go/10MiB | 250 ms | 6.7 ms | | ViewOpen/go/10MiB(窗口线程) | 224 ms | 1.19 ms | | ViewPrepareReload/go/10MiB | 225 ms | 9.32 ms | | ViewMemory/go/10MiB(打开并保留) | 228 ms,1.053/B | 12.4 ms,1.053/B | Memory 基准自己持有输入字节,所以测不出 cfg 持有原始字节的问题; 这一项是读代码发现的,在真实打开路径上多保留约一份文件大小的内存。 PrepareReload/json 变慢约 30%(仍在预算内):最宽行扫描从窗口线程移到了这里。 UndoRedo 仍超 1 ms、Open/json/10MiB 和 Memory/json/10MiB 仍超预算,留待后续提交处理。
- 每个文字标签改为行文本的子串,不再逐帧把可见列复制进 display 缓冲再转成字符串; 制表符、控制字符变成标签之间的空白格,非 UTF-8 字节单独画成 U+FFFD - rope 叶子改为不可变 string,Chunks 回调改收 string; rope.LineCopied:行落在一个叶子里时直接返回叶子的子串,不复制; 跨叶子的行复制一次后按 revision 缓存(最多 256 行、单行 64 KiB、合计 1 MiB) - 行号改为从一段预先格式化好的数字窗口里取子串(lineNumbers), 窗口只在可见行号离开它时才重建;行号位数用 decimalDigits 计算,不再 strconv.Itoa - 折行、小地图、选区改用同一个 v.line 读取行,不再各自复制 同一台机器(Apple M4)改动前后对比,count 6: | 基准 | 改动前 | 改动后 | | --- | ---: | ---: | | ViewPaint/go/10MiB | 57 µs,114 次分配,2.72 KiB | 55.3 µs,0 次分配 | | ViewPaint/minimap/10MiB | 74.7 µs,114 次分配 | 73.1 µs,0 次分配 | | ViewPaint/cjk/10MiB | 30.9 µs,115 次分配 | 28.4 µs,0 次分配 | | ViewPaint/mixed/10MiB | 34.7 µs,152 次分配 | 31.8 µs,0 次分配 | | ViewPaint/longline/10MiB | 14.2 ms,59.8 MiB,34 次分配 | 15.2 ms,10 MiB,1 次分配 | | ViewScroll/go/10MiB | 56.9 µs,114 次分配 | 55.1 µs,0 次分配 | | ViewCaretMove/go/10MiB | 45.9 µs,125 次分配 | 43.7 µs,0 次分配 | | ViewRewrap/go/10MiB | 6.81 ms,8425 次分配,1.07 MiB | 6.45 ms,9 次分配,152 B | 报告里 Paint 仍有 5–127 B/op、0 次分配:这是基准为循环新建的 Canvas 第一帧扩容缓冲区, 总量约 50 KB(小地图约 400 KB),不随迭代次数增长;TestRepaintAllocatesNothing 守住稳态为 0。 已知的显示变化:语法下划线、删除线不再画过制表符占的格子。 Paint/longline/10MiB 仍要复制整行(10 MiB),留待下一个提交处理超长行。
超过 64 KiB 的行不再整行复制: - longline.go:每 4 KiB 记一个停靠点(字节列和到该列的格数),按 revision 保存最多 64 行; 编辑后 keepStops 保留被编辑行在编辑点之前的停靠点、前面各行的停靠点, 以及行数没变时后面各行的停靠点,不重算 - 光标格数、点击定位(columnFrom)、选区、Tab 对齐、上下移动的目标列都从最近的停靠点往后数, 不再从行首数起 - 绘制和小地图只取可见列附近的一段子串(part),按 (行, 折行起点, 列范围) 在本 revision 内缓存,最多 256 段 - 折行改为按 rope 的叶子逐段喂给 wrapper(wrapRange),不再先把整行拼出来; countRows 和小地图的折行同样不复制 - rope.Substring:范围落在一个叶子里时直接返回叶子的子串;LineCopied 改用它 - 语法高亮:tokenize 先看行长再取行,超长行不复制;indentLocked 用 Chunks 只读缩进 同一台机器(Apple M4)改动前后对比,count 6,基准为上一个提交: | 基准 | 改动前 | 改动后 | | --- | ---: | ---: | | ViewPaint/longline/100KiB | 143 µs,104 KiB,1 次分配 | 1.22 µs,0 B | | ViewPaint/longline/10MiB | 15.2 ms,10 MiB,1 次分配 | 1.25 µs,0 B | | ViewOpen/json/10MiB | 2.65 ms,60 MiB | 75.8 µs,120 KiB | | ViewMemory/json/10MiB 常驻 | 20.5 MiB(超预算) | 442 KiB | | ViewMemory/json/100KiB 常驻 | 293 KiB | 61.6 KiB | 其他绘制类基准(Paint、Scroll、CaretMove、Type)同时快了 13–28%, 这次运行时机器负载与上次不同,这部分差异不全归功于本提交。 FirstUse/java +30% 是噪声:本提交没有改语法编译,改动前的基线同样是 4.0 ms 左右。 超长行停靠点和逐段绘制由 longline_test.go 对照整行结果验证(升序、降序、跳跃取列, 折行、小地图、编辑后停靠点保留与失效),TestRepaintingALongLineAllocatesNothing 守住 1 MiB 行重绘 0 分配。
TextMate 语法里大量模式以 lookahead、lookbehind 或 (^|\G) 开头, 原来的起点分析看不穿这些形状,只好在一行的每个位置都执行一遍。这次补上四项分析: - prefix.go:模式整体没有首字符集时,再算一遍,把正向 lookahead 的内容当作首字符来源, 例如 (?=;|\)|\]|\.|,) 只在这几个字符前尝试;否定前瞻和 lookbehind 仍然跳过 - prefix.go:交替的每个分支都以同一个锚点开头时,整个交替也算这个锚点; 语法编译器把不能匹配的 \G 写成 (?!),这种分支不参与判断 - runner.go:以 ^ 开头的模式在行中间开始搜索时,直接跳到下一行行首,不再逐个位置试 - required.go:模式外面没有必需字面量时,改用 lookbehind 里的字面量, 例如 (?<=\bconst\b)\s*(\w+) 必须有 "const";lookbehind 读的是搜索起点之前的文本, 所以这类字面量在整段文本里找(anywhere) - runner.go:Debug 开关在扫描和执行循环外读一次 Go、Java、Markdown 样例的解释执行指令数分别减少 29%、19%、41%, 进入执行的次数减少 42%、34%、64%,匹配结果数量与改前完全相同。 同一台机器(Apple M4)改动前后两个测试二进制交替运行,各 6 次,取中位数: | 基准 | 改动前 | 改动后 | 变化 | | --- | ---: | ---: | ---: | | SyntaxFullPass/go/100KiB | 64.8 ms | 54.1 ms | -16.6% | | SyntaxFullPass/java/100KiB | 45.0 ms | 40.9 ms | -9.1% | | SyntaxFullPass/markdown/100KiB | 19.5 ms | 14.9 ms | -23.5% | | SyntaxViewportCold/go/10MiB | 1.27 ms | 1.06 ms | -16.3% | | SyntaxViewportCold/java/10MiB | 842 µs | 769 µs | -8.7% | | SyntaxViewportCold/markdown/10MiB | 624 µs | 470 µs | -24.7% | | SyntaxTypeInLine/go/10MiB | 59.6 µs | 51.2 µs | -14.2% | | SyntaxTypeInLine/java/10MiB | 13.6 µs | 12.2 µs | -10.0% | | SyntaxTypeInLine/markdown/10MiB | 5.48 µs | 4.86 µs | -11.3% | FullPass/go 六次样本区间不重叠(64.0–67.1 ms 对 53.5–55.9 ms)。 TypeInLine 的 100KiB 文档变化在 ±8% 内,go/100KiB +1.2% 落在噪声范围。 FirstUse 耗时不变,首次编译分配多 4%(go 9.0→9.3 MiB,java 19.9→20.7 MiB): 没有首字符集的模式要多分析一遍,是一次性的临时分配。 整篇分词仍是约 530 ns/字节,离 50 ns/字节的预算还差一个数量级; 剩下的时间主要花在回溯执行本身。 lithe_test.go:TestStartShortcutsDoNotChangeMatches 把首字符集、Boyer-Moore 前缀、 锚点和必需字面量全部去掉作为参照,从每个起点比较匹配结果;TestStartAnalyses 确认这些形状 确实拿到了首字符集和锚点。对四项分析分别做了变异(放开否定前瞻、不比对分支锚点、 行首跳过错一位、anywhere 不从头找),测试都能失败。
原来撤销一步要把整篇旧文本放回去,高亮器丢掉所有状态从头分词, 折行布局也整个丢掉,等下一帧重新计算,一次撤销加一帧约 2.3 ms、分配 90 KiB, 超出 1 ms / 64 KiB 的预算。 - rope.go:新增 rope.Diff,找出两个版本之间改动的字节区间。同一文本的两个版本共享 没被编辑过的节点,Diff 从头、从尾各走一遍,跳过共享节点不读,所以只读改动附近的几个叶子; 结果不会切开 UTF-8 字符。Equal 改用同一个 common 实现 - rope.go:walker 的路径改成结构体里的定长数组加深度下标。原来用切片指向局部数组, append 让数组逃逸到堆上,Equal 每次比较都分配;现在 Diff 和 Equal 都不分配 - view.go:restore 用 Diff 得到的区间,像普通编辑一样调用 keepStops、hl.Edit 和 spliceRows, 保留改动之外各行的颜色、长行列位置和折行布局 同一台机器(Apple M4)改动前后两个测试二进制交替运行,取中位数: | 基准 | 改动前 | 改动后 | 变化 | | --- | ---: | ---: | ---: | | ViewUndoRedo/go/100KiB | 2.28 ms,90.5 KiB | 48.7 µs,58 B | -97.9% | | ViewUndoRedo/go/10MiB | 2.25 ms,86.7 KiB | 45.4 µs,1.4 KiB | -98.0% | | ViewPaste/go/100KiB | 5.84 ms | 3.46 ms | -40.8% | | ViewPaste/go/10MiB | 5.80 ms | 3.51 ms | -39.4% | | ViewType/go/10MiB | 46.1 µs,4.8 KiB | 45.7 µs,4.5 KiB | -0.7% | | ViewEnter/go/10MiB | 33.8 µs,3.4 KiB | 33.7 µs,3.1 KiB | -0.1% | UndoRedo 各 6 次、其余各 4 次。UndoRedo 现在在预算内,也不再随文档大小变化。 Paste 场景包含一次撤销,所以一起变快;Type 和 Enter 少的约 300 B 是 Equal 不再分配。 rope_test.go:随机编辑出一串版本,对每一对版本比对 Diff 和逐字节比较的结果; 补上小文本的边界情况;确认相邻版本之间 Diff 不分配。 undo_test.go:撤销和重做每一步之后,每行颜色都要等于整篇重新分词的结果, 折行行号等于重新布局的结果,长行的列位置等于整行重新计算的结果, 并且没受影响的长行保留原来的列位置缓存。等待高亮器都有 5 秒上限。
两处基准测错了对象,报告里留下 15 项并非来自编辑器的超预算结果。 绘制和滚动:benchView 把准备视图的几帧画在自己的一块画布上,计时循环 却从一块新画布开始,首帧为画布扩容的几十 KB 被平摊进每一帧,在 0 B/op 的预算上显示为每帧 1 到 40 字节。窗口每一帧复用同一块画布, 所以 benchView 改为接收调用方的画布,预热帧和计时循环画在同一块上。 之前先在循环画布上画过一帧的 selection、markers 和 longline 一直是 0 B/op,正好说明了原因。 验证:改前每帧字节数随迭代次数下降(minimap 2000 次 198 B、2 万次 19 B、8 万次 4 B,总量约 350 KB 不变),是一次性成本;改后 22 项绘制 和滚动结果在 2000 次与 2 万次下都是 0 B/op、0 allocs/op,耗时不变。 输入染色:TypeInLine 在每种规模下编辑各自文档的中间行,100 KiB 那行 是注释,10 MiB 那行是代码,规模比因此在 0.42x 到 5.93x 之间跳动, 比较的是两行内容而不是文档大小。改为每种规模都编辑小文档中间那一行 (大文档以小文档开头,这一行两边相同)。100 KiB 的结果不变(go 8.6 µs、java 27.8 µs、markdown 6.8 µs),10 MiB 的规模比变为 1.02x 到 1.03x。大文档把将近 10 MiB 文本放在编辑点之后,对“改动之后的 工作随文档增长”的检查反而更严。 预算、场景、文档规模和生成方式都没有改。
把 Viva 的性能要求写进开发规则,并记录编辑器性能基线的设计和第一次测量。 - AGENTS.md:新增“编辑器性能”入口提醒。改动编辑器模块前先读参考页; 改动前后在同一台机器上各跑一次基线,对比写进 PR;超预算只报告不阻塞, 但新引入的要逐项解释;不得上调预算、删除场景或缩小文档;只在空闲机器 上 record。 - develop-lithe SKILL.md 第四节:定义热路径;新增空闲时不得重绘、热路径 不分配也不做与总量成正比的工作、一帧开销只取决于可见范围、没有数据 不得写性能结论四条规则,并指向编辑器参考页;后续条目顺延编号,第五节 对虚拟化规则的引用同步改为第 14 条。 - references/editor-performance.md(新增):编辑器基线的规则真源,包括 适用目录、何时必须运行、九条硬性规则、规模配置、运行与对比命令、读 报告、历史记录和新增基准的写法。新增基准一节写明预热帧必须画在计时 循环用的同一块画布上,以及有规模比预算的基准在两种规模下必须处理 同样的文本。 - references/scripts.md:登记 scripts/desktop/perf/editor-bench.sh 和报告 生成器。 - Agent Note 2026-11-09-viva-editor-performance-baseline:为什么用合成文档、 三层基准、最高标准的预算、只报告不门禁、本地运行;第一次测量发现的 六处缺陷和复核时发现的两处基准错误;正确做法与反例;被否方案;修复后 的数字和分词器的已知状态。 - worktree-resources.json、reuse-worktree-resources 测试和 docs/ci-builds.md: 把 .artifacts/editor-perf/ 登记为不可跨工作树复用的输出,复制入口拒绝它。 - desktop/benchmarks/history/m4-mbp.jsonl:修复前在 Apple M4 参考机上的 第一次 record(a7e52e32e)。
上游的语言服务器同步(79bce218c)让视图通过 OnEdit 报告每次编辑。撤销、 重做和重新加载报告的是整篇替换,即使窗口没有设置 OnEdit,也每次把整篇 文档复制成字符串;每次按键还要从行首数到编辑点的 UTF-16 列,在只有一行 的大文件上与文档大小成正比。 - restore 只报告 rope.Diff 找到的那一段,文本用 Substring 共享叶子内存; 文本没有变化的撤销步骤不报告。 - positionAt 从行首和 CaretUTF16 缓存的光标列中较近的一个开始数,超长行上 按键只数光标和编辑点之间的字节。 - 没有 OnEdit 时,edit、restore 和 replaceFromDisk 都不计算报告; wholeDocumentEdit 只复制一次(原来是 Bytes 再转 string,两次)。 - edit 改为接收字符串,粘贴不再为报告多复制一份。 - 视图基准按窗口的方式配置视图:设置 OnEdit,并像状态栏那样每帧读取 CaretUTF16。基准原来没有设置 OnEdit,所以测不到上面这些开销。 - TestEditCallbackReportsLSPRange 改为断言撤销和重做报告的范围;新增 TestPositionAtCountsFromTheNearerKnownColumn,在含 1 到 4 字节字符的行上 逐个光标位置核对两种数法给出的列相同。 同一台机器上两份二进制交替各运行 6 轮,取中位数(两边的基准都设置了 OnEdit): | 基准 | 改前 | 改后 | 改前内存 | 改后内存 | | --- | --- | --- | --- | --- | | UndoRedo/go/100KiB | 56.0 µs | 48.9 µs | 208.1 KiB | 55 B | | UndoRedo/go/10MiB | 784 µs | 46.4 µs | 20.02 MiB | 1.4 KiB | | Paste/go/100KiB | 3.49 ms | 3.44 ms | 3.39 MiB | 1.17 MiB | | Paste/go/10MiB | 4.41 ms | 3.49 ms | 23.21 MiB | 1.18 MiB | | Type/go/10MiB | 46.1 µs | 46.1 µs | 4.5 KiB | 4.5 KiB | | Enter/go/10MiB | 34.6 µs | 34.7 µs | 3.1 KiB | 3.1 KiB | CaretMove 和 PageMove 在第一轮对比中变化不超过 1%,分配不变。
- references/editor-performance.md 的“新增基准”一节:视图基准必须设置 窗口给视图的回调(例如语言服务器同步用的 OnEdit),并在每一帧读取窗口 每帧都读取的状态(例如状态栏的 CaretUTF16);少设一个回调,视图为它 做的工作就不在测量之内。 - Agent Note:记录变基到上游语言服务器同步(79bce218c)后,撤销把整篇 文档报告给 OnEdit、基准却没有报出来的经过,以及修复后的数字;“正确 做法”里的撤销示例补上只报告改动的一段。
插件契约和 Core 只接受 arm64 和 x86_64 两个架构名(契约 README 的
${arch} 与 platform.arch;Core declarative.rs 的 KNOWN_ARCHITECTURES)。
宿主却把 Go 的 amd64 换成插件市场用的 x64,Core 因此拒绝在 x64 的
Windows 和 Linux 上为任何插件规划后端:语言服务器和构建提供者都启动
不了。arm64 Mac 上名字恰好相同,所以本地没有发现;从 79bce21 起,
Linux CI 的 TestProviderModelTaskAndCancellation 一直以
“The architecture x64 is not supported.” 失败。
- core.PluginArchitecture 成为唯一的换算:amd64 换成 x86_64,其余
原样。原来宿主和三个测试各写了一份,其中两份写成 x64。
- workbench 的语言服务器和构建提供者启动、buildprovider 和 core 的
测试都改为调用它;删除 workbench 里断言 x64 的旧测试。
- 新增 TestPluginArchitectureUsesContractNames,在任何机器上都核对
amd64 和 arm64 的换算,不依赖运行测试的架构。
- 插件市场的平台名(windows-x64、darwin-x64)是另一套约定,Core 的
市场索引就用这些名字,设置窗口里的那两处不动。
This was referenced Nov 9, 2026
- 新增 desktop/internal/treelist:项目树和 Git Log 改动文件共用的折叠树列表, 负责行几何、缩进、展开箭头、悬停、键盘焦点与失焦两种选择色、方向键/Home/End/ 翻页导航、双击展开和 Enter 激活,只声明可见行。项目树改用它绘制。 - Git Log 提交详情的改动文件按文件夹分组并可折叠:文件夹先于文件,文件保持 Git 返回的顺序;单击箭头、双击文件夹或方向键展开收起,切换提交后文件夹重新展开。 分组暂在 Go 中完成,下沉 Core 跟踪 #1814;分支面板迁移到 treelist 跟踪 #1815。 - Project 标题栏新增定位当前文件、刷新、全部展开、全部折叠四个按钮:定位逐级展开 祖先目录后选中、居中并在下一帧聚焦目标行;刷新重读已展开目录,根目录失败时重新 监听;全部展开最多打开 512 个目录,超出时提示;全部折叠保留根目录并把被隐藏的 选择移到所在的顶层目录。 - 抽出 toolIconButton,禁用状态同时写入命中与无障碍树;搜索面板复用它和 projectRelativePath。 - i18n:files.collapseAll、outline.expandAll、native.revealActiveFileInProjectTree 加入 desktop 平台,新增 desktop.project.expandAllIncomplete 中英词条并重新生成。 - 功能矩阵:更新 file-explorer、project-sidebar-header-icons、git-history、 macos-shared-tree-list-control 的证据、说明和验证步骤。
- 编辑器组标签栏放不下时横向滚动:顶部细滚动条显示位置,滚轮和触控板(含纵向滚轮) 在标签栏上左右滚动,所选标签自动滚入视野;右端 ⌄ 按钮列出部分或完全看不见的标签, 每项带图标、名称、未保存标记和关闭按钮,选择后切换并滚入视野,关闭后列表保持打开, Esc 或点击外部关闭。新增 workbench/tabstrip.go。 - 设置 > 编辑器新增“标签页”,参照 IDEA:一行(滚动标签页面板 / 挤压标签页)或多行。 挤压时标签最窄 72 并截断名称;多行按宽度换行,软换行等按钮在第一行右端。设置写入 editorTabRows / editorTabOverflow,未知值回到默认,恢复默认同样复位。 - 终端标签拖到编辑器组时,插入位置和插入竖线按行计算,多行标签栏可跨行放置。 - 新增 desktop/internal/hscroll:横向滚动状态(范围、滚入视野、滚动条滑块、滚轮), 项目树、Git Log 改动文件和编辑器标签栏共用;workbench/sideways.go 统一绘制细滚动条。 - Git Log 提交详情的改动文件列表可横向滚动,长路径不再被截断。 - 删除的文件改用红色(新增 Deleted 色),不再用暗色主题下发灰的次要文字色; Commit 工具窗口同样适用。 - i18n:新增 desktop.editor.hiddenTabs 和 desktop.settings.editorTabs 等七条中英词条并重新生成。 - 测试:tabstrip_test 覆盖滚动、隐藏标签列表、挤压、多行与恢复默认;editorgroups_test 覆盖 跨行插入位置;settingswindow/editor_view_test 覆盖设置页;hscroll、gitlog_files_test 覆盖横向滚动。 - 功能矩阵:更新 editor-multiline-tabs、git-history、file-explorer 的状态、证据和验证步骤。
1 task done
- 终端工具窗口的标签栏与编辑器组共用 drawGroupStrip:放不下时单行横向滚动,顶部细滚动条, 滚轮和触控板左右滚动,⋯ 列出看不见的标签;加号和下拉箭头始终可见,不跟随编辑器的挤压/多行设置。 - 加号旁新增 ⌄ 菜单(workbench/terminal_shells.go):在后台查找已安装的 Shell,同名多份时显示路径 (bash (/bin/bash)、bash (/opt/homebrew/bin/bash)),选一项即以该 Shell 新建终端;分隔线下的 “设置”打开 设置 > 工具 > 终端。Esc、点击外部或打开隐藏标签列表时关闭。 - localshell:非 Windows 新增 InstalledShells,列出 /etc/shells、常用前缀和 PATH 中每个不同的 可执行文件(同一文件经符号链接或硬链接到达只保留第一个位置,csh/tcsh 仍合并);Windows 维持每个 家族一项。新增 DefaultShell 和 Labels(同名才加路径)。 - 设置 > 工具 > 终端(settingswindow/terminal_view.go):选择新终端的默认 Shell,自动时显示实际生效的 登录 Shell,已保存但不存在的路径显示为“未找到”;写入 terminalShell。Controller.OpenTerminal 打开该页 并展开“工具”分组,已打开的窗口改用 requestPage 切页。新建终端时未指定 Shell 就用该设置。 - 横向细滚动条可拖动:hscroll 新增 Grab/DragTo,workbench/sideways.go 统一登记滑块并处理指针, 编辑器标签栏、终端标签栏、项目树和 Git Log 改动文件都可拖动。 - 底部区域默认高度改为主列高度的 42%(未拖动前随窗口变化),停靠拖拽预览同用 bottomFor; 固定 440 会在较矮窗口里挤掉左右工具窗口的内容。 - Git Log 提交详情的分支/标签引用改为换行显示。 - i18n:新增终端 Shell 菜单与终端设置页词条,desktop 平台复用 native.newTerminalWithShell 等已有词条, 重新生成。 - 测试:hscroll 拖动、TestEditorTabStripThumbDrags、gitlog_details_test、localshell 多安装与合并、 Labels、settingswindow 终端页与切页。 - 功能矩阵:terminal-sessions 补充 Viva 实现证据与验证步骤。
- 提交详情标题下的作者行原来是一行,作者名、邮箱和日期放不下时以省略号截断(如 “Yao…”、 “<23722032@bjt…”)。现在拆成哈希、作者、邮箱、日期四段,逐段按绘制字体量宽,用 wrapTabs 分行,每段完整显示;某一段单独就比一行宽(如很长的邮箱)时独占一行,用 ui Wrap 在段内折行。 - 新增 drawLogMeta / metaRows,宽度向上取整到整点,保证按数字放得下的行布局后也放得下; 数组留在 logView 中逐帧复用。 - 测试:TestLogCommitDetailsShowWholeAuthorLine 在最窄的详情面板中检查四段都完整画在面板内、 没有省略号,超长邮箱独占一行且各行拼起来是完整邮箱;把 Wrap 换回 Ellipsis 时该测试失败。 - 功能矩阵:git-history 补充证据与验证步骤。
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
最新进度与接手入口(2026-11-09,真实 Debug 与 Windows 原生边界节点)
持续开发,保持 Draft,不 ready、不自动合并。本节取代旧接手快照;下方历史说明仍保留。
当前提交与明确依赖
7354cb7c4,现有分支feature/1794-viva-workbench-shell。已保留并集成远端e92acfa84、d12cca7c9、7aea0ff17的编辑器/终端标签、Shell 设置、Git Log 等改动,没有覆盖其他工作。b22c2ef80421a555a08d0a87eb9f39693c08a2b1。继续复用原 Rust Core;工具链 pin 编辑与 DAP 状态转换仍在 Core,不重写内核。60aadcaf3已接回工具链发现、Core candidates/resolve、Build 设置草稿及显式批量保存,Build/Run/命令型 Tests 同时使用工具链程序与导出环境。toolchains.editPins与共享 fixture 取代 Go 的 pin schema 合并;取消、外部修改冲突和原子文件发布仍由原生层负责。本节点的具体行为
debug.adapters.executablePlan和startArguments,传真实 program/cwd、插件默认参数及目标绑定,修复空 launch arguments。自动查找跳过目录/非程序候选;明确配置失效时拒绝,不静默回退。xcrun --find查询选中开发工具,不硬编码工具或 Xcode 路径。serverProcess 4 仅有内部路径回归,未扩大宿主能力声明。.state,安装包只读。GetBinaryTypeW判断 Win32/64 程序,拒绝伪 .exe;不再用 Unix 执行位误拒真实程序。退出测试证明实际创建过进程,防止启动失败冒充清理成功。验证与限制
_dyld_start停留超过100秒、尚未进入测试,签名验证有效;去掉Go DWARF、重新临时签名都未解决,不能把标准冷启动记作通过或断言就是同一根因。后续复用已正常启动的同一竞态二进制、在正确包目录运行,工作台全包301通过/8条件跳过;首次直接运行因cwd错误导致的fixture缺失也保留为失败证据。诊断源码已恢复;失败日志、原生采样与有界终止证据保留,未放宽期限、未跳过断言。旧 Core unused/dead-code 与最低 macOS 链接警告保留。日志等价门禁仍由 #1802 跟踪;缺失的 Core 注释自动门禁和旧共享契约全量脚本不记作通过,新改动已有定向检查与真实消费者测试。本节点 GitHub Draft Linux CI、格式与脚本、Notes 和矩阵检查已全部通过:Desktop CI run
42655477550。macOS/Windows runner 按 Draft 策略跳过,不能当作通过。继续工作与恢复
_dyld_start启动停滞并补齐最新全包 race 的验收;继续真实插件设置来源与确认写回、正式插件准入、完整 Run/Debug 配置与工具链 provider,核对设置快照切换/关闭项目的作用域保护。previous-batches/delivery-audit/是旧盘点;146 must-replace、48 pending-owner-decision 不是删功能许可。LS3、SDK、编辑器/Git/生成器等剩余能力与跨平台原生/打包/升级还须逐项验收。~/.codex/worktrees/viva-1799-takeover/Lithe-IDEA,本地分支codex/1799-viva-completion;按大节点继续提交、同步本 PR,保持 Draft。.artifacts/1799-handoff/的旧恢复包保留;本次资料在takeover-2026-11-09/,含最新源码、客户端增量 bundle(基于旧final-snapshots.bundle的f105d32c)、独立 Core bundle、失败/通过日志及计时 HTML/JUnit。当前工作树继续使用,未归档;Windows 专属验证目录已在证据收集后删除,清理报告确认目录不存在、所属进程0;未动其他服务器工作区。本机诊断进程也已终止。本批已验收集成(2026-11-09)
保留远端
db2024230及此前编辑器性能优化,集成以下子任务;工具链和测试/Debug 工作树仍独立,未混入本次提交。plugin.json与唯一<plugin-id>/plugin.json布局;内容根名称必须匹配 Core 校验后的插件 ID。拒绝歧义 manifest、根外条目、路径穿越、符号链接及配额违规。归档摘要和内容摘要的审批边界保持不变,无签名磁盘包仍需要明确审批。官方 Cargo 0.1.0 原始 ZIP 已通过安装、启用、模型加载与真实构建,flat 包兼容回归保留;不代表发布者签名验证已实现。lsp.request不接受的 documentVersion/Extra,接现有 completionContext,并等待真实 ready。自动补全、只读/jar目标、重命名/格式化仍未实现。lsp.applyTextEdits仍是后台全量文本接口,未宣称它已增量化。core.PluginArchitecture,不加入第二套换算;补充真实 Core 对 arm64/x86_64 接受及 amd64/x64/sparc 拒绝的契约回归。本批验证:全量 Go 测试、workbench/plugininstall/pluginpkg/editorview 全包竞态、普通/dev vet、桌面构建、i18n 三项检查、Notes、功能矩阵、资源只读与测试稳定性门禁。真实 clangd 的定义/Hover/补全及官方 Cargo 原包 E2E 单独执行。所有证据为本机 macOS;Windows/Linux 原生端到端仍待验证。
编辑器性能:同机 Apple M4,100 KiB/10 MiB,相关 Paint/Type/UndoRedo/CaretMove/Scroll 基准各 6 次;28/28 在预算内,绘制/滚动 0 B/op、0 allocs/op。对比文件
.artifacts/editor-perf/batch2-before.txt、batch2-after.txt、batch2-after.md,不提交产物;本批没有新超预算项。关联 Issue / Linked issue
PR 类型 / Type
改动说明 / What changes
背景 / Why
将原 macOS SwiftUI 和 Windows Tauri 客户端迁移到共用的 Viva(Go)桌面界面;共享规则继续由独立的 Lithe-core-rust 实现,语言、构建和其他工具能力由插件提供。这个 Draft 已删除旧客户端与仓库内旧 Core,但新客户端尚未实现或验收旧产品的全部功能,不能作为可发布版本。
改动 / Changes
界面与工作台(此前已完成)
languages: 3TextMate 契约,撤回原languages: 2Monarch 语法;更新共享 fixture、i18n、功能矩阵、资源与测试脚本,并记录旧客户端相关决策的迁移状态。SIGCHLD信号栈问题;增加有界 Go 测试计时、Windows Git Bash 路径识别及资源只读检查。desktop/internal/windowcontrols按各自标题栏的文字色着色,按钮名称使用共享 i18n 的window.*词条。三个窗口各有TestWindowControlsFollowTheTitleBar回归测试。插件安装链路(此前已接入)
pluginpkg:ZIP 安全解压。拒绝契约禁止的绝对路径、..段、反斜杠、NUL 与符号链接,并补上跨平台安装所需的 Windows 设备名、尾随点/空格、大小写重复、文件与目录冲突;宿主自定 20000 条目 / 512 MiB 单文件 / 2 GiB 解压总量 / 200 倍膨胀上限(契约未给数值)。解压与摘要校验共用同一已打开句柄,关闭「校验完再按路径打开」的替换窗口;失败清理暂存目录;启动时清扫.staging/.trash残留。plugintrust:批准记录。只保存来源、归档摘要、包内容摘要、权限与已批准程序;市场来源在摘要与程序集都没变时复用批准,磁盘来源每次都问。记录加互斥,避免并发读改写丢更新。plugininstall:两阶段安装。Prepare 解压、校验清单、算内容摘要、取 Core 的安装审查并判定能否复用批准;Commit 才真正写入。解压与校验都响应取消。pluginstate/pluginmanager:启用状态与生命周期。卸载删除该插件的全部已安装版本并清掉对应批准,最后才清启用选择。pluginhost:能力声明、清单校验、包路径逐段解析(拒绝任一级符号链接)、宿主服务注册与派发(机器请求 30 秒期限,用户选择类请求豁免)、启动计划路径校验。pluginbackend:Core 绑定的后端启动、停止与事件泵。宿主请求交给pluginhost.Services应答,其余事件(诊断等)交给调用方;systemCommand启动用宿主工具发现解析裸命令。pluginservice:装配上述各层,并把 Core 的安装审查、语法解码、文档同步适配成内部类型。语言服务与诊断
plugin.json,语法文件经pluginhost.ResolvePackagePath逐段校验后交 Core 解码;行注释、块注释、括号与自动闭合都映射进编辑器语言表。单个语法被拒只让该语言降级为纯文本,不丢整个插件的语言。pluginlsp):文档在版本 1 打开,之后只发增量变更;未打开的文档拒绝变更/保存;Core 解析出的 URI 作为唯一键。plugindiag,在编辑器里按单元格网格画 2px 下划线(滚动与换行时仍贴着字符),状态栏显示问题总数(单数另有措辞)。Declared()从空集改为languages: [1,3]、languageServers: [1]、serverProcess: [1]。市场索引请求改为传真实能力集,条目可用性按实际支持过滤。本轮集成:Problems / Build & Run / Agent(三个工作树压缩为一个提交)
lsp.problems.query,虚拟化显示诊断并按 UTF-16 位置打开文件;诊断按插件隔离,关闭、禁用、崩溃、重启和项目切换时清理。language_server角色、Core root URI 和utf16Column字段;释放插件时使进行中的 Open 失效。buildSystems: [1]、buildProviders: [1,2];Core 检测实例、生成模型/任务/运行计划,插件提供工具知识,宿主执行原生进程并显示有界输出。支持 command/provider 任务、真实 ready、进度、取消及项目关闭清理;没有在 Go 内重写 Maven/Gradle/Cargo 规则。go vet失败项)。本轮验收边界
cargo build通过;此前原始 Release ZIP 布局曾被拒绝;本批已修复并以原包 E2E 替换拒绝回归。Maven 0.1.1 的languageImport与固定 Core 不兼容,未宣称 Maven 全流程通过。编辑器性能基线与优化(本轮新增,11 个提交:
5b24494b4..3031c2ff5)LITHE_EDITOR_PERF_LARGE_BYTES或--large-bytes修改。desktop/benchmarks/editor-budgets.json,限定每次耗时、内存、分配次数、吞吐,以及大文档相对 100 KiB 的倍数。scripts/desktop/perf/editor-bench.sh负责运行、生成报告和record。record在机器不空闲时拒绝记录。超预算只报告,不阻塞,也不是 CI 必跑项。develop-lithe新增参考页references/editor-performance.md;决策原因写进 Agent Notetesting/2026-11-09-viva-editor-performance-baseline.md。79bce218c)后发现一处回退:撤销、重做和重新加载把整篇文档当作一次替换报告给OnEdit,每次复制整篇文本;超长行上每次按键还要从行首数 UTF-16 列。rope.Diff找到的那一段,列号从较近的已知位置开始数。OnEdit,所以没有测出这处回退;现在已补上。同一台 M4 MacBook Pro,大文档 10 MiB:
修复
OnEdit回退前后,两份二进制交替各跑 6 轮,取中位数(两边都设置了OnEdit):超预算项:优化前 110 项中 52 项超出,优化后剩 20 项;两处基准修正去掉了其中 17 项不是编辑器造成的结果,剩下 3 项,都不是本 PR 新引入的:
desktop/benchmarks/history/m4-mbp.jsonl里只有优化前的第一次record(a7e52e32e,记录时工作区有未提交改动)。优化后的那次record按维护者要求停掉了,没有写入历史。发现的既有性能债务。按维护者决定合并在一个 Issue 里跟踪:#1816,每项可以单独修复、单独提 PR:
textmate/tokenizer.go:162:StateStack.push每次压栈都在堆上新分配一个节点。editorview/view.go:widestLine每次编辑都要重新找最宽的行。replaceFromDisk在窗口线程上做 O(n) 的工作。workbench/document_observation.go:187:每次观察文档都用bytes.Equal比较整篇内容。syntax/semantic.go逐行复制文本。(?:\n|$)一类模式算不出首字符,无法剪枝。Git Log 提交详情作者行不截断(
7aea0ff17)Yao…、<23722032@bjt…)。现在四段逐段量宽、用wrapTabs分行,每段完整显示;某一段单独就比一行宽(如很长的邮箱)时独占一行,用ui.Wrap在段内折行。TestLogCommitDetailsShowWholeAuthorLine在最窄的详情面板中检查四段都完整画在面板内、没有省略号,超长邮箱独占一行且各行拼起来是完整邮箱;把Wrap换回Ellipsis时该测试失败。git-history补充证据与验证步骤。终端标签栏横向滚动、按 Shell 新建终端、细滚动条可拖动(
d12cca7c9)drawGroupStrip:单行横向滚动、顶部细滚动条、滚轮/触控板左右滚动、⋯ 列出看不见的标签;加号和下拉箭头始终可见workbench/terminal_shells.go:每次打开时在后台线程查找 Shell,查找期间显示上次的结果(第一次打开时显示查找中的提示);Esc、点击外部、打开隐藏标签列表或按钮不再绘制(工具窗口隐藏、项目关闭)时关闭。localshell):InstalledShells,列出/etc/shells、常用前缀(/bin、/usr/bin、/usr/local/bin、/opt/homebrew/bin、/opt/local/bin)和 PATH 中每个不同的可执行文件。同一文件经符号链接或硬链接到达(如合并后的/usr)只保留第一个位置;csh/tcsh 仍合并。--login -i启动)、Cygwin、Nushell。Labels:名称唯一时只显示名称,同名多份时显示名称 (路径),例如bash (/bin/bash)、bash (/opt/homebrew/bin/bash)。InstalledWSL)暂不列入菜单。pageTerminal(父级「工具」)与settingswindow/terminal_view.go;Controller.OpenTerminal打开该页并展开「工具」分组,已打开的窗口通过requestPage切页,插件页原来的单独切页逻辑并入其中。新建终端时未指定 Shell 就用terminalShell设置。hscroll新增Grab/DragTo,workbench/sideways.go统一登记滑块并处理指针。layoutState.bottomFor);停靠拖拽预览同用bottomFor。hscroll拖动、TestEditorTabStripThumbDrags、gitlog_details_test、localshell多安装与合并、Labels、settingswindow终端页与切页。按维护者要求,终端 ⌄ 菜单本次没有新增 workbench 测试。terminal-sessions改为 Viva 证据、partial/pending,补充验证步骤与 Shell 查找取舍。编辑器标签栏横向滚动与标签页位置设置(
e92acfa84)workbench/tabstrip.go:布局后读取每个标签的位置,算出滚动范围和看不见的标签,变化时再画一帧。editorTabRows/editorTabOverflow,修改立即生效;未知值回到默认,「恢复默认」同样复位。insertionIndex/insertionMark增加纵坐标)。desktop/internal/hscroll:横向滚动状态(范围修正、滚入视野、滑块、滚轮换算),项目树、Git Log 改动文件和编辑器标签栏共用;workbench/sideways.go统一绘制细滚动条。项目树原来的手写横向滚动改用它,行为不变。Deleted,亮色#DB3B4B、暗色#DB5C5C),原来用次要文字色,暗色主题下显得发灰;Commit 工具窗口同样适用。tabstrip_test.go3 项(滚动与隐藏标签列表的选择、关闭、Esc、外部点击;挤压、多行与恢复默认;换行算法),editorgroups_test.go新增跨行插入位置并扩展插入竖线,settingswindow/editor_view_test.go覆盖设置页,hscroll_test.go7 项,gitlog_files_test.go新增横向滚动。editor-multiline-tabs改为 Viva 证据、partial/pending;git-history、file-explorer补充证据与说明。插件后端架构名修复(
db2024230)arm64/x86_64,宿主却把 Go 的amd64换成插件市场用的x64。Core 因此在 x64 的 Windows 和 Linux 上拒绝规划任何插件后端,语言服务器和构建提供者都启动不了。从79bce218c起 Linux CI 的TestProviderModelTaskAndCancellation一直因此失败。core.PluginArchitecture(原来宿主和测试各写一份,其中两份是错的);新增TestPluginArchitectureUsesContractNames,在任何架构的机器上都核对换算。插件市场的平台名(windows-x64等)是另一套约定,保持不变。项目树标题栏按钮与公共折叠树列表(
18748cc8f)desktop/internal/treelist:公共折叠树列表,负责行几何、缩进、展开箭头、悬停、有键盘焦点和失焦两种选择色、方向键/Home/End/翻页导航、双击展开和 Enter 激活,只声明可见行。行的无障碍属性报告Selected、Expandable、Expanded、Level。项目树改用它绘制。treelist:文件夹先于文件,文件保持 Git 返回的顺序;单击箭头、双击文件夹或方向键展开收起,Enter 打开文件差异;切换提交后文件夹重新展开。gitlog.go的groupLogFiles,按字节排序,与项目树的 Core 自然排序不同),下沉 Core 跟踪 [Feature] 将 Viva Git Log 提交改动文件的文件夹分组下沉到 Core #1814。treelist跟踪 [Feature] Viva Git Log 分支面板改用公共树列表 desktop/internal/treelist #1815。operation_rejected。desktop.project.expandAllIncomplete)。toolIconButton:禁用状态同时写入命中与无障碍树(ui.Box.Disabled只调暗绘制)。项目搜索的刷新按钮改用它;Search Everywhere 改用与定位按钮共用的projectRelativePath计算相对路径。app.WatchTree对项目根递归监听(FSEvents / ReadDirectoryChangesW),与项目搜索共用一条流;Linux 按已展开目录用app.WatchDirectory(inotify),上限 128 个。事件经 CoreFilterWorkspaceChanges过滤,再由 CoreListDirectories分批重读受影响的已展开目录。treelist_test.go8 项(几何、索引、最小滚动、居中、首行往返、键盘移动与展开、键盘滚动、双击),filetree_actions_test.go6 项(定位、定位放弃、全部展开与折叠、512 上限、刷新、根目录恢复),gitlog_files_test.go2 项(折叠、分组顺序)。file-explorer、project-sidebar-header-icons、git-history、macos-shared-tree-list-control:后三项改为 Viva 证据,状态partial/pending;尚未实现 IDEA SVG 图标、悬停渐显、标题下拉箭头、范围多选、拖放、行内编辑和插件树。此前的审查与 CI 修复
golang.org/x/text,改为把文件系统折叠导致的EEXIST翻译成重复路径错误)、Serve返回后的会话自动处置(改为文档化调用方责任,避免与Stop双重销毁)。Verify Agent Notes:155 篇笔记里约 735 条指向已删除路径的引用,改成删除线加注「已随 [Feature] Windows/macOS 统一 Viva 工作台与原生编辑器,保留 Rust Core 和插件体系(分阶段重构) #1794 移除」并保留原文,校验器不再把它们当作当前入口。ci-windows.yml。不在本次进度中 / Remaining work
languageServers: 3未声明。requestMethods、commands、serializedCommands、forwardNotifications、state、remote还没有转发实现,插件后端无法驱动自己的服务器。pending。Viva 升级
上游修复 vivaui/viva#187(Issue vivaui/viva#186)。它让 Mono 文本的布局、换行和截断都按等宽格子计算,中文等宽字符占 2 格,并新增
gfx.Canvas.WrapLinesStyle。另一个上游修复 vivaui/viva#188:Windows 上等宽文字走 GDI,GDI 为没有 semibold 字面的 Consolas 合成 600 字重,字比格子宽,日志窗口“级别”列和工具栏的
INFO显示成INFC;修复后中等和半粗的等宽文字交给 Direct2D。Lithe 侧不加绕过代码。本 PR 仍固定在
v0.5.2-0.20261109020342-0c11a3d0950d,等上游合并后再完成以下改动:desktop/go.mod,以及scripts/desktop/下package-desktop.sh、generate-desktop-icons.sh、generate-desktop-file-icons.sh里的VIVA_VERSION,三个脚本与go.mod用同一版本。desktop/internal/monogrid及其测试。Git 日志详情里的提交标题(internal/workbench/gitlog_view.go的subjectLines和logView.subject*缓存字段)改为f.Wrap(subject).Mono().Bold().FontSize(logFontSize),并用LineHeight设为等宽格子高度,保持现在的行距。internal/logwindow/window.go的mono():去掉非 ASCII 文本手动补宽度的分支,删除printableASCII。internal/logwindow/details.go操作区下方的脱敏说明改用f.Wrap(...).Mono(),删除wrapDetailWords及其两个测试,并核对行距与现在一致。wrapDetailRows(按字符折行带颜色的 JSON 片段)和工具栏的monoWidth(计算按钮宽度)。它们是正常功能,不是绕路代码。make -C desktop check,再用无头截图确认三处中文等宽文字不再超出边界:提交面板的分支名(不改代码,升级后自动修复)、Git 日志的提交标题、日志窗口。INFO显示完整。类型专属:feat
多平台对齐
范围检查 / Scope checks
功能矩阵 / Feature matrix
./scripts/platform-feature-matrix/verify-platform-feature-matrix.sh;生成视图未提交。e92acfa84:更新editor-multiline-tabs、git-history、file-explorer;结构检查与60aadcaf3..HEAD变更门禁通过(254 项能力)。d12cca7c9:更新terminal-sessions;结构检查与e92acfa84..HEAD变更门禁通过(254 项能力)。7aea0ff17:更新git-history;结构检查通过(254 项能力)。统一日志系统 / Structured logging
界面文案 / i18n
verify-app-language-localization.mjs、generate-i18n.mjs --check和 i18n 测试通过。18748cc8f:files.collapseAll、outline.expandAll、native.revealActiveFileInProjectTree加入 desktop 平台,新增desktop.project.expandAllIncomplete;变基后中英词条 10,647 条完整。e92acfa84:新增desktop.editor.hiddenTabs及desktop.settings.editorTabs等 7 条设置页词条;变基后中英词条 10,711 条完整。d12cca7c9:新增终端 Shell 菜单与终端设置页词条,desktop 平台复用native.newTerminalWithShell等已有词条;中英词条 10,714 条完整。逻辑归属 / Logic placement
性能与内存 / Performance and memory
设置 / Settings
terminalShell(不对应外部工具配置),回显当前值;自动时显示实际生效的登录 Shell,已保存但不存在的路径显示「未找到」。插件与共享契约 / Plugin and shared contracts
languages: 3与languageServers: 1、serverProcess: 1已声明;声明依据写在pluginhost.Declared的注释里,未实现的能力不声明。lsp.syncDocument/saveDocument/closeDocument/request的 Go 入口(契约已有,客户端此前未包)。io.github.lithe-idea.java-support)仍未装上并跑通;languageServers: 3的插件驱动能力未实现。发行包与资源 / Bundle and resources
.state/<id>/<version>),不写 bundle 或安装目录。无用代码与重构 / Dead code and refactoring
treelist)。验证 / Verification
本批集成在 macOS 上验证,旧分支的结果不冒充本批结果:
make -C desktop fmt-check;普通及-tags dev的vet ./...desktop-go.sh test ./... -count=1 -timeout=600stest -tags dev ./internal/buildinfo;build ... ./cmd/lithe.artifacts/test-stability/integration.json/index.html(本地,不提交产物)git diff --checkscripts/desktop/perf/editor-bench.sh(110 项,macOS M4)go -C desktop test ./internal/editor/... ./internal/editorview/...;desktop-go.sh vet ./...node --test scripts/desktop/perf/editor-perf-report.test.mjs18748cc8f变基到72c2a92da后:desktop-go.sh test ./... -count=1、vet ./...、gofmt -l;treelist、项目树按钮、Git Log 改动文件共 16 项新测试18748cc8f:i18n 生成与用法检查;功能矩阵结构及72c2a92da..HEAD变更门禁e92acfa84变基到60aadcaf3后:desktop-go.sh test ./... -count=1(41 个包)、vet ./...、gofmt -l;标签栏、设置页、hscroll、跨行插入、Git Log 横向滚动共 14 项新增或扩展测试e92acfa84:i18n 生成与用法检查、测试稳定性门禁、功能矩阵结构及60aadcaf3..HEAD变更门禁d12cca7c9:desktop-go.sh test ./... -count=1(41 个包)、vet ./...、gofmt -l;localshell、termview的GOOS=windows与GOOS=linux交叉 vetd12cca7c9:i18n 生成与用法检查、测试稳定性门禁、功能矩阵结构及e92acfa84..HEAD变更门禁7aea0ff17:desktop-go.sh test ./... -count=1(41 个包)、vet ./...、gofmt -l、测试稳定性门禁;新增测试的变异检查(换回Ellipsis时失败)未执行或仍有缺口:终端 ⌄ 菜单、终端标签栏横向滚动、细滚动条拖动、底部 42% 默认高度、Git Log 引用与作者行换行尚未在真实窗口验收;Windows 的 Shell 查找(Git Bash、PowerShell 7 等)与 Linux 的 Shell 列表只做了交叉 vet,未在真机运行,
workbench依赖 cgo 的 Core,无法交叉 vet;编辑器标签栏的滚动、隐藏标签列表、挤压与多行,以及 Git Log 改动文件横向滚动只有无头测试,尚未在真实窗口中用触控板验收;项目树按钮与 Git Log 改动文件折叠只有单元测试,尚未在真实窗口中点按验收;Windows/Linux 原生窗口与完整工作流、真实商业 Agent provider、市场正式语言插件端到端、完整打包发布与升级、插件 SDK 端到端;编辑器基线以外的跨平台性能基线、与 VS Code / Zed 的对照、真实窗口中的帧时间测量,以及优化后的record。迁移分支中已移除的旧日志/Core 契约检查未当作通过;原生平台矩阵保持 pending。固定 Core 构建仍有既有 unused/dead-code 警告及本机 Rust 静态库 macOS 最低版本链接警告,本次未更改 Core 修订或发布兼容性声明。最新 CI 以本 PR 推送后的运行结果为准,PR 保持 Draft。
提交前确认 / Final checks
preview,PR 保持 Draft。.artifacts/、编译产物、日志、截图或经定向扫描发现的凭据及机器专属用户目录。