Skip to content

Epic(0.7.0): 基于 Viva 框架的跨平台方案的迁移(#1794) - #1799

Merged
1lck merged 631 commits into
previewfrom
feature/1794-viva-workbench-shell
Nov 12, 2026
Merged

1lck merged 631 commits into
previewfrom
feature/1794-viva-workbench-shell

Conversation

@xiaoyumuxi

@xiaoyumuxi xiaoyumuxi commented Nov 7, 2026 •

Copy link
Copy Markdown
Collaborator

关联

当前状态

开发进行中,保持 Draft。其他开发已冻结,本 PR 单独推进到可替换旧客户端为止;旧 SwiftUI / Tauri 客户端和仓库内旧 Core 已在本分支删除。

已有(无头测试覆盖,原生窗口验收待做):

  • 外壳:欢迎页、工作台、可拖放工具窗口、多终端、设置窗口、日志与诊断窗口、新建项目窗口、i18n、统一日志写入。
  • 编辑器:Viva 原生编辑、TextMate 高亮、撤销重做与光标撤销/重做(Ctrl/Cmd+Z 优先恢复光标)、折行、小地图、标签栏;文档同步、定义跳转、Hover、自动补全(触发字符取自语言服务器)、查找引用、重命名、格式化与选区格式化(带编辑器缩进)、Problems;Git 行号区变更标记(预览/单处暂存/在 Diff 回退)与行尾 inline blame;Markdown 双栏编辑器(源码|渲染页,三态切换、双向同步滚动、目录弹窗,第二十三轮)、链接跟随(系统浏览器/编辑器/锚点)与相对/远程图片。
  • 本地历史:快照、与上一条/当前比较、设置(忽略规则实时检查、容量上限、清空,第二十二轮)。
  • 插件:市场、安装/启用/卸载、信任审批、settings2 动态设置页、工具链设置;后端反向调用宿主(workspace、functions、languageServer、run、documents/editor/window/browser/terminal、内容提供者);项目生成器;凭据存储(系统钥匙串;旧版凭据只经设置齿轮菜单中用户触发的一次性导入复制,不改、不删旧项);Java 插件准入的宿主能力已全部声明。
  • 执行:Build/Run/Test、输出链接、stdio Debug(真实 LLDB)、tcpLanguageServer 调试与远程 attach;调试线程列表与切换、当前帧求值与监视(监视跨停止保留并自动重求值)、普通单步与反汇编指令级单步、只读内存。
  • Git:状态、暂存、提交并推送、分支操作、历史与差异、Fetch All / Fetch Options(回显仓库配置)/ Update Branch / Show Changes、工作树页与控制台页,同步进度与取消;认证失败用 Core 错误码判断;Diff 编辑区标签页(并排为左右两个带语法高亮的只读编辑器,原版行号在中缝、改动用色带相连、块级勾选与回退在中缝、折叠行带图标与横线、两侧同步滚动;统一视图双行号;差异跳转、折叠未更改、文件切换);Commit 工具窗口暂存页(stash 查看/应用/弹出/删除/新建)与搁置页(Shelf 搁置/恢复/删除,暂存区与工作区分层查看);Log 页比较;提交选项(Sign-off、指定作者);控制台记录除自动刷新外的全部 Git 命令(含内部查询与被拒绝的请求),Commit 窗口、Diff 标签页、分支弹窗的写操作自动切到控制台页签。
  • 项目树:右键菜单(打开、Show Git Diff、Stage/Unstage、新建文件/目录、重命名、删除、复制路径、在 Finder/资源管理器中显示、刷新)。
  • IDE API:设置 › AI › IDE 连接页(按项目开关、配置/执行授权默认关、复制 stdio 配置);broker open/poll/claim/validate/respond/close 已实现;连接发布已实现的 11 个工具(project inspect;build inspect/reload/configure/execute;operations list/output/stop;run list/start/restart),Build 执行复用窗口的 runBuildTask 并从受理起占住窗口,执行输出由 Core output_page 按游标分页(第二十轮)。environment 与 Maven 专属工具按契约不在本客户端发布。
  • AI:Commit 面板生成提交信息、编辑器 AI 行内编辑(Cmd/Ctrl+K)、创建 PR 的 AI 描述,provider 从本机 Codex/Claude 配置经 Core 解析;设置 › AI › 生成(来源、输出语言、自定义指令)。Agent 对话已于 2026-11-12 按用户决定删除(见第十轮)。
  • Page 迁移:设置窗口、日志窗口、新建项目、欢迎页、弹窗与搜索、Git Log / Commit / 分支 / 工作树 / 控制台、Run / Tests / Debug 已改为 Viva Page,嵌入 Page 的输入路由统一在 workbench/pagehost.go。
  • 打包:lithe-mcp 辅助程序由 Core 检出构建后以 lithe_bundled_helper 标签嵌入客户端二进制,运行时原子安装到应用数据目录;安装包不新增可执行文件、不被运行时写入。
  • 字体:设置 › 外观 › 字体,“各位置效果”总览逐位置(编辑器、终端、运行输出)预览并带勾选框,可多选;下方卡片调整所勾选位置的字体、大小、行间距(自动显示实际值)与连字,点卡片右下角“保存”才生效、“还原”放弃,设置相同的位置自动合并(第二十四轮);Git 控制台跟随运行输出字体。macOS 发行包把 Inter、JetBrains Mono 与 JetBrainsMono Nerd Font Mono 编进可执行文件,按进程注册,不读写 bundle(第十六轮)。
  • IDE API 工具发布:open 的 toolExposure 与 validate 使用同一份 11 工具列表;未发布的工具返回 NOT_SUPPORTED。执行状态、错误码、ID 过期规则与输出游标按契约(第二十轮)。

验证:最近一次(2026-11-12,第二十四轮,Core d797244)macOS 本机 desktop-go.sh vet ./internal/... ./cmd/... 与全量 desktop-go.sh test ./internal/... ./cmd/... -count=1(51 包)通过;i18n 三项、功能矩阵 255 项、Agent Notes、运行时 bundle 只读、测试稳定性检查通过;--no-sign 打包实测成功。Linux Draft CI。Windows 在 Lithe-dev 上按阶段收尾时全量复验。最近验证(2026-11-10,Core de7a79ec):全量 desktop-go.sh test -count=1 -p 4 ./... 47 包通过;调试线程/求值监视、单步/指令级单步/只读内存、启动前保存、语义高亮开关、LSP 日志筛选/停止/重启、光标历史、Markdown 链接的端到端测试通过(cb963389a、06f27375d、bb8a32102、94476f3d7、190c8252e、027a093eb)。

交接(2026-11-11 夜,HEAD 见分支最新提交)

阶段:第十轮已删除 Agent 对话;第九轮按旧客户端补齐的右键菜单已提交(盘点见第九轮小节)。历史改写 UI 已在第八轮末提交。之后依次:真缺口(IDE 设置导入、SVN/插件 VCS provider、滚动条两项;HTML/SVG/媒体/PDF 预览暂缓(依赖 webview))→ 测试(workbench 的 31 个 Agent 失败用例随 Agent 对话删除,#1827 关闭;Windows 13 个)→ 矩阵 → GUI 验收。

本机工作树(Mac):

  • /Users/yaoyao/Dev/OpenRes/Lithe-IDEA:主工作树,直接在 feature/1794-viva-workbench-shell 上提交;推送前 fetch 并变基,只快进。
  • ~/Dev/OpenRes/Lithe-core-rust-gaps:Core 克隆,提 Lithe-core-rust PR,合并后改 PINNED_CORE_REVISION。
  • Viva fork 修复在 Lithe-IDEA/viva 提 PR,同一分支向 vivaui/viva 提上游 PR;fork 同步上游由用户团队做。

踩过的坑:

  • Core 不能并发编译,Mac 会卡死。换 pin 后每棵树都要重编一次,编译产物不能跨树复用;编译前先确认 pgrep -fl "cargo|rustc" 为空。
  • desktop/go.mod 的 Viva 版本:先 PR 并 --admin 合并到 Lithe-IDEA/viva,再执行 GOPROXY=direct GOPRIVATE=github.com/Lithe-IDEA go mod tidy。偶发 SSL 错误,重试即可。
  • 新词条先写入仓库根的 i18n-pending-*.json,i18n.Shared() 在导入前返回空串。导入后跑 generate 和三项门禁。
  • Viva ui.Select 等控件按指针绑定状态,必须用持久字段,不能用局部变量。Windows LockFileEx 会挡住第二个句柄的读取。
  • 车道代理会自报“已实现”,合并前看 diff;矩阵核对类报告要抽查。

第二轮车道(2026-11-10 已合并并推送)

  • Git 续:行号区变更标记(查看被替换原文、单处暂存、在 Diff 中回退)、行尾 blame、设置 › 版本控制的开关、项目树右键与文件操作、.git 元数据监听。未做:行历史、本地变更列表、多仓库分组、Rebase 计划编辑、Diff 搜索/忽略空白。
  • IDE API:连接设置页与授权、broker 循环、Build 查询/重载/执行与执行输出/停止。未发布:environment、Maven 专属、Run 配置、build_configure(等对应 UI/写入路径)。
  • 运行调试续:停止后列出适配器线程并可切换线程重载调用栈;Variables 区新增监视编辑器,表达式以 DAP watch 上下文在当前帧求值,跨停止保留并自动重求值,拒绝的表达式单独显示。
  • 运行调试续:工具栏单步进入/跳过/跳出(适配器默认粒度),反汇编区在 supportsSteppingGranularity 时按 instruction 粒度单步;新增只读内存页,经 Core readMemory 读取 256 字节并展示偏移/十六进制/ASCII 与不可读字节数。
  • 运行调试续:启动调试与 Run 重跑前先保存所有待写文档,保存失败则不启动;端到端测试覆盖调试启动前的保存。
  • 编辑器续:设置 › 编辑器新增“使用语义颜色”开关(默认开),关闭立即清除叠加层并停止请求,重新打开为当前文档重新请求;选择持久化。
  • 编辑器续:LSP 日志窗口新增文本筛选(大小写不敏感、无匹配提示)和停止/重启服务器按钮,重启复用设置页的重启流程。
  • 编辑器续:光标撤销/重做——键盘移动后 Ctrl/Cmd+Z 先恢复光标且只优先一次,Ctrl/Cmd+U 与 Ctrl/Cmd+Shift+U 独立行走光标历史,编辑/鼠标/API 选区清空;历史上限 100。
  • 编辑器续:Markdown 预览链接跟随——http/https/mailto 交系统打开,相对路径在编辑器打开,锚点滚动到标题;其他 scheme 不跟随。相对/远程图片仍受 Viva markdown 不解析图片限制。
  • 测试夹具:复制测试二进制改为优先硬链接(夹具不写入文件),避免每个夹具复制一份 160MB 二进制,也让系统只校验一个代码身份;不支持硬链接时回退复制。
  • AI 设置补全:生成选项、共享指令、技能查看/分组/搜索/导入、Hooks 搜索与删除确认、已归档对话搜索/服务商筛选/本地移除;新增 Agent Note。
  • 远端同时合入的 Git 工作树页与控制台页已并入;Core 固定版本随远端更新为 de7a79ec。

第三轮(2026-11-11)

  • 字体设置页(fontprefs、settingswindow/fonts_view.go、workbench/fonts.go):字体以“组”保存,每个位置恰好属于一组,默认一组覆盖全部位置;可以做到“终端 A 字体、其他位置 B 字体”。字体列表在后台读取已安装等宽字体,未安装的字体标“未安装”,空字体名为系统等宽字体。打开页面不写文件,只在用户修改时写回应用数据目录的设置文件;恢复默认值清空保存的字体列表。
  • 编辑器(editorview/font.go)与终端(termview/font.go)按各自字体绘制:字号、行高(字符格高 × 行间距,取整像素)、连字;终端行缓存以连字为键。运行输出与 Git 控制台使用运行输出字体,暂不绘制连字。
  • Git 控制台:与运行输出字体统一;时间戳浅灰、仓库名蓝色;去掉右侧“显示 N 项临时配置”按钮,直接点击行内 -c … 展开/收起;按字符宽度换行与截断(宽字符不被截半),Tab 按 8 列制表位展开。
  • 项目树:文件夹整行(含名称后的空白)都可点击展开;文件图标与文件夹图标对齐(为文件补上展开箭头的占位)。
  • Commit 工具窗口:有项目时标题栏只显示“提交 | 暂存”页签,去掉重复的工具名;“更新父仓库引用”从更改列表栏移入提交选项弹窗(附 ⓘ 说明),窄面板不再截断;Sign-off 勾选的操作日志改为先询问 Changed()。
  • 提交选项:“…”按钮和右下角打开设置的齿轮合并为一个齿轮弹窗,分 Git(作者、Sign-off、更新父仓库引用)与 AI(生成提示词、在设置中打开…)两组;新增“生成提示词”(aiGeneration.customInstructions),生成提交信息时去掉首尾空白后作为 Core AICommitOptions.CustomInstructions 传入;设置 > AI 生成卡片也能编辑同一份提示词,两处互相同步,打开页面不写入;文本输入在当次绘制内保存(Viva 的 After 只在点击类事件后运行,键入时不会触发)。
  • 修复:设置 › AI 的技能开关、共享指令同步开关与提交信息生成选项改动后不生效。Viva 绑定控件只在被询问 Changed()/Clicked() 或页面结束时写回取值,原代码在声明后立即比较局部变量,永远看不到点击;现改为先询问 Changed() 再读取。
  • 功能矩阵:editor-font-family macOS/Windows 更新为 partial / pending,缺口:找不到字体时回退系统等宽字体而非内置字体、最小字号 6 pt(旧客户端 8)、无缺字提示、运行输出不绘制连字。
  • 已知小问题:总览里每个位置的“单独设置”按钮无障碍名称相同,暂未区分。(第二十四轮去掉了这些按钮,总览改为按位置名称命名的勾选框)

第四轮(2026-11-11)C05 插件工具窗口

  • Core(feat(core): plugins.web.* 插件网页的加载规则与桥接校验 Lithe-IDEA/Lithe-core-rust#9,Draft):新增 plugins.web.open/close/resource/document/request/reply/event。页面能读哪些包文件、文档最前面注入 CSP meta 与 window.lithe 桥接脚本、每条桥接请求的参数校验,以及回复、进度和主题事件的封装都在 Core;调用 ID 不可复用、最多 16 个调用、一次一个对话框也由 Core 计数。.lithe-host/ 为保留路径(契约 README 已注明)。已合并为 fd9a0d3d,桌面端锁定到该提交;本仓库 shared/contracts 同步了 plugins.web.* 与 .lithe-host/。
  • desktop/internal/pluginweb:页面宿主。按 Core 给的路径段逐级 Lstat 读包文件,不跟随符号链接,并限制大小;执行 Core 交回的动作(状态、functions.list/invoke/cancel 与进度、文件对话框、workspace.openFile);页面关闭时取消它的全部调用;离开插件源的导航送回入口。
  • pluginservice:ToolWindows 列出已启用插件的工具窗口;页面调用插件后端时只收到本调用的 requestProgress;页面状态按窗口和工作区存放在 <插件根>/.state/<plugin>/pages/…,原子写入。
  • workbench:chrome 目录改为每个窗口一份(内置项在前、插件窗口在后),由 Core 统一排列;停用插件期间保存的布局仍保留其窗口位置,重新启用后回到原处。文本窗口显示原文;网页窗口用 app.WebHost 加 NativeView 显示,引擎就绪前显示“正在打开…”,打不开时说明原因;一帧没有声明某个页面就关闭它(隐藏、移动、关项目、停用或更新插件都走这条路)。对话框标题写明插件名。
  • pluginhost 声明 ui {1,2},带工具窗口的插件可以安装了。
  • 修复调试面板的偶发失败:快速单步时,上一次停止的栈或内存回复晚到,Core 以 staleReference 拒绝,面板不再把它当作失败显示(新的停止会重新请求)。TestDebugMemoryReadsWithoutComputedAddresses 此前约 1/4 失败,现连续 8 次通过。
  • 功能矩阵 plugin-web-tool-windows、declarative-plugin-contract,Agent Note、资源复用清单与 docs/ci-builds.md 已同步。

第五轮(2026-11-11)Diff 标签页改为 IDEA 式双编辑器(0932e1c52)

  • 并排视图改为左右两个只读 Viva 编辑器(原先是一张 List),按文件语言加载 TextMate 语法;左右标题为“锁 + 版本 + 路径”。原版行号画在中缝,修订版行号在右侧编辑器行号区;改动之间用三次曲线色带相连(新增绿、修改蓝、删除灰),块级包含勾选框与回退按钮放在中缝;最右侧标尺按整文件标出各处差异。
  • 折叠:未更改的行折成一行“⇕ N 行未更改”,带展开图标和贯穿到右缘的横线,不着色;Core 补丁的区块分隔行同样处理。
  • 滚动:两侧同步,按对方视口中线映射到对应行,并取整到像素;只保留右侧纵向滚动条(左侧隐藏,滚轮和键盘照常可用)。上下跳转差异时两侧都把光标放到该处并居中,光标不会停在折叠行上。
  • 统一视图:一个编辑器,行号区显示“原版 修订版”双行号,删除行灰底、新增行绿底,块级控件在左侧。
  • Core 请求:GitDiffRequest.WholeFile 以 Core 的 FULL_FILE_CONTEXT_LINES 作为 contextLines 读取整文件,Core 在该值下把 Git 的区块间上下文固定为 0;两侧面板由 workbench/diffpanes.go 从 Core 的区块构建(行文本、行号标签、改动标记、左右片段对应)。
  • editorview 新增宿主装饰接口(diffdecor.go):SetLineHighlights(整行着色或行间细线)、SetLineLabels(以标签替换行号并按标签宽度调整行号区)、CenterLine、LineTop/LineAt/LineHeight、ScrollOffset/SetScrollOffset、BindWithoutMinimap、HideVerticalBar、ShowContent;LineAnnotation 增加 Icon 与 Rule。绘制路径仍为 0 allocs(TestRepaintWithHighlightsAndLabelsAllocatesNothing)。
  • 关闭项目时释放 Diff 标签页的编辑器(finishCloseProject 调用 closeDiffs)。
  • 图标:生成脚本加入 columns-2(并排按钮)。
  • 前一轮为 List 加的重绘绕过随 List 一起删除,[Feature] Viva List 应用 ScrollTo/ScrollToEnd 的那一帧显示旧偏移:上游修复后移除 Lithe Diff 标签页的重绘绕过 #1820 已更新(剩余的 List 调用点仍待 Viva 上游修复)。
  • 功能矩阵 git-diff-review 补充证据与说明,状态仍为 partial / pending。
  • 未做(列入剩余工作):右侧可编辑、词内高亮(需 Core 提供行内片段)、分隔行展开部分上下文、Diff 内搜索与忽略空白。

第六轮(2026-11-11)Viva 改由 Lithe-IDEA/viva 维护,删除已不需要的绕过代码

第七轮(2026-11-11,先写代码阶段:只保证 vet 通过,测试/文档/矩阵/i18n/CI 集中收尾)

合并方:

  • 本地历史(保存、批量替换、外部重载、放弃修改、重命名前快照;文件历史对话框)、快捷键自定义(集中目录 + 用户覆盖 + Keymap 页)、终端回滚设置与环境变量、全屏、Islands 项目色渐变、网络代理页、编辑器标签上限、查看器标签(图片/外部打开/十六进制)、应用内更新(Viva update:签名源检查、下载校验、安装,设置 › 更新)、窗口标题跟随项目与文件(Viva SetTitle)、内存监控(语言服务器与插件服务分项、明细弹层)、编辑器代码折叠(editorview 行映射隐藏行;语言服务器 foldingRanges 优先,否则按缩进;命令与快捷键)
  • 修正:方法/指令断点载荷字段 breakpoints;插件编辑器动作按第 2 版解码并声明 hostOptions.editor(core.EditorHost)

车道(均已合入 integrate 并推送):

  • Git/工作区:GitHub 设备码登录、PR 面板(列表/详情/评论/评审/检出/新建 + AI 描述/发布分支)、变基上下移、文件树 Git 子菜单、Diff 查找回车、WSL 路径与边界、超长命令脚本、Windows/Linux 紧凑菜单、启动背景色、诊断导出上限与到期、Git 标记上一处/下一处
  • IDE/扩展:插件 hover/completion/semanticTokens/codeLens 提供方与触发字符、行首图标列、原生 form/source 节点、运行面板 CPU/内存折线(Windows 进程树)、调试异常信息与求值历史、isIncomplete 续请求
  • AI:上下文圆环、历史搜索/筛选/移除、编辑器“加入 Agent 草稿”、全局指令/Hooks/Agents 管理页补齐、回复链接与代码块操作、工具卡片文件与差异、Agent 欢迎页、编辑区居中阅读列、MCP 搜索与精选合并

第七轮续(2026-11-11 下午,均已合入 integrate 并推送,HEAD a26073264 之后):

  • 合并方:Search Everywhere 补齐(类/符号标签页启用、匹配高亮、按 matchingDegree 排序、源码预览、按类型筛选与文本选项、“/”命令、Tab 切换、右键菜单、滚动自动翻页与重试、双击 Shift 经 Core keymap.modifierGestureStep);输入法组字让出宽度(editor-macos-ime-presentation);通知中心按类型着色与欢迎页铃铛;终端原生配色(WCAG 门控)与 Nerd Font 优先;HTML/SVG 在浏览器中打开;Core 固定到 a783ed9(Lithe-core-rust#11:documentLink、workspace/symbol、GitHub checks 与评审线程、disconnect terminateDebuggee)
  • 编辑器:Vim 模式(Normal/Insert/Visual/Visual Line/Replace,移动/操作符/文本对象/搜索/计数/“.”、Ex 命令 :w :q :wq :x :{n} :s :%s、标记、具名寄存器与 "+/"*、状态栏模式项、设置开关);问题面板预览分栏、筛选与分组;文档链接(插件)悬停与点击;补全多来源合并
  • IDE:进程账本(插件运行、终端、构建/测试/调试适配器/项目生成)与启动时残留确认;运行配置编辑器的运行时参数/入口/工具路径与 JDK/Maven 选择;插件工具窗口图标映射与 ui.commands(查找操作 + 快捷键目录可改绑)
  • AI:自定义命令行 Agent、按会话草稿与“加入 Agent”指定会话、历史批量导出 Markdown、会话详情菜单同步与真实 Git 状态 Diff(Agent 领域到此暂停)
  • 工作台:欢迎页固定项目与拖入文件夹打开、随包字体发现(字体资源打包待做)、状态栏缩进/换行符/只读锁点击切换、Windows 终端 Ctrl+C 有选中时复制
  • 进行中:startDebugging 子会话(多会话调试窗口);PR 检查与评审线程 UI、Diff 忽略空白;LSP documentLink 与 workspace/symbol 并入 Search Everywhere

第七轮续二(2026-11-11 晚,均已合入 integrate 并推送,HEAD a26073264 之后续):

  • 合并方:打开项目时询问 This Window / New Window(可记住,设置 › 常规可改回询问);打开已不存在的最近项目提示 Remove From List;侧栏工具按钮右键 Hide/Move to 六个停靠区;Find in Files 列位置、命中高亮与长行裁剪、项目树右键入口、编辑器单行选区预填;编辑器标签右键菜单(关闭其他/左侧/右侧/未修改/全部/除固定外、固定、复制路径、在项目视图中选择);标签固定改由 Core setPinned 持有(删除 Go 端 document.pinned);重开项目恢复编辑器会话(分组、分屏比例、选中、焦点、光标、固定)
  • 登录 shell 环境:启动时在 Core 之前把登录 shell PATH 放进进程环境(缓存 + 后台刷新),构建/Agent/工具链扫描补齐其余变量;调试断点同步到所有会话;终端拖入文件/系统文件按 shell 转义(含 WSL 路径);输入法组字让出宽度
  • Core:Lithe-core-rust#12(GitHub PR head_sha)、lithe 0.1.14 #13(execution.planLaunchCommand),桌面固定到 fbe848a;Java 长 classpath 改由 Core 规划,删掉 Go 端重复规则,Windows 按系统代码页编码参数文件
  • 车道 IDE:运行输出快照标签不被上限淘汰;插件编辑器动作按车道并排多图标、navigate/test 状态图标、多动作点击弹车道菜单、宿主图标表补齐 9 个、整批 8 秒预算
  • 车道 Git:版本控制设置“显示变更列表”“显示更新父仓库引用”;日志引用面板按仓库分组与 Core 配色;嵌套仓库分组可折叠;未跟踪目录汇总行显示文件数
  • 合并方续:编辑器会话恢复(分组/布局/光标/固定,按项目根存 40 个);硬链接文件保存(独立文件/更新全部链接/取消,自动保存遇硬链接停用并提示一次);自动保存 1.5 秒(设置可关),窗口失焦(app: Config.OnFocusLost for the window losing the keyboard Lithe-IDEA/Lithe-viva#2 Config.OnFocusLost)与键盘离开编辑器时立即保存;Build 窗口依赖树(Core build.dependencyPlan/decodeDependencies);插件行首图标车道菜单在图标下方弹出(ui: MenuAt opens a menu at a point of the window Lithe-IDEA/Lithe-viva#3 ui.MenuAt);搜索排除目录经 Core workspace.configureIndexing 生效(打开安装、规则变更刷新、关闭释放租约),项目树“取消排除”与根节点“自动排除 Git 忽略目录”开关
  • 车道 IDE:原生插件面板选择/展开/表单值按项目持久化、隐藏时取消请求、树方向键、表单 source 与按钮 info;调试变量区寄存器视图;运行配置对话框编辑插件声明的构建选项
  • 车道 Git:Git 日志切换活动仓库;Pull 对话框(仓库/远程/远程分支/策略,默认策略由 Core 给出);顶部分支弹窗可选仓库;嵌套仓库 Rebase from Here,已有未结束会话时拒绝新开;Diff 视图 Cmd/Ctrl+F
  • 合并方续二:编辑器多光标(Alt+Shift+点击、Alt+拖动列选择、IDEA 键位的下一个/全部/取消相同项、Clone Caret 上/下,均进快捷键注册表;一次撤销恢复所有光标);Markdown 预览图片(相对路径与 http(s),走代理,SVG 与失败显示替代文字);Core [Feature]windows后期适配建议,运行多服务选项 #14 diff 行内改动范围 leftChanges/rightChanges(Go 已解码,Diff 视图尚未绘制)
  • 车道 IDE:构建选项持久化(build.resolveStoredOptions/editStoredOption,团队文档 .lithe/build/options.json 只读、本地文档存应用数据目录)与构建窗口“构建选项”对话框;IDE API lithe_build_configure 已分发;Vim Visual Block(Ctrl+V,含 I/A/c/d/y/r/p/P/o/O)
  • 车道 Git:Pull 对话框;分支弹窗选仓库;嵌套仓库 Rebase from Here 与会话单槽保护;Diff Cmd/Ctrl+F;Diff 右侧可编辑(含未打开文件:无标签 document,镜像编辑保持对侧光标);折叠占位行分步展开(上/下 20 行、全部,悬停显示三区图标);命令面板 Show History for Selection

收尾阶段待办(新增):

  • 测试阶段:ide_api_dispatch_test.go 第 21 行“不分发 build_configure”的断言改为已分发;shortcuts 默认键测试纳入 5 个多光标动作;测试夹具设 DisableAutoSave;fake kernel 补 indexingKernel、buildDependencyKernel 等类型断言接口
  • 代码续:Diff 视图按 leftChanges/rightChanges 画词内高亮(6256f1fa1);历史改写 UI(进行中)(撤销/删除/压扁提交、编辑提交信息:Core 已有 historyRewritePreview → 审阅 → 带 expectedState 写入);Vim 块操作的 . 重复
  • Core 缺口:cherry-pick / revert / reset 的请求字段契约(Lithe-core-rust#15,bdd12452a 固定并加 Go 封装);launch.json 导入无 Core 命令
  • 确认为真缺:embedded-viewers(HTML/SVG/媒体/PDF 预览,暂缓(依赖 webview),2026-11-11 决定)、editor-ide-settings-import、editor-scrollbar-style 与 editor-wallpaper-overview-ruler(需 Viva)、SVN/插件 VCS provider(shared/contracts/vcs-provider-v1.md,Go 侧未接)
  • 矩阵大面积滞后:车道核对 130 条中多数“缺/部分”已实现(editor-tab-limit、history-*、login-shell-environment、vim-mode、file-open-selected、search-replace、run-output-snapshot、workspace-files、git-line-history、git-multi-repository-references 等),收尾时按代码统一更新
  • 矩阵补:workspace-indexing-exclusions(已生效)、editor 自动保存与失焦保存、dependency-browser、editor 会话恢复
  • 导入 i18n-pending-{me,git,ide,ai}.json(实际 612 条)到 shared/i18n/,跑 generate 与三项门禁(cabbf4f5c)
  • GUI 实机验收重点:代码折叠(行映射改动大)、内存明细、更新流程、窗口标题、PR 面板、WSL、紧凑菜单、Vim(Ctrl 组合键经 onShortcut、: 命令行、H/M/L 折行落点)、输入法组字、双击 Shift 与 Tab 切换标签页、Search Everywhere 预览、新增状态栏项(旧布局可能需重置)
  • 更新:发布流水线生成签名 feed 与 ldflags 注入 UpdateFeedURL/UpdatePublicKeys
  • Core 缺口:发布分支规划、详细诊断分类、remote/ssh 子进程是否加 CREATE_NO_WINDOW(可能需要控制台交互,待定)、语言服务器 PID 回报(进程账本)、会话暂停期间单独暂停一个已单独继续的线程(debug.execute 的 pause 只在会话运行时接受)(git.diff 忽略空白已有 ignoreAllWhitespace;PR checks/评审线程、documentLink、workspace/symbol、disconnect 策略已在 [Feature] 适配其他语言系 尤其是前端部分 #11 合入)
  • 待设计:provider options 按插件 schema 渲染表单;ui.commands 的 toolbar/menu 放置;监护进程(崩溃兜底);首次启动引导;随包 Inter/JetBrains Mono 字体的构建期打包与许可
  • Viva 缺口:剪贴板文件/图片、Segmented/Stepper 控件、按宽度断点(按坐标菜单、失焦回调、Markdown 图片已在 fork 补上)
  • 矩阵 notes 已过期需按代码更新:vim-mode、embedded-viewers、search-replace、keymap-customization、workspace-tree-batch-files、file-open-selected、command-palette、editor-tab-limit、terminal-native-palette、window-title、run-output-snapshot、plugin-editor-actions、git-workspace-commit-retry、git-submodule-commit-plan、git-multi-repository-change-groups、git-local-changelists、git-large-untracked-directories;并补本轮新增(workspace-open-switch、workbench-tool-window-docking、search-project、workbench-panes、run-java-long-classpath)
  • 契约:rust-core-api.md 已改为实际函数 java_feature_version_from_release(Core d797244 中已一致);lithe-plugin-docs 已退役,契约只在 Core shared/plugins/,不再需要同步

第八轮(2026-11-11 夜,收尾优先级 1:代码缺口)

  • 6256f1fa1 Diff 视图按 Core [Feature]windows后期适配建议,运行多服务选项 #14 的 leftChanges/rightChanges 画词内高亮:editorview 新增 InlineHighlight/SetInlineHighlights(设置时把 UTF-16 列换算成单元格,绘制时按行二分查找,重绘零分配),画在行底色之上、选区和文字之下;并排视图用 modified 色,统一视图按删除/新增色;性能基线见下文。
  • 27831d9f3 修 Log 列表点击提交后右侧详情不显示:“从此处变基”菜单给每行另设的点击目标收走了左键,列表选不上提交;改为把右键菜单挂在列表行自身上(与暂存、调试列表一致),TestLogCommitListSelectsWithTheKeyboard 覆盖。
  • 894bf60da 窗口标题变化后红绿灯按钮保持居中(darwin: keep the traffic lights centered when the title changes Lithe-IDEA/Lithe-viva#5)。
  • bdd12452a Core 固定到 1274b3f(后续 48c6991f9 升到 d797244,含 [Feature] 希望尽快推出 Windows 版,另外支持一下 keymap 自定义 #16 控制台折叠与 feat(database): add integrated database workspace #17 契约单一基线;Lithe-core-rust#15:cherry-pick、revert、reset 写入请求与 git.operationState/operationControl/integrationPreflight/historyActionCapabilities),Go 端 core/git_history.go 封装历史改写预览与写入。
  • cabbf4f5c 导入第七轮待办词条 612 条,删除 i18n-pending-*.json;generate-i18n.mjs --check、verify-app-language-localization.mjs、test-i18n.mjs 通过。
  • 150db9b9a Viva 固定到 fork main 7850516([Feature] 现在是支持的Spring系,希望增加支持quarkus系 #6 MenuItems.Beside())。
  • 1e5a9accd 分支弹窗参照旧版重做:行菜单从行右侧展开(放不下才翻到左侧);顶部操作补齐 Update Current Branch、Commit…、Push…、New Branch、Checkout Tag or Revision、New Tag,搜索时加 Fetch;行菜单为 New Branch from、Compare with Working Tree、Compare with Current、Checkout、Update、Push…、Rename、Delete;行高压到 24pt,Local/Remote 按 / 折叠成文件夹(默认收起)。修根因:同步、比较、推送原先作用于项目仓库,现在作用于弹窗选中的仓库(嵌套仓库不再误推项目仓库)。测试加 popupHit(取最上层图层的控件),避免同名控件命中背后窗口。

第九轮(2026-11-11 夜,按旧客户端补齐右键菜单与零散修复)

逐个对照旧 SwiftUI 客户端的 litheContextMenu,把已有功能的右键菜单接上;菜单项都调用对应按钮的同一个动作,按钮被禁用的状态下菜单项同样禁用。

  • c73fd2fdf 合并 diff 的竖条与缩略条按行着色,删除行改红色;切换提交时取消旧的读取。

  • b06fd169e Git 控制台把内部读取命令淡化并整段折叠,可一键隐藏(Core [Feature] 希望尽快推出 Windows 版,另外支持一下 keymap 自定义 #16)。

  • 4701b1d3d 日志提交右键菜单补齐复制哈希、标签、拣选、还原、重置与历史改写,并显示进行中的合并/拣选/还原。

  • d1d442fab 日志引用面板的分支右键菜单补齐比较、签出并变基、合并、变基、拉取、跟踪分支与复制分支名。

  • d0a0e3811 提交窗口变更行、终端、标签页与项目树右键菜单补齐旧版操作。

  • fb1711cd0 双击 Shift 打开全局搜索;输出面板逐行右键菜单;关闭终端时等待 shell 退出。

  • 96c6d89cd “在当前窗口打开”项目改为项目标签,与旧版一致。

  • f9ab844ca 全局搜索滚动到底自动翻页,不再跳回首行。

  • a9f2d6fb6 调试面板补齐右键菜单;插件原生树面板右键不再崩溃。

  • 866b9bc17 “在文件中查找”结果行右键菜单:打开、在访达中显示、复制路径与相对路径。

  • 5ecb713e7 工作树列表行右键菜单:打开、在新窗口打开、在访达中显示、复制路径、锁定、移除、清理失效记录。

  • 484c128d4 快捷键设置行与反汇编指令行右键菜单;从菜单打开反汇编不再空白。

  • 16b305e18 构建工具窗口右键菜单:任务运行;目标按适用的运行方式运行;项目打开构建文件、重新加载模型;依赖树重新加载。修根因:构建根不在工作区根时,打开构建文件(含原有双击)按契约以构建根解析项目路径,不再找错目录。

  • 0af74618f 侧边栏按钮菜单加“前移/后移”(同一区域内);工具窗口标题栏右键可隐藏该窗口(旧版 Problems 标题栏);“全部替换”预览的文件行右键菜单(打开第一处改动、在访达中显示、复制路径与相对路径;预览是模态窗口,打开文件前先关闭预览)。修测试:clangd 端到端用例的测试清单补上契约归 0 后必填的 requires(此前 8 个用例被误当成环境超时);切换项目用例改为先关闭再打开(已有项目时再打开会新建项目标签)。

  • 9dc094ee5 断点右键菜单加启用/禁用;禁用的断点在列表中淡化,保留行号与选项,Core 不发给适配器;随编辑重定位时保留启用状态。

  • e2737bf7b 编辑器行号区显示断点(禁用为空心、条件、日志点),点击行号切换断点,暂停时着色当前执行行;断点列表改为调试窗口分页,修复暂停后调用栈被挤成零高度。editorview 改动前后基线(同一台 M4,scripts/desktop/perf/editor-bench.sh,.artifacts/editor-perf/bp-before.* → bp-after.*):28 项全部在预算内,无新增超预算;最大变化 Paint/java/100KiB +6.3%,Paint/gutter ±0.1%,分配数全部不变。

行号区断点:改动后基线(vs 改动前)
Benchmark ns/op B/op allocs/op extra metrics vs base Budget
BenchmarkEditorViewPaint/plain/100KiB 41.8 µs 0 B 0 +3.3% ns/op, allocs = ✅ within
BenchmarkEditorViewPaint/plain/10MiB 39.1 µs 0 B 0 +0.8% ns/op, allocs = ✅ within (scale 0.94x vs 100KiB <= 1.5x)
BenchmarkEditorViewPaint/go/100KiB 44.4 µs 0 B 0 -4.9% ns/op, allocs = ✅ within
BenchmarkEditorViewPaint/go/10MiB 41.1 µs 0 B 0 +0.6% ns/op, allocs = ✅ within (scale 0.93x vs 100KiB <= 1.5x)
BenchmarkEditorViewPaint/java/100KiB 34.4 µs 0 B 0 +6.3% ns/op, allocs = ✅ within
BenchmarkEditorViewPaint/java/10MiB 31.5 µs 0 B 0 +0.6% ns/op, allocs = ✅ within (scale 0.92x vs 100KiB <= 1.5x)
BenchmarkEditorViewPaint/wrap/100KiB 43.1 µs 0 B 0 +1.6% ns/op, allocs = ✅ within
BenchmarkEditorViewPaint/wrap/10MiB 39.9 µs 0 B 0 +0.4% ns/op, allocs = ✅ within (scale 0.93x vs 100KiB <= 1.5x)
BenchmarkEditorViewPaint/minimap/100KiB 62.1 µs 0 B 0 +0.2% ns/op, allocs = ✅ within
BenchmarkEditorViewPaint/minimap/10MiB 58.9 µs 0 B 0 -0.5% ns/op, allocs = ✅ within (scale 0.95x vs 100KiB <= 1.5x)
BenchmarkEditorViewPaint/longline/100KiB 1.33 µs 0 B 0 +0.6% ns/op, allocs = ✅ within
BenchmarkEditorViewPaint/longline/10MiB 1.36 µs 0 B 0 +0.4% ns/op, allocs = ✅ within (scale 1.02x vs 100KiB <= 1.5x)
BenchmarkEditorViewPaint/cjk/100KiB 26.2 µs 0 B 0 +0.3% ns/op, allocs = ✅ within
BenchmarkEditorViewPaint/cjk/10MiB 24.7 µs 0 B 0 -0.1% ns/op, allocs = ✅ within (scale 0.95x vs 100KiB <= 1.5x)
BenchmarkEditorViewPaint/mixed/100KiB 28.3 µs 0 B 0 +1.0% ns/op, allocs = ✅ within
BenchmarkEditorViewPaint/mixed/10MiB 29.3 µs 0 B 0 +0.3% ns/op, allocs = ✅ within (scale 1.03x vs 100KiB <= 1.5x)
BenchmarkEditorViewPaint/selection/100KiB 44.7 µs 0 B 0 +0.7% ns/op, allocs = ✅ within
BenchmarkEditorViewPaint/selection/10MiB 41.4 µs 0 B 0 +0.4% ns/op, allocs = ✅ within (scale 0.93x vs 100KiB <= 1.5x)
BenchmarkEditorViewPaint/markers/100KiB 44.8 µs 0 B 0 +0.5% ns/op, allocs = ✅ within
BenchmarkEditorViewPaint/markers/10MiB 41.4 µs 0 B 0 +0.3% ns/op, allocs = ✅ within (scale 0.93x vs 100KiB <= 1.5x)
BenchmarkEditorViewPaint/gutter/100KiB 46.3 µs 0 B 0 +0.1% ns/op, allocs = ✅ within
BenchmarkEditorViewPaint/gutter/10MiB 42.9 µs 0 B 0 -0.1% ns/op, allocs = ✅ within (scale 0.93x vs 100KiB <= 1.5x)
BenchmarkEditorViewType/go/100KiB 50.4 µs 2.71 KiB 7 +0.1% ns/op, allocs = ✅ within
BenchmarkEditorViewType/go/10MiB 47.8 µs 4.66 KiB 31 +0.1% ns/op, allocs = ✅ within (scale 0.95x vs 100KiB <= 2x)
BenchmarkEditorViewCaretMove/go/100KiB 45.8 µs 32 B 0 +0.6% ns/op, allocs = ✅ within
BenchmarkEditorViewCaretMove/go/10MiB 34 µs 32 B 0 +0.3% ns/op, allocs = ✅ within (scale 0.74x vs 100KiB <= 1.5x)
BenchmarkEditorViewScroll/go/100KiB 45.6 µs 0 B 0 +0.5% ns/op, allocs = ✅ within
BenchmarkEditorViewScroll/go/10MiB 41.4 µs 0 B 0 +1.2% ns/op, allocs = ✅ within (scale 0.91x vs 100KiB <= 1.5x)

This report never fails the build; overruns are findings to fix or to justify in the PR.

盘点结论(旧版菜单所在功能在新版整体缺失,菜单随功能补,已记入下方“功能缺口”):

  • 运行配置浏览列表(作用域、分组、固定、批量选择、服务地址):新版只有运行配置下拉条与编辑对话框,行菜单的 Run/Stop、Edit Configuration…、Pin、批量选择没有挂载对象。
  • 插件 VCS provider 工具窗口(SVN 等):Commit Files…、Show Diff、Show Diff in New Tab。
  • Shelf(搁置变更)(第十三轮补齐)。
  • 调试:线程暂停/继续、监视表达式行内编辑(第十一轮补齐;行断点启用/停用已在 9dc094ee5 补齐)。
  • 构建窗口的测试:Run Tests、按项目范围测试、Discover Tests(第十二轮补齐);依赖侧栏的“从依赖树排除”。
  • 编辑区终端标签页的 Clear/Interrupt/Restart(新版没有编辑区终端)。

第十轮(2026-11-12)删除 Agent 对话

用户决定 Viva 桌面端不做 Agent 对话(51ee91dcd):

  • 删除:助手工具窗口、会话与历史(含已归档对话)、Agent 安装与管理、自定义 Agent、Agents/指令/技能/Hooks/MCP 配置五个设置页、快捷键“新建 Agent 对话”、项目树“加入 Agent 会话”;desktop/internal/core/agent*.go、mcp.go,internal/agentbrand、internal/mcpconfig。97 个文件,约 1.7 万行。
  • 保留:AI 提交信息、编辑器 AI 行内编辑、创建 PR 的 AI 描述。它们共用的 provider 发现搬到 workbench/ai_provider.go,只调 Core 的 ai.configuration.sources/parse;生成选项移到设置 › AI › 生成,设置文件字段 aiGeneration 不变。AI 分组现为“生成 → IDE 连接”。
  • 文案:shared/i18n 删除只给桌面端 Agent 用的 474 条,与旧客户端共享的 490 条只去掉 desktop 平台。
  • 矩阵与清单:38 个 agent-*/mcp-* 行改为 missing,docs/viva-migration.md 新增“放弃:Agent 对话”表。
  • Agent Note:新增 implemented/feature/2026-11-12-viva-agent-conversation-removed.md;Viva Agent 桥与 Markdown 回复两篇归档;四篇子进程与 ACP 笔记去掉已删路径。
  • 测试:TestCoreChildProcessesKeepGoSignalStack 改用 Go 与 Core 的 git status 子进程验证 SIGCHLD 仍带 SA_ONSTACK;工具窗口拖放测试改用 Markdown 预览代替助手窗口(第二十三轮起改用“通知”窗口)。[Feature] 桌面端 Agent 面板 31 个用例在欢迎选择页上线后过时 #1827 的 31 个 Agent 失败用例随代码删除。
  • 未动:Rust Core 的 Agent 宿主和 shared/fixtures/agent、shared/fixtures/mcp,是否删除待用户决定。
  • a4eb41350 修运行时 bundle 只读检查(随包字体 f30c102d3 与新窗口打开项目 96c6d89cd 各自调用 os.Executable,检查失败):安装包位置只在新增的 internal/installedpackage 查找(Executable 只用于启动另一个客户端,ResourceFolder 只读返回 bundle 内固定资源目录),检查脚本只放行该包,并在该包出现写文件、exec、syscall 时失败;测试确认读取并注册随包字体前后 bundle 文件清单与哈希不变。
  • 验证:全量 desktop-go.sh test -count=1 -p 4 ./... 48 包通过,vet 0 条;i18n 两项、功能矩阵 255 项、Agent Notes 232 篇、运行时 bundle 只读检查通过。

第十一轮(2026-11-12)调试单线程继续与监视行内编辑

  • 线程选择器右键菜单新增“继续线程/暂停线程”:适配器声明 supportsSingleThreadExecutionRequests 时经 Core debug.execute(singleThread: true)单独继续一个线程。Go 绑定原来漏了 singleThread 字段,新增 ExecuteDebugThread;Core 无改动。
  • continued 事件在会话仍暂停时只清掉该线程:选择器标“(运行中)”,该线程不再显示栈、变量和监视值;其他仍停着的线程照常切换查看,单步按钮在当前暂停线程被单独继续后禁用。整体继续或下一次停止清空单线程状态。
  • Core 只在会话运行时接受 pause,所以会话暂停期间无法再单独暂停已单独继续的线程,菜单项显示为禁用;已记入 Core 缺口。
  • 监视表达式行内编辑:双击或右键“编辑监视”把该行变成输入框,Enter 或焦点离开保存并在当前帧重新求值,Esc 取消;空白或未改动不变。
  • 新文案 desktop.debug.threadRunning;native.pauseThread、native.resumeThread、native.editWatch 加入 desktop 平台。
  • 测试:TestDebugThreadResumesAloneAndWatchEditsInPlace(fixture 适配器支持单线程请求,走真实右键菜单、双击、Enter/Esc);调试相关 workbench/core/i18n 测试、vet、i18n 三项检查、功能矩阵校验通过。

第十二轮(2026-11-12)构建窗口的测试入口(5e768983e)

  • 项目行右键“运行测试”:构建系统声明 project 测试范围时出现,按该项目运行(Core build.testPlan 的 project 范围)。
  • 目标行右键“运行测试”:声明 target 范围、且目标带有声明的 targetTags 之一时出现(未声明标签时所有目标都可以);连同所属项目一起交给 Core。窗口只隐藏 Core 会拒绝的入口,规则仍由 Core 判定。
  • 发现测试:声明 discovery 的构建系统在构建树末尾显示“已发现的测试”分组。只在用户点“发现测试”或右键“刷新已发现的测试”时运行(可能触发编译):Core build.testDiscoveryPlan 规划,插件 provider 回答 lithe/build/discoverTests,Core build.decodeTestDiscovery 校验并限长。每个测试双击或点行内按钮单独运行,原样带回 suite/case/项目/目标选择器;行按当前选中的项目筛选。
  • 撤销旧清单:模型重新加载(含标记文件保存、设置变更)或重新检测只撤销对应实例的清单;在构建目录内保存任何文件也撤销该实例的清单,进行中的发现按代数丢弃。目前没有项目级文件监听,编辑器外的改动不会触发撤销。
  • 测试工具窗口:“重新运行”重复上一次的选择(单个测试、目标、项目或整个工作区);上次不是整个工作区时多一个“运行全部测试”按钮。每次运行都打开测试工具窗口(与构建窗口在同一区域)。
  • Go 绑定:core.PlanBuildTestDiscovery、DecodeBuildTestDiscovery,测试声明读取 targetTags;Core 无改动。新文案 desktop.build.testDiscoveryFailed;native.runTests、native.runAllTests、native.discoverTests、native.discoveredTests、native.discovering、native.noTestsDiscovered、native.refreshDiscoveredTests 加入 desktop 平台。
  • 测试:TestBuildWindowRunsProjectTargetAndDiscoveredTests(fixture provider 两个项目、带标签和不带标签的目标;走真实右键菜单、点击、双击,逐次检查 provider 收到的选择器,最后保存源码确认清单撤销);构建、测试窗口、文档保存相关 workbench/core/pluginservice/i18n 测试、vet、i18n 三项检查、功能矩阵 255 项通过;全量 desktop-go.sh test ./internal/... 49 包通过,运行时 bundle 只读检查通过。

第十三轮(2026-11-12)Commit 工具窗口的 Shelf 页签(b6cec1d0d)

  • Commit 工具窗口新增第三个页签“搁置”,Git 工具菜单新增“Lithe 本地搁置”入口。布局与 Stash 页相同:工具栏(刷新、显示 Diff、搁置更改、展开/折叠全部)、上下可调整的搁置列表与文件树、底部“恢复”按钮;行右键菜单“恢复”“删除”。
  • 搁置:弹窗填写名称(空名称不可提交)。Core git.shelf 的 capture 读取暂存区与工作区(含未跟踪文件)两层补丁;客户端先写入记录,再按 plan(clean) 的顺序逐层 clean。有冲突时 Core 返回 SHELF_CONFLICTS,层内容变化返回 SHELF_CHANGED,失败时记录保留,提示“仓库已发生变化。搁置记录已保留…”。没有改动时提示“没有可搁置的改动”。
  • 恢复:按 plan(restore) 逐层 restore,全部成功才删除记录。失败时记录保留,可以重试,Core 会识别前一次已应用的层。删除只移除记录,不动工作区,需要确认。
  • 未保存守卫:仓库内有未保存的编辑器文件时,拒绝搁置和恢复(git.saved.unsaved,与旧 Windows 客户端一致)。
  • 存储:客户端配置目录 Shelves/<仓库根路径 sha256 前 8 字节>/<随机 id>.json,格式版本 1,原子写入。不写仓库、不写安装包。读取时跳过其他格式、id 与文件名不符和无法解码的文件,并记入日志。
  • 查看:选中记录后用 Core git.parsePatch 解析两层补丁,文件树按“暂存区”“工作区”分层(层标题吸顶),再按目录分组。双击文件打开只读 Diff 标签页:暂存层为 HEAD ↔ 暂存区版本,工作层为暂存区版本 ↔ 工作区。
  • 重构:Stash 页文件树抽成共用的 workbench/saved_files.go(Stash 一层无标题,Shelf 两层),Diff 标签页的 stashSource 改为通用 savedSource(左右标签由来源给出);删除与 projectRelative 重复的 projectRelativePath。
  • Go 绑定:新增 core.GitShelfCapture/Plan/Clean/Restore、GitParsePatch。Core 无改动。
  • 文案:不新增词条;git.saved.tab/shelves/staged/restore/drop/changed/conflicts/noChanges/unsaved、native.shelveChanges/noShelves/lldFileS/couldNotLoadSavedChanges/thisRemovesTheSavedPatchFromLitheAndCannotBeUndone 加入 desktop 平台。
  • 测试:
    • TestShelfTabShelvesShowsRestoresAndDropsShelves:真实 Git,覆盖暂存新文件、工作区修改和未跟踪文件。依次检查:搁置后工作区干净;记录在客户端目录;两层文件与两种 Diff 标签;有未保存文件时拒绝恢复;冲突时恢复失败、记录保留;重试后三类改动全部还原、记录删除;删除需要确认且不动工作区。
    • TestReadShelvesSkipsForeignFiles、TestGitActionsMenuShowsTheShelfTab。
  • 验证:Shelf/Stash/Diff 相关测试;全量 desktop-go.sh test -count=1 ./... 50 个包通过,vet 0 条;i18n 三项检查、功能矩阵 255 项(git-rebase-stash 补证据)、运行时 bundle 只读检查通过。

第十四轮(2026-11-12)运行配置浏览列表(9cbf595d4)

  • Run 工具窗口顶部改为运行配置列表(原单个下拉框),与下方构建实例、目标、输出之间用可拖动分隔条调整高度(列表最小 72pt,下方保留一行目标与输出的最小高度)。
  • 范围选择器:全部配置、置顶,以及 Core 给出的执行类型中实际存在的服务/应用/任务/组合,每项带数量(“应用 (2)”)。切到不再存在的范围时回到全部配置。
  • 分组:按提供配置的插件 + 构建系统分组,组标题取构建系统自报名称(缺省为构建系统 id),组按标题、组内按名称排序;组可折叠,折叠选中配置所在组时选中落到组行。同名配置由 Core 按根目录加后缀区分(“Run Main (tools)”),桌面不再另做去重。
  • 行:执行类型图标、名称、置顶标记;空闲时行尾“运行”按钮(构建窗口忙或模型未加载时禁用),正在运行的配置显示“运行中”和“停止”按钮(buildOperation 记录所运行的配置 id)。Enter 或双击运行;组行 Enter/双击折叠展开。
  • 右键菜单:运行/停止、编辑运行配置…(打开已有编辑对话框)、置顶/取消置顶。
  • 置顶:客户端数据目录 run-configuration-pins.json(按项目根路径存排序后的 id),首次解析出配置后读取;写入失败保留原状态并提示。不写项目、不写安装包。配置暂时消失(模型重载中)时置顶保留。
  • 文案:不新增词条;native.allConfigurations/pinned/services/applications/tasks/groups/pinConfiguration/unpinConfiguration/editConfiguration/noConfigurationsInThisScope/runConfigurations/lld.variant2/collapseSection/expandSection/stopRun.variant2/running 加入 desktop 平台;删除不再使用的 desktop.runConfig.label/edit。
  • 测试:TestRunConfigurationListScopesGroupsPinsAndRuns——范围与数量、分组与排序、右键置顶写入客户端存储且不写项目、重新读取后置顶范围只剩该配置、折叠/展开、双击经插件发出该运行请求、运行中行显示停止并能停止、取消置顶后存储清空并显示空范围提示。
  • 未做(记入剩余工作):批量选择与并发运行(需要按配置的独立运行会话,会影响 IDE API 输出与结束语义;Viva ListState.Selection 已支持多选)、服务地址提示(端口规则应先进 Core)。
  • 验证:运行配置相关测试;全量 desktop-go.sh test -count=1 ./... 50 个包通过,vet 0 条;i18n 三项检查(范围标题改为字面量词条)、功能矩阵 255 项(run-discovery 补证据,仍为 partial)、运行时 bundle 只读检查通过。

第十五轮(2026-11-12)插件 VCS Provider 工具窗口

  • 宿主声明 vcsProviders。已启用插件的每个 VCS Provider 各有一个底部工具窗口,标题取 Provider 自报名称,使用通用分支图标;插件启用、停用或换包时窗口随目录更新。工作区根由 Core vcs.detectRoots 识别(嵌套、歧义目录由 Core 判断),用户为歧义目录选定的 VCS 存客户端数据目录 vcs-root-mappings.json,不写项目。
  • 会话:窗口第一次需要时,按 Core PlanPluginVcsProvider 的计划启动 Provider;buildprovider 改为同时承载构建和 VCS 两种角色,从 Core 的 vcsProvider 事件记录协商到的 VCS 和能力。协商不到或 VCS 不匹配时关闭会话并提示。每个请求由 Core lsp.vcsRequest 生成,回复由 vcs.decodeReply 校验后才用;Provider 错误按 Core 保留的错误码显示(ProviderError)。
  • 窗口:工作副本选择、修订/分支/位置标题;“更改”页按冲突、变更、未版本化分区列出状态,行带状态字母、勾选和说明(移动来源、树冲突、本副本锁定、他人锁定、属性修改)。提交区用 Commit 窗口的分栏规则:保持自己的高度,列表占剩余空间,面板很矮时也能看到提交按钮;没有 push 能力的 VCS 提示提交会直接进入仓库。工具栏和右键菜单按协商能力显示:刷新、显示差异、回滚(确认对话框列出路径)、更新、标记为已解决、清理、重新识别。“历史”页分页加载修订,列表与修订详情之间可拖动。
  • Diff:双击变更,经 baseContent 取基线,用 Core 已有的 diff.compareTexts 和磁盘内容比较(新增 core.CompareTexts 封装),打开只读 Diff 标签页;Provider 标为二进制或磁盘内容不是 UTF-8 文本时显示为二进制,基线为 null(新增文件)时按空文本比较。
  • 生命周期修复(构建会话里原有的同类问题一起修了):会话启动移到锁外,窗口线程关闭会话时不再最多等 60 秒;关闭项目会使旧会话失效(closing),迟到的启动由启动方自己关闭;构建会话加 detached 计数,detach 之前开始的启动不再挂到新会话上。
  • 教训:Viva 的 c.After 只在点击/指针事件的绘制中执行,普通绘制里登记的回调会被丢掉。所以窗口的识别、状态和历史改在绘制时直接触发,与 Run 窗口的 loadBuildSystems 做法一致。
  • 文案:新增 desktop.vcs.commitDirectly,其余复用已有 native.* 词条(加入 desktop 平台)。
  • 测试:TestVcsProviderWindowListsCommitsAndRollsBack 用一个按契约应答的假 Provider(测试进程自身)走完识别、分区与标题、双击只读 Diff(+1/-0)、右键回滚确认与请求参数、勾选提交与提交信息、提交后显示新修订、标记解决后冲突分区消失、历史页;TestBuildRuntimeDetachKeepsTheRuntimeOpen 覆盖 detach 计数。
  • 未做(记入剩余工作):Annotate、单文件历史、编辑器 gutter、元数据目录监听、fileOperations(项目树添加/移动/删除交给 Provider)、项目树状态着色、vcs.ownerOf、lithe/vcs/execution 控制台输出、冲突另一方显示、历史条目 Diff、authenticate;真实 Subversion 插件(lithe-plugin-svn)验收。
  • 验证:VCS 与构建会话相关测试;全量 desktop-go.sh test -count=1 ./... 50 个包通过,vet 0 条;i18n 三项检查、功能矩阵 255 项(vcs-subversion-and-plugin-providers 改为 partial/pending)、运行时 bundle 只读、测试稳定性检查通过。

第十六轮(2026-11-12)插件 CodeLens 路由、工具启动、打包字体恢复、矩阵复核(517900b79、a790c8bae、fc7e22c9a)

  • CodeLens 路由修复:宿主已接好 CodeLens 界面,但 core.EditorHost.ProviderTypes 缺 codeLens,Core 一直拒绝插件的 CodeLens 注册;现已声明该类型。pluginservice/hostproviders.go 改为按 providerFunctionFields 一张表路由,去掉六段几乎相同的分支。新增 core/editor_providers_test.go(Core 接受全部六种类型,仍拒绝 foldingRange)和 pluginservice/hostproviders_routes_test.go(每种类型都落到插件注册的函数上)。
  • 插件后端与语言服务器的 {kind:"tool"} 启动:pluginbackend.ToolResolver 改为接收工作目录,返回 ToolExecutable(程序路径加上所选工具声明的环境,如工具目录与 PATH)。工作台用 resolveBackendTool 解析,走与 Run 相同的工具链层级(resolveRunTool)。环境变量按“工具 < 计划 < 请求”覆盖。测试 TestStartResolvesAToolThroughTheHostToolchain。
  • 打包字体恢复(字体文件原随 SwiftUI 客户端在 f1e8d8139 删除,发行包实际用的是系统字体):
    • 字体放回 desktop/internal/bundledfont/fonts,与 preview 上的 git blob 完全相同:Inter 4.1 的 18 个 OTF、JetBrains Mono 2.304 的 16 个字型、JetBrainsMono Nerd Font Mono 的 4 个字型,以及许可文件。NOTICE.txt 写明来源和每个字型的 SHA-256。
    • macOS 发行构建用 lithe_bundled_fonts 构建标签经 go:embed 编进可执行文件(package-desktop.sh 传入该标签)。运行时不读写 bundle 的 Resources,因此删除了已无用的 installedpackage.ResourceFolder。
    • 启动时经 Viva app.RegisterFont 按进程范围注册(暂存副本在用户缓存目录 viva/fonts)。界面在首次绘制前切换为 Inter,编辑器和运行输出默认 JetBrains Mono。开发与测试构建不带字体,用系统字体。
  • 终端默认字体:按 terminalNerdFonts 顺序取第一个可用的 Nerd Font。已安装的 MesloLGS 优先,其次是打包的 JetBrainsMono Nerd Font Mono,再其次其他已装的 Nerd Font,都没有时用打包的 JetBrains Mono。之前打包的 Nerd Font 从未参与选择(fonts_test.go)。
  • 字体测试:
    • 不带标签:分组注册、字体目录与 SHA-256 清单一致、每个字体族的字型数量。
    • 带标签(desktop-go.sh test -tags lithe_bundled_fonts ./internal/bundledfont/):嵌入文件与仓库文件逐字节一致;用真实 CoreText 注册得到三个字体族;Nerd Font 出现在等宽字体列表里。
  • 代价:可执行文件增大约 25 MB,启动注册约 85–120 ms,其中约 75 ms 是 Viva 暂存时计算的 FNV-1a 哈希。fontfile: name staged fonts by SHA-256 Lithe-IDEA/Lithe-viva#8(上游 perf(fontfile): name staged fonts by SHA-256 vivaui/viva#233)改用 SHA-256,可降到约 8 ms;要等 Viva 固定版本升级后才生效(由用户团队进行;fork feat: enhance native terminal experience #7 已合入,feat(windows): add Windows Qt and Win32 implementation #8 待合)。
  • 资源与文档:worktree-resources.json 的 bundled-ui-fonts 改为新位置(并加了测试断言),docs/ci-builds.md 的字体章节和打包字体 Agent Note(新增“Viva 客户端:字体编译进可执行文件”一节)已同步。.gitattributes 把字体目录标为 -text。
  • 运行时 bundle 只读门禁的测试(test-runtime-bundle-immutability.mjs)在 a4eb41350 加入 installedpackage 检查时没有同步,有两例一直失败。现在夹具补上 installedpackage,并新增一例覆盖“installedpackage 必须只读且必须存在”。
  • 功能矩阵与迁移文档复核(46 个 JSON):按功能矩阵 JSON 和代码逐行复核“必须迁移”各项的现状,“无 desktop/ 证据”改写为主要实现文件。现状为完成 38 / 部分 109 / 未开始 5。未开始的是远程开发两项、构建 Provider 原生配置与只读模型输入,以及依赖 webview、已暂缓的 embedded-viewers。
  • 验证:
    • 全量 desktop-go.sh test -count=1 ./internal/... ./cmd/... 49 个包通过。
    • 通过:macOS vet、Agent Notes 232 条、运行时 bundle 只读检查及其 Node 测试、资源复用测试。
    • i18n:三项检查通过(11651 条,中英完整)。
    • 功能矩阵:255 项。
    • 字体测试:带标签和不带标签均通过。

第十七轮(2026-11-12)“打开所选文件”可改绑,补 F4 测试(ffe9701ea)

  • “打开所选文件”放进快捷键目录:shortcuts.OpenSelected(workspace.openSelected),默认 F4,归在“项目”分组,标题沿用共享词条 keybindings.commands.file.openSelected.title(这一条的 platforms 加上 desktop)。设置的快捷键页可以改绑或禁用它,和其他动作一样做冲突检查。
  • 生效范围:它只对项目树或搜索结果列表里选中的项起作用,所以窗口级的快捷键循环跳过它。树和列表通过 elementShortcut 把用户的有效按键声明在自己的元素上(root.go)。原来写死的 Shortcut(0, "f4") 已删除。
  • 搜索结果 F4(689efc520 已实现,此前没有测试):TestProjectSearchF4OpensTheSelectedMatchAndKeepsItsPlace 覆盖五点:
    • 键盘进入结果列表,用方向键选中第二个匹配,按 F4,在匹配的行列打开;
    • 打开后列表仍选中该项;
    • 改绑到 F7 后,F4 不再打开;
    • 按 F7 打开;
    • 去掉 F4 处理后,测试失败。
  • 新发现:项目树的 F4 从来没有生效过。原因在 Viva:listRowScope 只登记 List 的行范围,没有 Tree 的,所以 Tree 的某一行有焦点时 Box.Shortcut 不触发。
  • 同时记入 [Feature] 在 Lithe-IDEA/viva 补齐输入框禁用/只读、Tree 横向滚轮与行内 label、Splitter 按键路由,移除 Lithe 的对应绕过代码 #1821:macOS 应用菜单不能由应用加“设置…”,标题是写死的英文(第 9 项);输入框会接走不带修饰键的按键,所以查询框里不能用方向键选结果再按 F4。
  • 矩阵:file-open-selected 的说明、证据和验证步骤已按现状改写,仍为“部分”(项目树等 viva#9;查询框 F4 未做)。docs/viva-migration.md 对应行已同步。
  • 验证:gofmt、desktop-go.sh vet ./internal/... ./cmd/... 通过;全量 ./internal/... ./cmd/... 49 包通过、无失败;i18n 三项检查(生成、语言、--check)与功能矩阵生成/校验通过

第十八轮(2026-11-12)本地历史 Diff;快照改存客户端数据目录(019d54dfe)

  • 本地历史窗口新增“与上一条比较”和“与当前比较”,都打开只读 Diff 标签页。实现方式与插件 VCS 的只读 Diff 相同:savedSource 承载 Core diff.compareTexts 的结果,可切换并排/统一视图、查找、折叠。
    • 两侧标签:快照一侧显示时间(有标签时附上标签);当前一侧显示“当前版本”。
    • “当前”取已打开编辑器里的未保存文本;文件未打开时读磁盘,文件已删除时按空文本比较,非 UTF-8 时按二进制处理。
    • 两侧相同时只在窗口里提示“没有可比较的更改”,不打开标签页。标签页打开后关闭本地历史窗口(模态窗口会挡住标签页)。
    • 词条沿用共享的 localHistory.compareWithCurrent、compareWithPrevious、noChangesToCompare 和 native.currentVersion,只给它们加上 desktop 平台。
  • 修复两个问题,原因相同:快照原来写在 <用户配置目录>/Lithe/LocalHistory。
    • 这是旧版 Lithe 的数据目录,新包不应写入(新包与旧 Lithe 并行,旧数据只读导入)。
    • 测试保存文件时也写进这里。本机已有 422 个文件夹(6.3 MB),哪些来自测试无法区分,所以没有删除。
    • 现在改为 <客户端数据目录>/LocalHistory/<项目路径哈希>,与 Shelf 相同。测试用临时 store,因此自动隔离。Viva 预发布版之前记下的历史不迁移(只是预发布数据)。
  • 测试:新增 TestLocalHistoryComparesASnapshotWithThePreviousOneAndTheCurrentText,覆盖五点:
    • 文本相同时只提示、不开标签页;
    • 与上一条比较:只读 Diff,两侧名称正确,Core 给出一增一删;
    • 与当前比较:取编辑器未保存文本(测试关闭自动保存,并断言磁盘上没有这处修改);
    • 快照落在 store 目录;
    • 反向验证:去掉“读编辑器文本”后测试失败。
  • 矩阵 history-snapshots 的说明、证据和验证步骤按现状改写,仍为“部分”。未迁移:本地历史设置(忽略规则、容量、清空)、全项目时间线、手动标记条目。
  • 同时更正剩余工作里过时的 C07 一行:快捷键、网络代理、更新页早已完成。
  • 验证:gofmt、desktop-go.sh vet ./internal/... ./cmd/... 通过;i18n 三项检查(generate、verify-app-language-localization、--check)通过;功能矩阵校验通过;workbench、i18n 两个包全量测试通过(129s);变异检查:把“与当前比较”改成读磁盘文件后新测试失败,恢复后通过

第十九轮(2026-11-12)网络设置页“测试连接”(3b7665e51)

  • 设置 › 网络在自定义代理下新增“测试连接”按钮。检查用的是未保存的草稿,行为与旧 macOS 客户端相同:
    • 地址为空或端口不在 1–65535 时立即提示“请先填写服务器地址和 1 到 65535 之间的端口”,不发请求。
    • 草稿先经 Core network.proxyPolicy 解析,密码规则与保存时相同:新输入的密码随草稿的端点;密码框没改动时取钥匙串里的已存密码,由 Core 校验它属于同一端点和账号;点过“清除密码”就不带密码。Core 得出的不是完整的自定义服务器时按“未填完整”处理。
    • 在独立的 http.Transport 上发一个 HEAD https://github.com 请求,10 秒内必须结束(含 Core 解析),不跟随重定向。200–399 算成功,显示耗时;其他状态码显示“代理返回了 HTTP …”;没有响应时显示“连接检查失败。”加上原因(不带请求地址)。
    • 不使用也不关闭生效中策略的连接,不改动当前策略。
    • 检查在窗口线程之外运行,期间按钮显示“正在测试…”且不可点;“还原”和“应用”会丢弃正在进行的检查和上一次的结果。
  • 代码:
    • netproxy.Check(新增):按策略决定每个请求是否走代理,与应用的请求用同一个 proxyFor(由 Proxy 拆出),因此排除列表同样生效。
    • workbench/network.go:新增 checkNetwork / networkChecker。applyNetwork、setNetwork 和检查共用新的 networkProxyRequest、networkIdentity,不再各自拼请求。
    • settingswindow:新增 Options.CheckNetwork、NetworkCheck 和带锁的检查状态。
  • 词条沿用旧 macOS 的 settings.network.testConnection、testing、connectionSucceeded、checkFailed、enterAddressAndPort、proxyAnsweredWithHTTP,只给它们加上 desktop 平台。
  • 测试(新增 3 个文件):
    • netproxy/netproxy_test.go:用本地 HTTP 代理验证请求经代理并带 Basic 凭据、重定向不跟随、不改当前策略;排除的主机直连;代理关闭时只报原因。
    • workbench/network_check_test.go:用真实 Core 验证新输入的密码、本端点的已存密码、换端点后的已存密码(Core 丢弃密码、保留账号)、已清除的密码,以及没有服务器时不发请求。
    • settingswindow/network_view_test.go:页面流程,覆盖进行中的提示、耗时、状态码、失败原因、还原后清除结果、未填完整时不调用检查、非自定义模式不显示按钮。
    • 反向验证:分别改成跟随重定向、忽略已存密码、还原时不清结果,三个测试都失败;恢复后通过。
  • 新建 [Feature] 代理排除列表的写法解释与匹配下沉到 Core,netproxy 不再自行实现 #1829(refactor):排除列表的写法解释和匹配只在 Go 的 netproxy.Excluded,Core 只去空格,应下沉到 Core。这是旧客户端交给系统网络栈、迁移后落到 Go 的既有债务,本轮不改。
  • 矩阵 network-proxy-settings 的说明、证据和验证步骤按现状改写,仍为“部分”。未迁移:代理认证只有 Basic(旧客户端还支持 Digest/NTLM);旧钥匙串 app.lithe.desktop.proxy 的密码没有可选导入。
  • 验证:gofmt;desktop-go.sh vet ./internal/... ./cmd/...;generate-i18n.mjs、--check、verify-app-language-localization.mjs;平台功能矩阵校验(255 项);netproxy、settingswindow、workbench、i18n 四个包完整测试通过;三项反向验证按预期失败,恢复后通过。

第二十轮(2026-11-12)IDE API 执行语义按契约收齐(4f3765616)

  • 输出分页改由 Core 做:lithe_operation_output 在窗口线程取这次执行的完整输出,交给 Core ideHost.control 的 output 动作(output_page)分页。
    • 每页最多 32 KiB,不拆开字符。
    • 游标是“字节位置:前缀 SHA-256”;控制台裁剪后,旧游标返回 reset: true 并从头读。
    • 删除 Go 里按行号分页的实现,新增 core.IDEHostOutputPage。
  • 失败码只用契约列出的码:
    • 去掉 OPERATION_BUSY、BUILD_MODEL_NOT_LOADED、OPERATION_NOT_RUNNING、NO_PROJECT、CANCELLED。未知工具返回 NOT_SUPPORTED(原为 NOT_AVAILABLE)。
    • Build 窗口拒绝启动时改为返回带码的 buildRefusal(INVALID_ARGUMENTS / NOT_FOUND / NOT_READY / NOT_SUPPORTED / BUSY),工具调用原样报这个码,窗口仍只显示原有提示。
    • 项目未打开返回 WORKSPACE_CLOSED,调用超时返回 TIMEOUT,Core 分页失败返回 OPERATION_FAILED。
  • 执行从受理起就占住 Build 窗口:beginBuildOperation 在计划、保存和提供方请求之前登记执行,所以:
    • 准备期间再次启动(窗口或工具发起)返回 BUSY。
    • 停止立即生效:准备用的上下文随停止取消(buildOperation.bind),已发出的提供方请求在后台取消,停止后才到的请求或进程直接取消,不再挂到这次执行上。
    • 运行配置启动(startRunConfiguration)同样先占住窗口再保存。
  • 状态按契约:preparing → running → stopping → completed / failed / cancelled。
    • 原来只有 succeeded,没有 preparing 和 stopping。
    • 退出码只在执行报告时给出,取消和启动失败时为 null。
    • Build 窗口停止后显示新词条“正在停止…”(desktop.build.stopping),直到执行结束。
  • run_start / run_restart 等执行启动(进程或提供方请求已存在)后再应答,最多等 5 秒。
    • 启动前失败返回 LAUNCH_FAILED 和原因。
    • restart 只接受运行配置的执行,否则返回 NOT_AVAILABLE;执行未结束时返回 BUSY。
  • 执行 ID:项目只保留最新一次执行。
    • ID 格式为 ide-<build|run>-<epoch>-<n>,epoch 在项目每次打开时随机生成,n 是序号。
    • 被替换的 ID 和项目重开前的 ID 返回 OPERATION_EXPIRED,从未发出的 ID 返回 NOT_FOUND。原来旧 ID 可能指到别的执行。
    • 停止只作用于窗口当前的执行。
  • build_configure 等 Core 读回后才应答:
    • 与“构建选项”对话框走同一条 build.editStoredOption,答复 Core 从改后的文档读回的值和来源(user / default / unset)。原来在写入前就按请求值应答。
    • Core 拒绝的值返回 INVALID_ARGUMENTS,不写入。
    • 执行中、模型加载中、对话框打开或正在保存时返回 BUSY。
  • 两处小改动:
    • 过长的输出行改在字符边界截断,原来可能截在 UTF-8 字符中间。
    • runBuildTask 返回它占住的执行,IDE 的执行入口不再从窗口状态里取。
  • 剩余工具的结论:environment 与 Maven 专属工具按契约由插件经通用 Build 入口提供,本客户端不发布。Core ide-api/v1.md 有一段仍说 Windows 提供这两组工具,已记入“合入后”。
  • 测试:
    • 新增 workbench/ide_api_operation_test.go,用真实 Core:
      • 用一个计划永远不返回的内核:工具启动答复 preparing;准备中再次启动、窗口自己的启动和改选项都返回 BUSY;列表和停止在准备中生效;执行结束为 cancelled,退出码为 null;下一次执行后旧 ID 返回 OPERATION_EXPIRED;构建任务不能 restart。
      • 约 120 KB 中文输出经 Core 分页后拼回原文,每页不超过 32 KiB;读到末尾没有新内容,新输出可以续读;控制台裁剪后旧游标得到 reset。
      • 用契约 fixture build-instance-options 的 release 选项:设置后读回 true / user 并写入本地文档;非法值返回 INVALID_ARGUMENTS;设为 null 后来源不再是 user,本地文档被删除;未知选项和未知实例返回 NOT_FOUND;对话框打开时返回 BUSY。
    • ide_api_dispatch_test.go 改写:启动拒绝码表、ID 的当前 / 过期 / 未知规则、状态只结算一次。
    • ide_api_test.go:未知工具和 environment 工具返回 NOT_SUPPORTED。
    • 反向验证:分别改成不判旧 ID 过期、读输出不传游标、停止不结束准备、不用 Core 读回值、启动前不占住窗口,五项都让对应测试失败;恢复后通过。
  • 矩阵:ide-api-run-output、ide-mcp-connection、ide-api-maven、ide-api-environment 的说明、证据和验证步骤按现状改写,状态不变。
  • 验证:gofmt;desktop-go.sh vet ./internal/... ./cmd/...;i18n 三项;平台功能矩阵校验(255 项);全量 desktop-go.sh test ./internal/... ./cmd/... -count=1(50 包)通过;五项反向验证按预期失败,恢复后通过。

第二十一轮(2026-11-12)异常退出遗留进程清扫、停止等待时间与强制结束(5de0940e5)

  • 启动清扫由 Core 决定:
    • 进程台账(processledger)记录 PID 和启动时间,用来防止 PID 复用。上次留下、现在仍在运行的进程,在窗口打开后交给 Core 的 processLifecycle.resolve(startupSweep 上下文)。
    • 运行、构建、调试适配器和插件工具直接结束。终端按设置“意外关闭后遗留的终端”询问或直接结束;确认窗口里可选结束或保留,答案经 processLifecycle.settle 结算。
    • Core 无法给出方案时,全部交给用户决定,不自动结束。原来在插件服务打开时直接弹确认,不经过 Core。
    • 结算之前,记录一直留在台账里;启动中途退出,下次还能找到。StartupLeftovers 和 SettleStartupLeftovers 加了锁,结算在后台执行。
    • 结束改为批量处理:先发 SIGTERM,每 100 ms 检查一次;超过等待时间后,再核对一次进程身份才发 SIGKILL。删除了 Sweep。
  • 停止等待时间:
    • 设置页“进程终止策略”新增“停止程序”卡片,包含等待时间输入框、−/+ 按钮和“恢复默认值”。默认值和范围取自 Core(默认 5 秒,范围 1–60 秒)。Core 没有公开这三个值,桌面端用三次 resolve 探测出来;已建单 [Feature] 停止等待时间的默认值与上下限由 Core 公开,桌面端不再三次探测推导 #1830,让 Core 直接公开。
    • 这个值经 Core 解析后,用于此后停止的每个进程:运行、构建和插件 run 先向整个进程组发 SIGTERM,超时再强制结束(buildprocess.Stop)。原来是直接结束。
    • 新增“意外关闭后遗留的终端”卡片,可选“下次启动时询问”或“下次启动时结束”。
    • 从旧版导入设置时带上 startupSweep 和 gracefulStopSeconds,只取能映射的值。
  • 强制结束:运行或构建正在停止时,停止按钮变为“强制结束”,再点一次立即结束进程。插件 run 第二次停止同样直接结束。IDE API 的停止不升级为强制结束。
  • Windows:停止即结束,没有优雅停止;也没有进程台账,因为没有按启动时间核对进程身份的办法。所以设置页不显示这两张卡片(由 buildprocess.StopsGracefully 和 processledger.Supported 控制)。
  • Windows 测试修复(集中测试阶段 13 个失败中的两项):
    • idehelp 测试在 Windows 上不再检查 Unix 权限位。
    • documentsUnder 测试按平台分隔符构造路径。
    • Windows 机器离线,这两项还没有在实机上复跑。
  • 测试:
    • processledger_unix_test.go(真实子进程):
      • 收到 SIGTERM 就退出的进程在等待时间内结束;
      • 忽略 SIGTERM 的进程在等待时间过后被 SIGKILL;
      • 选择保留时,只从台账删除记录;
      • 启动时间对不上的进程不发信号;
      • 上下文结束时立即返回。
    • buildprocess/process_unix_test.go:Stop 先请求退出、超时再结束;Kill 立即结束。
    • workbench/startup_sweep_unix_test.go(真实 Core 和真实 sleep 进程):
      • 默认设置下,构建直接结束,终端被询问;回答“结束”后终端结束,台账清空;
      • 设置为直接结束时,不再询问;
      • Core 失败时全部询问;选择保留后进程继续运行,台账清空。
    • TestStopTimeFollowsCoreAndTheSetting:读到 Core 的规则 {5, 1, 60};设为 12 秒后生效值为 12 秒;设为 1000 秒时被限制为 60 秒;恢复默认后回到 5 秒。
    • legacyimport:两个新字段的导入,以及无法映射的值被丢弃。
  • i18n:新增 6 条 desktop 词条;7 条旧 macOS 词条加上 desktop 平台后复用。
  • 矩阵:process-termination-policy 和 run-processes-end-with-ide 的说明与证据已更新,状态不变。
  • 验证:gofmt;desktop-go.sh vet ./internal/... ./cmd/...;buildprocess、processledger 按 Windows 目标交叉 vet;i18n 三项;平台功能矩阵校验(255 项);运行时 bundle 只读检查;测试稳定性静态检查;全量 desktop-go.sh test ./internal/... ./cmd/... -count=1(51 包)通过;新增启动清扫测试连跑 3 次通过。

第二十二轮(2026-11-12)补齐已实现功能的回归测试;本地历史设置(d4b766f5d、3dc43e1bc)

  • 回归测试(d4b766f5d)。下面这些功能早已接通,只是缺测试,矩阵说明也过时了:
    • Markdown 预览图片:相对路径和 http(s) 图片都能显示(经 fork lithe 0.1.12 #4),包括 SVG;下载失败时显示替代文字。
    • Git 行号区:跳到上一处、下一处变更,到头后回绕。
    • 通知:四种类型;toast 最多同时显示三条;欢迎页也有铃铛入口。
    • Diff:查找覆盖左右两侧;忽略空白;没有块计划时,右侧的编辑也写入 document。
    • 矩阵:editor-git-gutter-peek、markdown-images-links 改为 implemented;git-diff-review、workbench-notifications 的说明按现状改写。diff_find.go 顺带修了一处判断。
  • 本地历史设置(设置 › 通用 › 本地历史卡片):
    • 已用空间:显示当前项目的历史占用和上限,例如“3.5 MB / 100 MB”,由 Core history.usage 计算。没有打开项目时提示先打开项目。
    • 清空:点“清空项目历史”先弹确认,确认后由 Core history.clear 删除并重新计量。失败时显示原因,可以重试;历史为空时按钮不可点。
    • 容量上限:单位 MB,必须是正整数;留空表示用 Core 的默认值(输入框占位符显示该默认值)。Core 把上限限制在 10 MiB–100 GiB,默认 100 MiB;卡片显示的是 Core 生效后的值。
    • 忽略规则:通配符和正则表达式各占一个多行输入框,每行一条。
      • 输入时由 Core history.ignorePreview 实时检查(200 ms 防抖,过期结果丢弃)。
      • 无效的正则会标出所在行号和 Core 的错误信息。
      • Core 内置的规则只读显示在输入框下方,不并入编辑内容,Go 端不重写 Core 的匹配规则。
    • 测试路径:输入项目内的相对路径,卡片显示结果:
      • 会被记录;
      • 被哪条通配符或第几行正则排除;
      • 是项目树隐藏的路径;
      • 是否被 Git 忽略。
      • 越出项目的路径显示“测试路径必须留在当前项目内”。这是随输入重算的校验提示,不写错误日志。
    • 应用与还原:
      • 应用时每条规则去掉首尾空白、丢掉空行后再保存,然后按新上限重新计量;
      • 还原回到已保存的设置。
      • 设置存在偏好里(localHistory),每次记录快照都随请求交给 Core(HistoryPolicy)。快照仍在客户端数据目录,不写项目,也不写安装目录。
    • 已知差异:桌面端还没有“隐藏文件”设置,所以不发送 hiddenFilePatterns,按 Core 的默认隐藏规则处理。
  • i18n:新增 5 条 desktop 词条(desktop.settings.localHistory.*);26 条旧 macOS 词条加上 desktop 平台后复用。
  • 矩阵:history-snapshots 加了 4 个证据文件和本地历史设置的验证步骤,状态仍为“部分”。还缺两项:全项目时间线、手动标记条目。
  • 测试:
    • settingswindow/local_history_view_test.go(假的 source):
      • 规则逐行原样送给 Core;
      • 标出无效正则的行号;
      • 测试路径的四种结果;
      • 应用时去空白、丢空行,并拒绝非整数上限;
      • 还原;
      • 清空前先确认;取消时不清空;失败后可以重试;
      • 没有项目时的提示。
    • workbench/local_history_settings_test.go(真实 Core):
      • 忽略规则确实让匹配的文件不被记录;
      • 预览能报出命中的规则和正则行号;
      • 内置文件夹规则按内置规则报出;
      • 越出项目的路径返回 invalid_request;
      • 上限 5 MB 被限制为 10 MiB;
      • 清空后占用为 0,上限回到默认 100 MiB;
      • 关闭项目后不再计量。
  • 验证:gofmt;desktop-go.sh vet ./internal/... ./cmd/...;i18n 三项;平台功能矩阵校验(255 项);全量 desktop-go.sh test ./internal/... ./cmd/... -count=1(51 包)通过。

第二十三轮(2026-11-12)Markdown 改为双栏编辑器(15f23670a)

  • Markdown 文件打开后是双栏编辑器,左边源码、右边渲染页,参照 IDEA。去掉了右侧的“Markdown 预览”工具窗口。旧布局里存着这个窗口也不影响,chromeState.apply 会跳过未知的位置 ID。
  • 三态切换:编辑组标签栏末尾、折行开关之前,有“编辑 / 编辑与预览 / 预览”三个图标按钮(RoleRadio,带悬停提示),默认“编辑与预览”。模式按文档记住,切到别的标签再回来不变。
  • 同步滚动:两侧按源码行双向同步。
    • 滚动源码,渲染页跟随;滚动渲染页,源码跟随。用 led 标记避免两边互相回弹。
    • 切换模式时,新显示的一侧接上原来的位置:从“预览”切回来,源码滚到渲染页顶部对应的行;从“编辑”切回来,渲染页跟上源码。
    • 只改宽度、重新排版时,渲染页顶部保持在同一段源码。
  • 目录:渲染页右上角有“目录”按钮,点开是标题弹窗。
    • 标题按级别缩进;列表最高 400 点,超出时可以滚动。
    • 点击或回车选中标题后关闭弹窗,源码和渲染页一起滚到该标题。
    • 文档没有标题时不显示按钮。标题随编辑更新。
  • 不变的部分:
    • 链接跟随:http/https/mailto 交系统打开,相对路径在编辑器打开,锚点滚到标题。
    • 相对路径和 http(s) 图片照常显示。
    • 超过 1 MiB 的文件只显示“文件太大”提示。
    • 点渲染页会把焦点编辑组切到这一组。
  • i18n:editor.markdownSourceView、editor.markdownSplitView、editor.markdownPreviewView 加上 desktop 平台后复用;删除不再使用的 desktop.markdown.noFile、desktop.markdown.title。editor.markdownViewModes 是给整组按钮命名的词条,Viva 没有给控件组命名的接口,所以桌面端不用它。
  • 矩阵与笔记:markdown-rendering、markdown-preview-outline 的说明改为双栏编辑器;归档笔记里“工具窗口的 Markdown 预览”的说法同步改掉。
  • 测试:workbench/markdown_preview_test.go 重写,覆盖以下几项:
    • 源码与渲染页左右各占一半;三态切换;编辑后目录更新。
    • 非 Markdown 文件不出现切换按钮。
    • 目录跳到第 12 节,源码顶部行为 55。
    • 两侧双向同步滚动。
    • 切换模式后保持位置。
    • 链接目标解析;相对链接跟随。
    • 工具窗口拖放与默认布局的测试改用“通知”窗口。
  • 验证:gofmt;desktop-go.sh vet ./internal/... ./cmd/...;i18n 三项;平台功能矩阵校验(255 项);Agent Notes 校验;全量 desktop-go.sh test ./internal/... ./cmd/... -count=1 通过。

第二十四轮(2026-11-12)字体页改为“勾选位置 → 调整 → 保存”(dedb1fde5)

  • 按用户标注改版:先在“各位置效果”里勾选要调整的位置,再在下方调整字体,最右边点保存。
  • 总览:编辑器、终端、运行输出各占一行,行首是勾选框,可多选;每行照旧显示该位置当前生效的字体预览和摘要。
    • 首次打开时,默认勾选与编辑器共用同一套字体的位置。这样不改勾选直接保存,不会拆开原来共用的位置。
  • 调整卡片:只有一张,标题列出已勾选的位置;一个都没勾时,标题显示“未勾选位置”。
    • 行:字体族、预览、字号、行间距(自动时显示所勾选位置各自的实际值)、连字。
    • 修改先作为草稿,不写设置。未修改时,卡片显示第一个勾选位置当前的设置;改过之后,再勾选或取消位置,草稿保持不变。
    • 卡片右下角:“还原”放弃草稿;“保存”把草稿交给所有勾选的位置,未勾选的位置保持原样。没有勾选位置,或保存不会带来任何变化时,“保存”不可用。
  • 去掉了:每张组卡片里的“作用范围”勾选,以及总览里的“单独设置”按钮。“单独设置”按钮无障碍名称相同的已知小问题随之消失。
  • 模型:fontprefs.Assign(fonts, scopes, look) 替换 SetScope 和 Update。
    • 把勾选的位置从原来的组里取出,交给新设置;
    • 清掉已经没有位置的组;
    • 设置完全相同的组合并为一组(SameLook,自动行距视为相同);
    • 存储格式不变,旧的 settings.json 照常读取。
  • i18n:新增 desktop.settings.fontsNoneChecked、desktop.settings.fontsEditHelp;改写 desktop.settings.fontsOverviewHelp;删除 fontsScope、fontsScopeHelp、fontsSeparate;复用 ui.save 与“还原”。
  • 矩阵:editor-font-family 的说明和验证步骤按新流程改写(“保存后生效,打开页面和编辑草稿都不写入”)。
  • 测试:
    • settingswindow/fonts_view_test.go:
      • 默认三个位置都勾选;
      • 取消勾选终端、字号加 2,在保存之前不写设置;
      • 保存后编辑器与运行输出为 15 pt,终端保持 13 pt;
      • “保存”在“还原”右侧,位于卡片最右边;
      • 勾选另一个位置并保存时,沿用第一个勾选位置的字体,并合并为一组;
      • 还原丢弃草稿;
      • 未勾选任何位置时“保存”不可用。
    • fontprefs:TestAssignSetsTheScopesGivenAndJoinsTheSameLook。
  • 验证:vet 与全量 desktop-go.sh test ./internal/... ./cmd/... -count=1(51 包)通过;i18n 三项(11660/11660)、功能矩阵 255 项、Agent Notes 232 篇通过。

交接(2026-11-12,dedb1fde5)

分支已推送,工作区干净,没有遗留的 Lithe、cargo 或 go test 进程。固定版本未变:Core d797244,Viva fork 7850516be532。

下一项是插件后端的 workspace 文件与搜索方法(API-06/07/08:workspace/readDirectory、stat、readFile、watch、findFiles、findText)。代码还没写,已调研清楚的部分:

  • 契约在 Core shared/plugins/contract/v1/README.md 的 “Public document, file and window methods” 一节;Core(plugin_function.rs)只检查权限,语义全部由宿主实现。旧 Swift 实现(PluginFileHostService.swift、MacPluginWorkspaceFileService.swift、MacPluginWorkspaceWatchHub.swift)可作行为参照。
  • 复用 Core:列目录用 ListDirectories(排序、隐藏规则、省略符号链接都归 Core),搜索用 SearchEverywherePage(resultKinds 取 file 或 content;Go 的 EverywhereSearchRequest 要补 FileMask 字段,Core 已支持),解码用 DecodeFileBytes(identity 也由它给出),纯文本判断用 core.ClassifyDocumentText,监听结果过滤用 FilterWorkspaceChanges。这几个方法不在 pluginservice.Kernel 里,用可选接口加类型断言,实现了才注册。
  • 宿主负责的部分:路径逐段不跟随符号链接(Unix 用 openat + O_NOFOLLOW,放进 documentio;Windows 逐段检查重解析点);读文件最多 128 KiB,读 max+1 字节判断是否截断,截断时尾部最多去掉 3 字节再解码;分页默认值与上限是目录 200/1000、搜索 100/200,搜索总数不超过 200;游标为不透明 base64 JSON,绑定 context、generation 和查询;每个调用方最多 4 个并发操作,超过返回 limitExceeded。
  • 监听:pluginservice 不直接引用 Viva,经注入的 watcher 接口调用 app.WatchDirectory / WatchTree,由工作台适配。每个调用方最多 32 个监听,总数最多 256;累计超过 1000 条路径或监听丢失事件时,只发 requiresRescan。通知走 lithe/host/subscriptions/notify,参数 {subscriptionID, sequence, event:{rootID, changedPaths, requiresRescan}},sequence 从 1 开始;订阅登记在 s.resources.add,会话或 context 结束时释放。
  • 写完后要做:补测试(假内核 + 临时目录,等待有上限),跑 vet 与全量测试,更新功能矩阵和本 PR 描述。

剩余工作

Page 迁移(已完成,每个窗口一个 Page;工作台根 Page 见 workbench/root.go):

  • 标签栏隐藏标签菜单的逐行关闭按钮与细滚动条(c862d812c 补回)
  • 真实窗口验收:IME、拖拽手感、高 DPI、Windows 构建

第一轮功能车道(已合入;逐项状态见功能矩阵):

  • Agent:工具时间线、思考、计划、上下文用量、模型调用与轮次统计、额度、子代理监控、斜杠命令、文件引用、中途补充输入、contextLimits;已归档对话;设置 › AI 的 Agents/指令/技能/Hooks 页;回复改用 Viva Markdown 视图;文件树右键“加入 Agent 会话”(第十轮删除)
  • MCP 与 AI:设置 › AI › MCP 配置页(发现 Codex/Claude 原生配置、保格式回写、备份回滚、所有权账本、注册表分页获取)(第十轮删除);Commit 面板生成提交信息;编辑器 AI 行内编辑(Cmd/Ctrl+K,差异审阅后接受);IDE broker 的 Core 封装
  • Git:Diff 对话框(块级暂存/回退)、Push 对话框、Stash/Worktree/仓库工具、Blame 对话框、未跟踪目录、回滚确认
  • 编辑器:行操作、跳转后退/前进、References 面板、Structure(documentSymbols)、语义高亮、按编码打开/保存、LSP 状态与日志窗口、Markdown 预览、右键菜单;editorview 行号区装饰/点击回调/行尾注释接口
  • 运行调试:变量分页/修改/JSON 视图、异常断点、反汇编窗口、普通单步与指令级单步、只读内存、线程列表与切换、求值与监视、调试 TCP 传输按 Core 生命周期驱动、插件 debug/start、退出前确认运行中的程序、执行 PATH 走 Core
  • 测试稳定性:workbench 插件后端初始化超时可配置(负载下不再超过 Core 10s)

第二轮功能车道(已合入):

  • Git 续:行号区变更标记、内联 blame、.git 元数据监听替换 internal/gitmetadata、文件树右键菜单(Git 操作、新建/重命名/删除)
  • Git 续:行历史(683f2d51a)、本地变更列表(changelists*.go)、多仓库分组(409a1cc2f)、Rebase 计划编辑(第八轮历史改写)、worktree 检出已有分支(gitworktree.go)、Diff 内搜索与忽略空白(51858fd8d)、Diff 右侧可编辑(683f2d51a、48f1e39a4)、Diff 词内高亮(6256f1fa1)、Diff 分隔行分步展开(683f2d51a)、Shelf(第十三轮)
  • IDE API:ide-mcp-connection(连接设置页、授权、broker 循环)
  • IDE API 剩余分发:Run 配置(run list/start/restart)与 build_configure 已分发,执行语义按契约收齐(第二十轮);environment 与 Maven 专属工具按契约由插件经通用 Build 入口提供,本客户端有意不发布
  • AI 设置补全:提交信息与行内编辑的生成选项、共享指令页、技能页查看与搜索、Hooks 搜索与删除确认、已归档对话搜索/服务商筛选/本地移除
  • 需要 Core 补:Lithe-core-rust#10 已合并(9e2e6f8),见下列清单
  • 运行调试续:step filters(56fea1512:设置卡片、启动携带、调用栈折叠)、debug.target: launch(d3474bba7)、startDebugging 子会话(需多会话调试窗口,宿主暂不声明该能力)、运行配置发现与编辑面板(50b5bce5a 发现/选择/带保存选项运行,b2d103950 编辑对话框:参数/工作目录/环境/保存范围,经 updateOptions 冲突检查后原子写回;providerRunOptions 编辑与 JDK/Maven 选择待做)、异常退出遗留进程清扫(第二十一轮;仅 macOS,Windows 没有进程台账)
  • 编辑器续:Markdown 预览相对/远程图片(经 fork lithe 0.1.12 #4 绘制,第二十二轮补测试;上游 [API] Draw images in Markdown with host-supplied bitmaps vivaui/viva#220 合入后随 fork 同步)

需要 Core 补(Lithe-core-rust#10 已合并,桌面已固定到 9e2e6f8):

  • JAVA_HOME:不是 Core 缺实现,而是契约漂移。fix(epic,core,macos): 把 Java 专属逻辑全部移出 Core 与 macOS 宿主,改走通用插件 API #1791 后 JDK 由插件工具链选定、桌面 applyToolchainSelection 注入;execution.resolveEnvironment 契约与 fixture 改为与工具无关的合并语义,Core 测试执行 fixture,桌面端去掉 skip 和无效字段
  • debug.adapters.startArguments 接受后端 configuration 并返回合并后的最终参数,桌面删掉 Go 端合并
  • 终端忙闲:Core 的 processLifecycle.resolve 本就收 idle,缺的是桌面探测——localshell.Shell.Busy(Unix TIOCGPGRP、Windows 子进程),退出/关闭项目/关闭标签页都会确认忙碌终端
  • _meta.lithe.claudeDesktop:契约已有,补共享 fixture shared/fixtures/agent/claude-desktop-cards-v1.json(六种卡片,Host 逐例重放);桌面端绘制卡片仍未做,见功能缺口
  • 内存字节版编解码:新增 text.decode/text.encode,桌面不再为编解码写临时目录
  • Markdown 结构化输出:取消。换成 Core(Comrak)解析不能让图片显示,缺口在 Viva 的绘制能力(见 [API] Draw images in Markdown with host-supplied bitmaps vivaui/viva#220);数学、Mermaid 同理,等上游渲染能力

与旧客户端的行为差异(已知,后续按需补):关闭确认问运行中的程序和忙碌终端(合并成一次确认,不逐个问、不能跳到终端;exec 替换后的 shell 和 Windows 上的 WSL 终端读作空闲);调试会话静默结束;Markdown 预览不渲染 HTML、数学、Mermaid;按编码重新打开时有未保存修改直接拒绝;引用改为面板;inline blame 只标光标行且不提供行号区菜单中的 annotate/close。

功能缺口:

  • C05 插件工具窗口(ui 1 文本、ui 2 包内网页)与 Web 页面桥接
  • C05 剩余:build.* 桥接方法(本宿主不向页面提供构建系统);插件声明的窗口图标(暂用通用图标);ui.commands 入口;ui 3 原生树/列表;页面摄像头/麦克风授权;真机验收(web-panel 夹具显示、CSP 拦截、主题切换、状态往返)
  • C06 SVN provider(宿主窗口已在第十五轮接入,待真实插件验收)、快捷键导入、Go/PHP/Lua executionProviders 入口
  • C07 设置页:进程终止(bb72e44e0;遗留终端与停止等待时间见第二十一轮)、快捷键(bd2350c89 集中目录 + Keymap 页)、网络代理页与“测试连接”(第十九轮)、更新页(Viva update)已完成;剩余:代理 Digest/NTLM 认证、自建更新通道的发布侧、AI 待定、构建工具栏选项(Maven profiles/settings/offline、Gradle offline/userHome)改为插件拥有的 settings2
  • Maven/Gradle settingsChanged 通知;java.project.sourcePaths / classpath 由构建插件提供
  • 插件后端:debug/start 的 launch 目标、{kind:"tool"} 启动走工具链解析(第十六轮)、editor/registerActions、registerProviders(第十六轮补 CodeLens 路由;foldingRange 未路由,Core 拒绝注册)、preview/openHTML(依赖 webview,暂缓)、workspace 文件与搜索方法(设计见上方“交接”)、卸载时清理凭据(Windows 凭据 2560 字节上限与契约 16 KiB 不一致)
  • Java 端到端:运行 main、断点命中(Java 支持插件全流程已实测通过;rust-core、Java 插件、插件市场均在 Lithe-IDEA 组织仓库)
  • 统一通知中心(toast 消失后可回看):状态栏铃铛+未读数、历史面板(最多 100 条)、同文案合并计数(6a241bf0a)。四种类型、最多三条 toast、欢迎页入口已接通并在第二十二轮补测试;悬停或聚焦时暂停计时由 Viva ui.Toaster 提供
  • 右键菜单盘点出的整体缺失功能(见第九轮):运行配置浏览列表(第十四轮;批量选择与并发运行、服务地址提示未做:前者需按配置的独立运行会话,后者需先把端口规则放进 Core)、插件 VCS provider 工具窗口(第十五轮;Annotate、单文件历史、gutter、元数据监听、fileOperations、项目树状态、ownerOf、VCS 控制台输出、冲突另一方、历史条目 Diff、authenticate 未做)、Shelf(第十三轮)、调试线程暂停/继续及监视行内编辑(第十一轮)、构建窗口测试入口(第十二轮)、依赖排除
  • 迁移清单 docs/viva-migration.md 其余“必须迁移”项(AI、编辑器、扩展、运行调试、版本控制、工作区等);“放弃”19 项已确认,另有“放弃:Agent 对话”38 项(2026-11-12)
  • 旧数据可选导入(用户在新包中主动触发,只读旧来源,不改不删旧数据;不是首个预发布的前提):全局插件设置、Windows 最近项目(localStorage)、未保存恢复、本地历史、会话、快捷键;已完成:插件凭据(macOS)、应用偏好与最近项目(e37e104bc,齿轮菜单“从旧版 Lithe 导入设置…”,macOS 读 defaults export、Windows 读 Tauri store,逐项勾选、读回校验;日志目录有意不导入)、旧版插件清单(648327a52,列出未装插件并跳转市场重新安装,不复制旧包;旧启用状态不导入)
  • 打包发布:新应用标识 app.lithe.viva(新产品,与旧 Lithe 并行安装,不做原地升级;旧 Lithe 停更到迁移完成)、签名、自建更新通道(不衔接旧 Sparkle 链)、新包自身的更新与回退演练
  • 功能矩阵盘点(91f2d83fc):原 116 项“尚未盘点”全部按 desktop/ 代码定状态与证据;macOS 现为 implemented 28、partial 124、missing 69、plugin-provided 24、platform-specific 10(共 255 项)。迁移文档“放弃/不纳入”的记 missing 并注明决定;部分实现的缺口写在各项 notes,作为后续补齐清单
  • Linux CI 失败修复(182f91a3e):Linux/Windows 上 Viva 自绘的窗口“Close”按钮被测试辅助函数误当成对话框按钮,TestClosingABusyTerminalTabAsksFirst 自 05:11 起在 Linux 失败;查找时跳过标题栏按钮图层
  • Viva 升级到 b680a1c(9d8f1edbe,第六轮改为 fork 7edac95):页面浮层与声明式表单字段、ScrollArea 横向滚动、Flow、等宽单元格按字体度量、制表符号按单元格几何绘制、浮层按键与 ScrollAt 滚轮修复;macOS vet、viva vet、全量 50 包通过
  • Windows 全量复验(lithe-dev,9d8f1edbe):vet 通过;测试 45 包通过、5 包 13 个失败,留到集中测试阶段修——8.3 短路径 ADMINI~1 与长路径不等同(localshell 终端目录、pluginservice 工作区、IDE API 配置)、mcpconfig 测试期望 / 分隔(第十轮随 Agent 对话删除)、idehelp 期望 Unix 权限位(第二十一轮)、workbench 附件拖放/插话文件为空(同上删除)、远程调试确认与运行输出链接 20s 超时、documentsUnder 返回 0(第二十一轮,测试按平台分隔符构造路径;两项待实机复跑)
  • Claude Desktop 卡片(4a082940d):章节、建议回复、建议任务(在新对话中开始)、PR、目录;可视化只显示源码,渲染待 Viva fix(windows): 降低编辑器输入热路径开销,避免每键全文同步造成卡顿 #209–[Bug]windows平台下同时存在前端项目与JAVA项目时无法启动 #211
  • 工作方式(2026-11-11 起):先大批量写代码,只保证编译;测试、文档、功能矩阵、i18n 门禁与 CI 在代码写完后集中处理。三条车道并行:AI/Agent、版本控制+工作区、运行调试+扩展/插件;合并方写工作台/搜索/设置
  • 原生 GUI 验收(macOS / Windows,按阶段手动清单)
  • 本地历史剩余:全项目时间线、手动标记条目
  • 已建单尾项:[Feature] 将 Viva 项目树可见行和导航规则下沉到 Rust Core #1800、[Feature] 将 Viva Git Log 提交改动文件的文件夹分组下沉到 Core #1814、[Feature] Viva Git Log 分支面板改用公共树列表 desktop/internal/treelist #1815、[Feature] Viva 桌面端 13 项已接通功能缺少自动化测试(Vim、本地历史、GitHub PR/检出/设备授权、更新、代理等) #1828(13 项已接通功能缺少自动化测试;本地历史比较与代理已补)、[Feature] 代理排除列表的写法解释与匹配下沉到 Core,netproxy 不再自行实现 #1829(代理排除列表规则下沉 Core)、[Feature] 停止等待时间的默认值与上下限由 Core 公开,桌面端不再三次探测推导 #1830(停止等待时间的默认值与上下限由 Core 公开)

合入后:

  • lithe-plugin-docs 运行 contract.mjs sync 同步契约:该仓库已退役(feat(plugins): 插件契约统一基线 0,契约与开发资料只在 Rust Core #1826),契约只在 Core shared/plugins/,此项作废
  • 插件 SDK(Node)在宿主不提供 litheLogging 时降级运行,解决 Cargo 0.1.3 在旧客户端起不来
  • Core rust/contracts/ide-api/v1.md:旧 Windows 客户端随本 PR 删除后,改写其中仍说 Windows 提供 environment 与 lithe_maven_* 工具、尚未发送 toolExposure 的段落(d797244 的 Windows 段)

Viva 上游(不阻塞功能开发,合并后升级):

编辑器性能基线(根窗口改为 Page,79997457f → a816b77,M4,--count 6)

110 项中 107 项在预算内。超预算 3 项是 SyntaxFullPass go/java/markdown 100KiB,改动前已超(本次 +2%~+5%),不是本次引入。绘制、滚动、光标移动仍为 0 allocs;ViewPaint −10.6%~+3.9%,ViewType 在 ±0.3% 内。ViewPrepareReload 与 Memory 耗时 +5%~+23%,分配不变;本次只给 editorview/termview 各加了一个 Bind,未触及这两条路径,按噪声记录,下次空闲机器复测。本轮改动编辑器绘制(gutter 标记、blame 注释)后再复测并更新数字。

光标历史改动(190c8252e)前后各跑一次 editor-bench.sh run:112 项中 109 项在预算内,超预算的仍是同样 3 项既有 SyntaxFullPass(go/java/markdown 100KiB),非本次引入;EditorViewUndoRedo 100KiB 50.1→49.3 µs、10MiB 46.8→47.1 µs,EditorViewType 在噪声范围内,无新增超预算。

字体改动(editorview/termview 改为按字体绘制)前后各跑一次 editor-bench.sh run(M4):70 项全部在预算内,分配全部不变,绘制仍为 0 allocs;耗时变化 −1.5%~+5.8%,多数在 ±2% 内。最大的是 PrepareReload/json/10MiB +5.8%、Open/java +4.7%/+3.5%,这两条路径未触及字体代码,且运行时机器上有其他编译任务,按噪声记录,下次空闲机器复测。

Diff 标签页改为双编辑器(editorview 新增 diffdecor.go,paint.go 接入行着色、行号标签与居中;gutter.go 注释图标与横线;scrollbar.go 可隐藏纵向条)前后各跑一次 editor-bench.sh run --count 6(M4,基线为 6f976b293 工作区):112 项中 109 项在预算内,超预算的仍是既有 3 项 SyntaxFullPass(go/java/markdown 100KiB,本次 +0.1%~+1.8%),非本次引入;分配全部不变,绘制、滚动、光标移动仍为 0 allocs。首轮 ViewPaint cjk/mixed 显示 +6%~+16%,但单次样本 26~40 µs 波动明显;单独以 --count 10 复测 ViewPaint plain/go/cjk/mixed,全部在 −0.2%~+4.3% 内,按噪声记录。PrepareReload/log/10MiB +9.1%、PrepareReload/json −11%~−20% 未触及本次代码,同为噪声。

Diff 词内高亮(6256f1fa1,editorview 新增行内范围底色)前后各跑一次 editor-bench.sh run(M4,基线为 6256f1fa1^ 的独立工作树,--count 6):改动前后均 70 项全部在预算内,分配全部不变,绘制、滚动、光标移动仍为 0 allocs;ViewPaint −0.5%~+8.3%,多数在 ±1% 内。变化较大的 Memory/markdown/10MiB +31%、PrepareReload/log/10MiB +17% 未触及行内范围代码(没有设置行内范围时绘制只多一次空切片判断),且分配不变,按噪声记录。

验证方式

每个改动跑相关包测试、gofmt、vet,以及仓库门禁(i18n 三项、功能矩阵、Agent Notes、运行时 bundle 只读、测试稳定性)。macOS/Windows 全量测试与原生 GUI 验收在阶段收尾时进行。改动编辑器模块时按 AGENTS.md “编辑器性能”一节做前后基线对比。i18n 测试需单独运行,与全量 Go 测试并行时曾出现 gofmt 子进程卡住(重跑即通过)。

本轮实测(2026-11-10):

  • cd desktop && ../scripts/desktop/desktop-go.sh vet ./... 通过;viva vet ./... 0 条。
  • 全量 desktop-go.sh test -count=1 -p 4 ./...:47 个包通过。
  • i18n:generate-i18n.mjs --check、verify-app-language-localization.mjs、test-i18n.mjs(41 项)通过。
  • 功能矩阵:change gate 通过,verify-platform-feature-matrix.sh 254 项通过。
  • verify-agent-notes.sh 232 篇通过;verify-runtime-bundle-immutability.sh 通过。
  • 打包:package-desktop.sh --no-sign --format app 成功,bundle 内无 lithe-mcp 文件,嵌入字节与暂存辅助程序逐字节一致,生成文件已清理。

Linux CI 修复(2026-11-11,d8e0888c0、f2e21e1f5):

  • gofmt:自 11-10 起 Desktop CI 每次失败,根因是 CI 按 go 1.26.0 安装 Go,本机是 1.27.3,两版对长 map 键对齐不同。desktop/go.mod 加 toolchain go1.27.3,setup-go 读取该行。
  • 平台相关测试:欢迎页“显示于文件管理器”文案抽成 welcomeRevealLabel(),Search Everywhere 快捷键测试改用 primaryModifier()(原测试写死 macOS 文案与 Cmd)。
  • 竞态测试:插件后端会话测试改为等 functionsChanged 与 ready 都到;调试内存测试两次单步都等到 paused 已应用。
  • 本机验证:全量 desktop-go.sh test -count=1 -p 4 ./... 通过;修复的两个竞态测试分别 -count=40、-count=20 全过;i18n、功能矩阵、测试稳定性门禁通过。
  • 观察项:TestStashTabMakesShowsPopsAndDropsStashes 在 859bd469c 的 CI 上失败过一次,此后 9 次 CI 与本机 -count=30 均未复现,未做推测性修改。

此前各节点的详细交接记录见本 PR 描述的编辑历史。

@ghfind-review ghfind-review Bot added the review: high ghfind author score; see https://ghfind.com label Nov 7, 2026
@xiaoyumuxi xiaoyumuxi changed the title feat(desktop): #1794 Viva 桌面客户端外壳:欢迎页、工作台外框、日志与诊断窗口 feat(desktop): #1794 Viva 桌面客户端:工作台、Git 提交与分支、打包发布,并删除旧内核与旧客户端 Nov 8, 2026
@xiaoyumuxi xiaoyumuxi changed the title feat(desktop): #1794 Viva 桌面客户端:工作台、Git 提交与分支、打包发布,并删除旧内核与旧客户端 feat(desktop): #1794 Viva 桌面客户端:工作台、Git 提交与分支、编辑器引擎、三平台打包发布,并删除旧内核与旧客户端 Nov 8, 2026
@1lck 1lck changed the title feat(desktop): #1794 Viva 桌面客户端:工作台、Git 提交与分支、编辑器引擎、三平台打包发布,并删除旧内核与旧客户端 feat(desktop): #1794 基于 Viva 的跨平台工作台迁移(进行中) Nov 9, 2026
1lck added a commit that referenced this pull request Nov 10, 2026
- core: git.write 在请求带进度观察者时订阅 Core 事件流,解析 progressDetails
  (阶段、阶段百分比、对象计数);新增 WithGitProgress 与 GitFetchSettingsOf
  (包装只读的 git.executionInspect)。
- workbench: 同步状态行显示当前阶段名、百分比和进度条,高频事件合并后再投递
  到 UI 线程,取消沿用原按钮;Fetch Options 对话框打开时读取仓库
  lithe.fetch.* 与应用默认值作为当前值,并显示实际标签行为,读取完成前不可提交,
  打开对话框不写任何文件;配置无效或读取失败时说明原因并显示默认值。
- i18n: 补齐阶段名、进度、设置提示和标签行为的中英词条并重新生成。
- 功能矩阵:更新 git-branches-remotes 的 Viva 验证说明。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1lck added a commit that referenced this pull request Nov 10, 2026
克隆对话框、插件审核与提示、Search Everywhere、跳转行列、语义弹窗(引用/补全/悬停)、
重命名对话框和窗口通知改为同一个 overlay Page:ui.Modal/ui.Dialog、ui.List、ui.Toasts。
删除 Frame 绘制、手写 Tab 循环和 focus 还原;窗口输入统一经 pages_input.go 路由到 Page。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1lck added a commit that referenced this pull request Nov 10, 2026
欢迎页改为整屏 Page:ui.TextField、ui.Button、ui.Menu(更多)、ui.List 加 ContextMenu 与行内菜单;
最近项目分支读取改为 Page 的 Effect。Find in Files 改为面板 Page:ui.TextField、ui.Popover
选项、ui.List 结果列表,刷新按钮并入面板。删除 Frame 绘制、手写菜单与焦点、列表虚拟化。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1lck added a commit that referenced this pull request Nov 10, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1lck added a commit that referenced this pull request Nov 10, 2026
改用 Popover 挂在窗口顶部居中(y=84)的锚点上,不再有遮罩;标签页、查询框、结果列表放进浮层,
点击外部关闭并把点击交还给下面的界面。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1lck added a commit that referenced this pull request Nov 10, 2026
- Commit 工具窗口是嵌在面板 Slot 里的 Page:工具栏、变更列表、提交区用 ui.Scroll、
  ui.Checkbox、ui.TextArea(绑定项目持有的 text.Editor)和 ui.Splitter,评审用 ui.ModalWith;
  Primary+Enter 提交改为 Box.Shortcut,删除 app.go 里按 commitMessageID 的快捷键、滚轮和文本输入分支。
- 分支弹窗、分支对话框和同步(Fetch 选项、分叉)对话框是一个覆盖整窗的 overlay Page,
  在窗口 Frame 绘制之后绘制;弹窗用 ui.PopoverWith,行菜单用 ui.Menu,对话框用 ui.ModalWith,
  标题栏分支按钮仍由 Frame 声明(branch_chrome.go),弹窗锚在它的矩形上。
- 新增 git_pages.go 集中路由 Pointer/Key/Shortcut/Wheel/TextInput,app.go 只加调用点。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1lck added a commit that referenced this pull request Nov 10, 2026
- 日志页是嵌在 Git 面板 Slot 里的一个 Page:引用面板用 ui.Tree,提交列表用 ui.List(行用
  ui.Control 之外的 Draw 回调沿用 gitgraph.go 的图、文字与标签绘制),详情区的变更文件用带
  RowWidth 的 ui.List(左右键用容器的 Shortcut 展开/折叠),分隔用 ui.Splitter,
  过滤弹层用 ui.PopoverWith,操作菜单用 ui.Menu,同步状态行与取消按钮用 ui.Progress/ui.Button。
- 删除 paintGitLog/captureLogFiles/logKey/logFilesPointer 与 beginFrame/capture 的后绘制与手写分发,
  提交列表上下键、选择和滚动交给 ui.List;折叠和选中状态仍在 project.log。
- 原先在面板头里的“显示全部”和 ⋮ 操作菜单并入过滤栏(头部由外壳绘制);⋮ 放在过滤栏最前,
  窄面板不会把它裁掉。
- 把对话框、弹层、过滤栏、键盘与侧向滚动补成测试,并让手写滚动逻辑只在水平分量占优时才侧向滚动。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
诊断输出指出了两条真实原因:

- 远程确认测试里失败信息是 “plugin package path is not usable: "adapter" does not exist”:
  debugPluginHarness 没像 debugHarnessWith 那样把清单里的 packaged path 换成 adapter.exe,
  而拷贝的测试二进制在 Windows 上就叫 adapter.exe,于是启动前就被拒绝。
- Run 输出链接测试里文档路径是正斜杠、目标路径是反斜杠,字符串不同但同一个文件。
  winpath.Equal 改为在 Windows 上把两侧展开长名后统一用 / 分隔符并忽略大小写比较。

本机 vet 通过,winpath 用 GOOS=windows 交叉编译通过。

Co-Authored-By: AtomCode (deepseek-v4.1-flash) <noreply@atomgit.com>
This was referenced Nov 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

review: high ghfind author score; see https://ghfind.com

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants