Skip to content

feat(vcs): macOS 宿主接入插件 VCS Provider,SVN 改为独立社区插件(#827 P3) - #1441

Merged
xiaoyumuxi merged 9 commits into
previewfrom
feat/827-svn-host
Oct 23, 2026
Merged

xiaoyumuxi merged 9 commits into
previewfrom
feat/827-svn-host

Conversation

@xiaoyumuxi

@xiaoyumuxi xiaoyumuxi commented Oct 23, 2026 •

Copy link
Copy Markdown
Collaborator

概要

Issue #827 第三阶段(P3)的第一部分:macOS 宿主接入插件 VCS Provider。装上 Subversion 社区插件后,Lithe 能识别工作区里的 SVN 工作副本,在左侧“Subversion”工具窗口里查看变更、勾选提交、更新、回滚、标记冲突已解决、清理,查看文件和工作副本的历史,与基线比较;项目树按 SVN 状态着色,项目树里的重命名、移动交给 Provider(svn move)记录。

SVN 插件不再放在主仓库,改为像 Cargo 插件一样的独立社区插件:Lithe-IDEA/lithe-plugin-svn,插件 ID io.github.lithe-idea.svn-support,vendor.signatureRequirement 为 none(不需要 Lithe 签名)。原来放插件的 #1432 已关闭,其中与具体 VCS 无关的部分并入本 PR。

本 PR 的 base 改为 feat/827-vcs-provider-core,合入顺序为 #1430 → 本 PR(#1430 合并后 base 改成 preview)。宿主里没有任何 VCS 或插件名字的分支,界面看 Provider 协商的能力决定显示什么。

相对上一版(114dcc1be)的变化

评审过上一版的话,先看这一节。

1. SVN 插件搬到独立仓库

  • 不再包含 Plugins/mac/Official/SvnSupport/、rust/lithe-core/tests/plugin_sdk/svn.rs,以及 verify-rust-core-crates.sh 里运行 SVN 插件测试的步骤。主仓库 CI 不需要装 svn。
  • 也不再包含 feat(svn): Subversion 官方插件 Provider(#827 P2) #1432 为“官方 SVN 插件”做的配套改动:OfficialPluginCatalog.Entry 改成可选 language、LSPControlCenterView 跟着改、ModuleRuntimeTests 的断言、Rust plugin_sdk 测试辅助函数的搬动。这些只在 SVN 是官方插件时需要,现在和 feat/827-vcs-provider-core 保持一致。
  • 插件仓库内容:Provider 源码、录制的 svn --xml 样例与错误输出、解析测试、sdk.lock.json 按上游提交和逐文件 SHA-256 固定 Node SDK、按同一宿主提交构建 Core 跑的端到端场景测试(状态、提交、过期提交、更新与冲突、resolve、回滚、移动、删除、历史分页、Annotate、二进制文件、changelist),以及 CI 和 Release 工作流。暂未打 tag、未发 Release,也没有向 Lithe Store 提交索引。
  • 插件仓库这次额外修了两处:
    • 在 changelist 里的文件原来不会出现在状态里(svn status --xml 把它们放在 <changelist> 下,与 <target> 同级),现在会照常列出。
    • 移动未版本化文件时改为不覆盖已有的目标文件或目录,目标已存在时报 svn.move.destinationExists。

2. 从 #1432 并入的通用部分

  • ModuleID.vcsProvidersExtension(_:) 与 LanguageExtensionModuleManifests.vcsProviders(...):每个声明 vcsProviders 的插件生成一个 <插件 ID>.vcs-providers 模块,默认不启用,启用状态随插件。
  • DeclarativePluginDescriptor 读取清单的 vcsProviders(只读 id 和 displayName),为每个 Provider 生成工具窗口和命令贡献。
  • 契约 shared/contracts/vcs-provider-v1.md:示例里的插件 ID 改为 io.github.lithe-idea.svn-support;lsp.vcsRequest 示例的键名改为实际使用的 sessionId、operationId;“Subversion provider notes”改为指向社区插件仓库,详细映射看插件 README。
  • sdk/node/examples/sample-vcs/provider/main.mjs 注释里的“官方 Subversion 插件”改为“Subversion 社区插件”。
  • Plugins/mac/README.md 新增 “Subversion community plugin” 一节,说明插件独立维护发布、需要宿主声明 vcsProviders、SVN 的样例和 Core 兼容测试在插件仓库,主仓库只保留通用契约测试和 SDK 样例 Provider。

3. 测试不再依赖 SVN 插件

  • VcsProviderHostTests 用契约自带的 fixture 清单(shared/contracts/plugins/v1/fixtures/svn-provider.plugin.json)测真实 Rust Core 的根识别、归属、回复校验和安装审核。
  • PluginManagerTests.vcsProviderPluginGetsOneDisabledModuleForItsProviders 用 SDK 样例 Provider(sdk/node/examples/sample-vcs/plugin.json)验证 Core 接受 vcsProviders 插件,并且只生成一个默认停用的模块。
  • 上一版描述里写的 VcsProviderProjectMoveTests 实际名为 VcsProviderAppModelTests(同一文件),这次补了关闭窗口的用例。

4. 自审和评审修正(f76025c18)

  • 包住工作区的工作副本也会刷新:打开的目录位于某个 SVN 工作副本内部时(根是 .. 这类上层目录),工作区的文件监听看不到上层 .svn,在终端里提交或更新后工具窗口不刷新。现在 VcsProvidersFeatureModel 为这类根单独监听 Provider 声明的元数据目录(只监听 .svn,不监听整个上层工作副本);监听丢事件或目录消失时按标记变化处理,重新识别根。工厂由 MacServiceContainer 注入 MacDirectoryWatcherFactory。
  • 移动两端都要归同一个根:项目树移动交给 Provider 前,先按 Core 的归属规则(vcs.ownerOf)确认源和目标都属于这个根。目标落在嵌套的 Git 仓库里,或者落在还没选 VCS 的歧义目录里时,不再当成 svn move,退回普通的磁盘移动。
  • 关闭窗口后 Provider 不会被重新拉起:shutdownProjectSession 调用新的 VcsProvidersFeatureModel.shutdown(),停掉这个窗口的所有 Provider 和待执行的刷新。修了一个竞态:窗口关闭时还在进行的工作区扫描结束后会调用 loadVcsProviders,以前会把 Provider 重新启动;现在 shutdown() 之后的加载请求一律只清空。关闭的会话模型不会被复用,所以不需要恢复入口。
  • 工具窗口图标:Provider 的工具窗口和命令面板项沿用宿主的版本控制图标(PluginUIIcon(host: "git")),以前侧栏按钮显示的是通用插件图标。
  • 首次读取状态时显示“正在读取更改…”:第一次读取还要启动 Provider 进程,可能要几秒,以前这段时间是空白。
  • 辅助功能:变更行合并成一个辅助功能元素后,VoiceOver 只能勾选。现在补了选中状态,以及“选择”(默认操作)、“显示差异/打开文件”、“纳入提交”三个操作;“显示差异”还是“打开文件”和双击的规则一致(新提取的 opensDiff)。
  • 新增测试:watchesTheMetadataOfAWorkingCopyThatEnclosesTheWorkspace、providerWindowsShowTheVersionControlIcon、closingTheProjectWindowStopsTheWorkspaceProviders;movesTrackedItemsThroughTheProviderAndLeavesTheRestToTheDisk 补了目标落在嵌套 Git 仓库时退回磁盘移动的用例。
  • Agent Note、能力版本 Note 和功能矩阵同步更新:记录社区插件的决定和不采用“官方插件留在主仓库”的原因,以及上面几条宿主行为。

完整改动

宿主能力与安装审核

  • PluginManifest.hostCapabilities 声明 vcsProviders: [1],Core 从此接受声明了 vcsProviders 的插件。
  • PluginProgram 新增 packagedVcsProvider、systemVcsProvider、runtimeVcsProvider 三种程序类型,以及 vcs、vcsClientCommands、entry、runtimeArguments、mayUseNetwork 读取方法。
  • 安装确认页显示 Provider 的启动命令、客户端命令(如 Client: svn)和“可能连接仓库服务器”,用户批准前就知道插件会运行哪个程序。

Provider 进程与 Core 调用

  • VcsProviderContracts.swift:宿主侧的 VCS 操作(状态、提交、更新、回滚、标记已解决、清理、历史、基线内容、文件操作)、回复模型、Provider 错误、工具窗口贡献 ID 与可见性键。
  • RustVcsOperations:封装 vcs.detectRoots、vcs.ownerOf、vcs.decodeReply,根识别、文件归属和回复校验都由 Rust Core 决定。
  • RustCoreBridge.lspVcsRequest / LanguageServerRuntimeCore.requestVcsProvider / LanguageServerSession.vcsRequest:经 lsp.vcsRequest 发送一个 VCS 操作并等待 requestCompleted。
  • RustDeclarativePluginOperations.vcsProviderLaunchPlan 与 MacPluginLanguageServerLaunchResolver.resolveVcsProvider:展开 Provider 的启动计划,校验插件包内路径,在插件状态目录(Application Support)下为每个 Provider 建 ${stateDir} / ${workspaceStateDir},不写 app bundle 和插件包。
  • MacVcsProviderSessions:每个“插件 × VCS × 工作区”一个进程,第一次请求时启动,切换工作区、停用或替换插件时停止;插件设置变化后下一次请求重启。VCS 客户端(如 svn)单独解析并在每个请求里传给 Provider。

功能模型

  • VcsProvidersFeatureModel(按窗口创建;启动时有插件声明 vcsProviders 才创建):
    • 打开工作区时识别根,记录歧义目录;用户选择的 VCS 由 MacVcsRootMappingStore 按工作区存进应用偏好(Vcs.RootMappings.<摘要>),不再歧义时自动删除。
    • 读取每个根的状态,嵌套 Git 仓库和工作区外的变更不进项目树。
    • 文件变化合并约 0.8 秒后刷新受影响的根;元数据目录里只有 Provider 声明的 metadataPaths(SVN 是 .svn/wc.db)会触发刷新,宿主自己的操作期间和结束后 2 秒内忽略元数据变化;出现或消失标记目录时重新识别;包住工作区的工作副本单独监听其元数据目录。
    • 提交、回滚、更新、标记已解决、清理、移动同一时间只运行一个,结束后刷新状态;Provider 错误码按契约给出中文提示(认证失败、工作副本过期、冲突、锁定、格式不支持、客户端不可用)。
    • 提交信息草稿按根保存,关闭工具窗口不丢失。
    • 窗口关闭时 shutdown(),之后不再加载任何工作区。
  • AppModel+VcsProviders:打开工作区时识别根,工作区文件变化转发给功能模型;插件启用状态变化时重新识别,关闭工作区时停止进程。

工具窗口(Views/Vcs/)

  • 每个 Provider 贡献一个左侧工具窗口,VcsProviderToolWindowRegistration 只按贡献上的 vcsProviderPluginID、vcsProviderID 键注册,没有 VCS 名字。启动后才安装的插件,窗口提示重启 Lithe。
  • “变更”页:冲突、变更、未版本控制文件三组;默认只勾选“变更”组,冲突文件和被忽略的文件不能勾选;移动的文件提交时带上原路径。工具栏有刷新、更新项目、回滚(二次确认)、显示差异、标记为已解决、清理工作副本。多个根时可切换,显示当前修订和分支,并展示识别问题、歧义目录选择、截断提示和操作结果。右键菜单:显示差异、打开、显示历史、标记已解决、回滚、复制路径、在 Finder 中显示。
  • “历史”页:工作副本历史和单个文件的历史,分页加载,展开查看每个修订改动的文件。
  • 差异:窗口级弹出面板(RootView 显示 presentedDiff),项目树右键菜单也能打开;复用本地历史的比较算法和 Git 的 DiffPaneView,超过 2 万行时退成左右两栏纯文本;二进制和超过 2 MB 的文件不比较。

项目树与文件操作

  • 项目树通过只观察 VCS 功能模型的包装视图拿到插件根的状态,项目树本身仍是 .equatable();同一文件 Git 和插件都有状态时显示 Git 的。文件行显示 Provider 状态字母,右键菜单新增“显示 差异”(Provider 支持基线内容、文件有基线时)。
  • LitheWorkspaceModule.WorkspaceFeatureModel 新增注入的 moveTrackedItem 回调:重命名和拖动移动先交给拥有该文件的 Provider,Provider 不跟踪、拒绝或两端不归同一个根时退回原来的磁盘移动。工作区模块不认识任何 VCS。

文档、矩阵与本地化

  • 提议 Note 2026-10-22-unified-vcs-provider-model.md:第 7 节改为“SVN 作为社区插件”,记录 P2、P3 第一部分完成的内容和原因,新增“SVN 作为官方插件留在主仓库”的不采用理由;状态读取热路径改为“先整根查询、实测太慢再按能力版本加增量参数”。
  • 能力版本 Note:vcsProviders: [1] 等 macOS 接入会话后才加入的说明。
  • 功能矩阵 vcs-subversion-and-plugin-providers:macOS 改为部分实现;验证项写明 SVN 回归在插件仓库 CI、主仓库只保留通用契约回归,以及宿主自动化覆盖的场景。
  • 新增所有界面文案的简体中文翻译(含“正在读取更改…”);本地化测试检查这些键存在且占位符一致。原来比较界面用的 “Base” 键已有“目标”的含义,改用新键 “Base revision”(基线版本)。

暂不包含

  • 编辑器 gutter 与 Annotate、交互式认证(lithe/vcs/authenticate 仍按未知请求回绝,认证失败时提示先用命令行登录一次)、把 lithe/vcs/execution 执行报告接到项目控制台。
  • 对照 IDEA Subversion 工具窗口还缺的部分,下一个 PR 处理:
    • “仓库”页的主从布局(左边修订列表、右边该修订的文件树)、按日期分组、按作者/日期筛选和搜索;这些只需要宿主改。
    • 查看历史修订里某个文件的差异:契约 v1 只能取 BASE 内容,要加可选能力(例如 revisionContent)。
    • “传入”页(服务器上还没更新到本地的修订):要加可选能力(例如 incoming)。
    • “工作副本信息”:契约已有 head.location,宿主可以先显示 URL 和修订;仓库根、depth 等要扩展回复。
    • 本地更改按 changelist 分组:要在状态回复里加可选字段。
    • Git 和插件 VCS 共用一个版本控制窗口:等 Git 迁到同一模型时再做,目前同时有 Git 和 SVN 的项目会出现两个窗口。
  • SVN 插件的 Release 和 Lithe Store 上架:要等带 vcsProviders 能力的宿主版本发布后再做。
  • Windows 宿主(P4)。

测试

  • VcsProviderHostTests(15 个)与 VcsProviderAppModelTests(2 个,经真实 AppModel):
    • 用假 Core 和假 Provider 测功能模型:根识别与嵌套 Git 的归属、刷新规则(未声明的元数据不刷新、宿主操作期间忽略元数据、标记目录触发重新识别)、包住工作区的工作副本元数据监听、同一时间只运行一个操作、移动跟踪与拒绝、歧义目录选择的保存与清理、错误提示、外层工作副本的路径换算。
    • 工具窗口规则:分组和默认勾选、移动的两个路径、修订摘要与日期显示、工具窗口和命令使用版本控制图标。
    • 真实 Rust Core:用契约 fixture 清单识别 .svn 根与嵌套 .git、文件归属、回复校验(未知状态被拒绝);真实安装审核显示 Provider 命令、客户端和联网。
    • VcsProviderAppModelTests:经项目树移动时被跟踪的文件交给 Provider、未版本控制的文件走磁盘移动;关闭项目窗口停止 Provider,之后迟到的工作区加载不再启动。
  • PluginManagerTests:SDK 样例 Provider 经 Core 校验,生成一个默认停用的模块。
  • AppLocalizationTests:新文案的简体中文翻译与占位符。

本地验证:

  • 完整 macOS 测试(test-stability-macos.sh)2735 个,只有 PluginUIIconTests 的两个渲染取色测试失败(15 个问题都来自这两个测试)。它们不涉及本 PR 的代码,单独运行也失败,上一版在 CI 的 Swift tests 中通过,是本机 macOS 27.2 的渲染差异。
  • VcsProvider 相关 18 个测试单独运行全部通过。
  • verify-shared-contracts.sh、verify-platform-feature-matrix.sh、verify-module-boundaries.sh、verify-agent-notes.sh、verify-runtime-bundle-immutability.sh 通过。
  • 插件仓库:LITHE_SVN_INTEGRATION=1 node scripts/test.mjs 24 个测试全部通过(含按固定 Core 跑的 svn 场景测试),测试结束后没有残留的 Core 或 Provider 进程。

后续修正(078d0bd、b8c81d9)

  • 隐藏 .svn:项目树、搜索、索引和工作区监听像 .git 一样隐藏 .svn(Swift 与 Rust Core 的内置列表同步),避免 .svn/pristine 的基线副本进入索引。
  • 按根监听元数据:每个插件根单独监听自己的标记目录(含包住工作区的 ../.svn);工作区里新出现的条目会在后台检查标记,新检出的工作副本能被识别。
  • 客户端缺失:找不到 svn 时按契约报 vcs.tool.unavailable,工具窗口先显示安装提示。
  • 基线比较判断统一:VcsRootState.comparesWithBase 供工具窗口双击、辅助功能动作和项目树右键共用。
  • 移动归属等待期:等 Core 判断归属时开始了别的操作,就直接退回磁盘移动。
  • ..repo 判断:根 ID 只有全部由 .. 段组成时才算外层工作副本,与 Core 一致;工作区内名为 ..repo 的根不再丢失文件状态,补充回归用例。
  • 适配基线:基线已按 refactor(plugins): 契约发布到 lithe-plugin-docs,fixture 按能力改名,SDK 移出主仓库 #1442 把 SDK 移到 lithe-plugin-docs,PluginManagerTests 改用契约 fixture vcs-provider.plugin.json;VCS 工具窗口提交栏改用 preview 的 ActionButton.spacing(Commit.buttonBorderInset 已删除)。
  • 测试修正:watchesTheMetadataDirectoryOfEveryRoot 在第二次投递元数据事件前推进时钟(读状态会开始全局静默期)。

本地验证:VCS/插件管理/市场/文件可见性/项目树相关 75 个 Swift 测试通过;cargo test -p lithe-core、cargo fmt --check、契约、Agent Notes、功能矩阵(含变更门禁)、模块边界、服务边界、测试稳定性、Rust Core 注释、bundle 不可变性检查均通过。完整 macOS 测试在本机有大批异步等待超时,同一组套件在不含本 PR 的基线工作树上同样失败,判断为本机环境问题,以 CI 为准。

- 插件清单 API 3 新增 vcsProviders 能力、process.vcs 权限和 onVcsRoot 激活事件,git 为保留 ID;安装审查以 vcsTool 列出 VCS 命令行
- 新增 vcs.detectRoots(静态标记识别根、歧义目录与用户映射、祖先工作副本)、vcs.ownerOf(最深根归属)、vcs.decodeReply(Provider 回复校验与归一化)
- LSP 会话:只向插件会话提供 litheVcs 协商,成功后发出 vcsProvider 事件;lsp.vcsRequest 按操作生成 lithe/vcs/* 请求并检查已协商能力;Provider 错误码只保留契约白名单
- lithe/vcs/execution 转为会话日志事件,lithe/vcs/authenticate 暂按未知请求回绝
- 契约、插件 README/schema、rust-core-api、fixtures、功能矩阵与提议 Note 同步
- 修复 unregistering_a_running_function_revokes_the_call 的竞态:改为有界等待 $/cancelRequest 写出
- backend.vcs(id, handlers, traits) 按声明的处理函数协商 VCS 能力,必需 status/baseContent/checkin/rollback,git 保留,litheVcs 不能手写进 capabilities
- 只在宿主提供 litheVcs 1 时分发 lithe/vcs/* 请求;回复必须是对象,无返回值视为 {}
- VCS 处理函数的 context.run 自动发出 lithe/vcs/execution(命令行、退出码、耗时、截断到 16 KiB 的 stderr),可用 report: false 关闭
- 导出 VCS_ERRORS 与 isVcsId,补充类型声明、README 和单元测试
- 新增 sdk/node/examples/sample-vcs 玩具 VCS,Rust 端到端测试经真实 Core 会话跑通协商、全部 11 种操作、错误码和执行报告
- 契约写明 lithe/vcs/execution 的参数;Note 与功能矩阵更新 P1 完成状态
- 只有全部由 .. 段组成的根 ID 才是工作区外的祖先根;工作区内名为 ..repo 的目录按普通路径计算深度和包含关系,补充单元测试
- 示例 Provider 回滚移动目标时把文件移回原路径、恢复基线内容并清除移动记录;端到端测试覆盖移动后回滚
- 插件能力版本笔记补充 vcsProviders、其对 serverProcess 的依赖、两端宿主尚未声明的状态,以及 litheVcs 协商
@ghfind-review ghfind-review Bot added the review: medium ghfind author score; see https://ghfind.com label Oct 23, 2026
@xiaoyumuxi
xiaoyumuxi marked this pull request as ready for review October 23, 2026 04:49
@lithe-code-review

lithe-code-review Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

Lithe Review

结论: ⛔ 有阻塞
范围: feat/827-svn-support ← feat/827-svn-host · head: 114dcc1

Findings

  1. [P1] 将 VCS Provider 清理接入原生项目窗口关闭路径
    macos/Sources/Lithe/Platform/MacOS/MacServiceContainer.swift:794

    • 实际影响:新增的 Provider 会话未随项目窗口关闭而停止,后台进程和轮询任务会残留;重复打开、关闭项目会累积资源。
    • 触发条件:已启用 SVN 插件,工作区状态读取已启动 Provider,然后关闭该项目的独立窗口,同时保持 Lithe 其他窗口运行。
    • 复现步骤:打开 SVN 项目并等待状态显示,关闭窗口,再重复操作。静态调用链为 RootView.closeWindowAfterProjectCleanup → resetDedicatedWindowSession → AppModel.shutdownProjectSession();后者没有调用 VCS reset。新增 reset 只位于工作区切换、显式关闭路径(AppModel.swift:947、1014)。VCS 对应的 DeclarativeWorkbenchModule.shutdown() 为空,不能代为清理;LanguageServerSession.swift:943–946 的轮询任务还会强引用会话,释放窗口引用也不能结束它。
    • 来源:本次引入。新增服务持有独立进程,但未接入既有项目会话销毁入口。
  2. [P2] 文件移动应使用 Core 判定的实际归属
    macos/Sources/Lithe/Application/Features/VcsProvidersFeatureModel.swift:563–568

    • 实际影响:嵌套 Git 根或未映射的歧义目录中的文件,仍可能被交给外层 SVN Provider 移动,产生不符合 Core 归属结果的 SVN 删除、添加记录。
    • 触发条件:外层 SVN 工作副本中的已跟踪目录,同时包含一个嵌套 Git 根;用户从项目树重命名其中的文件。
    • 复现步骤:让 SVN 跟踪 module/a.txt,在 module 建立 Git 仓库后打开外层工作区,再重命名该文件。rootPath(of:)(第 663 行)只遍历插件 roots,忽略 allRootIDs 中的 Git 根和 ambiguous;而 isUnversioned 将无树状态视为可跟踪,因此最终发送外层 SVN .move。官方 Provider 随后执行 svn move(svn-provider.mjs:378–379)。树状态投影已使用 planner.owners 排除这些路径,移动操作却未遵循相同规则。
    • 来源:本次引入。新增项目树移动回调使用了与 vcs.ownerOf 契约不同的归属判断。
  3. [P2] 为工作区外的 Provider 元数据注册监听
    macos/Sources/Lithe/Models/AppModel/AppModel+VcsProviders.swift:19–20

    • 实际影响:打开 SVN 工作副本的子目录时,外部命令造成的纯元数据变更不会自动刷新,工具窗口和项目树会持续显示旧状态,直到手动刷新。
    • 触发条件:工作副本位于 /wc,Lithe 只打开 /wc/subdir;外部操作仅改变 /wc/.svn/wc.db。
    • 复现步骤:先创建 /wc/subdir/a.txt 并等待界面显示未版本控制,待刷新静默期结束后,在外部执行 svn add /wc/subdir/a.txt。新增接线只接收现有工作区文件通知;DirectoryWatchConfiguration.physicalRoots 只有工作区和 Git 上下文,MacDirectoryWatcher.swift:168–171 也只发布工作区内的普通路径,所以外层 .svn/wc.db 无法到达 workspaceFilesChanged。本 PR 已明确支持外层工作副本的路径换算,但未扩展相应监听范围。
    • 来源:本次引入。新增自动刷新功能依赖了无法覆盖所支持根范围的事件源。

Scope Check

  • 关联 Issue:[Feature] 希望能够支持svn #827 要求跨平台 SVN 支持;本 PR 仅实现 macOS P3 第一部分,不能视为整个 Issue 完成。
  • 已完成范围:宿主能力与安装审核、Provider 启动和请求、状态与主要操作、历史和差异、项目树展示及移动接线。
  • 未完成范围:gutter、Annotate、交互式认证、执行报告接入项目控制台、官方插件索引发布,以及 Windows P4;正文、Note 和功能矩阵已说明阶段边界。
  • 能力复用:复用 Rust Core 根识别与回复校验、现有语言服务进程通道、SVN CLI 和既有差异组件,未发现需要另行报告的并行领域实现问题。
  • 三项 Finding 均由本次宿主接入引入,属于其生命周期、文件归属和刷新职责范围。

Suggestions

  1. 提交前必须修复 Finding 1: 在 shutdownProjectSession() 首次挂起前停止 VCS 功能,取消待处理任务并停止启动中、运行中的会话;补充原生窗口关闭路径的确定性回归测试,验证 Provider 停止及进程登记释放。
  2. 非阻塞,针对 Finding 2: 对移动的源、目标使用 planner.owners(roots:ambiguous:paths:),仅当两者实际归属于同一插件根时调用 Provider;覆盖嵌套 Git 和未映射歧义目录。
  3. 非阻塞,针对 Finding 3: 将检测到的 Provider 元数据路径注册为独立监听输入,使工作区外的元数据事件也能触发 VCS 刷新;补充从 watcher 到功能模型的测试。
  4. 补充安装审核、VCS 工具窗口、历史、差异和项目树的截图;已有界面修改提供前后对比。当前提供的上下文没有截图,视觉效果尚未验证。

Summary

整体接入复用了已有 Core、进程通信和 UI 组件,阶段范围清楚。当前需要先修复项目窗口关闭后的进程清理遗漏;另两项建议涉及已支持场景中的归属一致性和自动刷新。现有测试覆盖了较多模型规则,但未覆盖上述实际窗口销毁与元数据监听调用链。

Verification

  • 实际检查:固定 base...head 的完整 40 文件清单及相关调用链,重点包括功能模型、Provider 会话、启动解析、Swift/Core 契约、项目树移动、窗口销毁、文件监听、UI、测试和矩阵。仅执行静态只读检查。
  • 作者报告:4 组共 46 个测试通过;完整 macOS 2731 个测试中有两个渲染测试失败,作者称在基线同样复现;矩阵、模块边界、Agent Notes 和 bundle 不可变性检查通过。以上均未由本次审查独立验证。
  • 已提供 CI:多个 gate、矩阵及 Agent Notes 检查成功,但 Swift、Rust、Windows 和插件实际测试作业多项为 skipped;不能据此认定运行时和跨平台测试已通过。
  • 本次未运行任何仓库代码、测试、构建、验证脚本或应用,也未访问网络。
  • 验证缺口:真实 Provider 的窗口关闭清理、嵌套根移动路由、外层 SVN 元数据监听,以及 UI 截图。上述复现路径来自静态调用链分析,未动态执行。

SVN 插件改为独立仓库 Lithe-IDEA/lithe-plugin-svn 的社区插件
(io.github.lithe-idea.svn-support),主仓库只保留与具体 VCS 无关的部分;
原 #1432 里宿主识别 vcsProviders 的通用改动并入本提交。

- 宿主识别:声明式清单解码 vcsProviders,声明了 VCS Provider 的插件生成一个
  <pluginID>.vcs-providers 扩展模块,只承载启用状态,默认关闭;
  PluginManifest.hostCapabilities 声明 vcsProviders: [1]。
- 安装审核:显示 Provider 的启动命令、客户端命令和是否连接仓库服务器。
- Provider 会话、Core 调用(vcs.detectRoots / ownerOf / decodeReply、
  lsp.vcsRequest)、VcsProvidersFeatureModel、左侧 VCS 工具窗口、历史与差异、
  项目树状态着色和移动跟踪。
- 测试改用契约里的 svn-provider 清单 fixture 和 SDK 的 sample-vcs 样例,
  不再依赖 SVN 插件源码。
- 契约的 Subversion provider notes 改为指向插件仓库;Note、功能矩阵和
  Plugins/mac/README.md 同步说明社区插件。
- 包住工作区的工作副本(如 ../.svn)单独监听其声明的元数据目录,
  终端里的提交或更新也会触发刷新。
- 移动前按 Core 的归属规则确认两端都属于同一根,嵌套的 Git 仓库或
  未选择 VCS 的歧义目录不会被当成 svn move。
- 窗口关闭时调用 shutdown():停掉所有 Provider,之后迟到的工作区
  扫描也不会再把 Provider 拉起来。
- 工具窗口与命令沿用宿主版本控制图标;首次读取时显示“正在读取更改…”;
  变更行补充选择、打开/查看差异、纳入提交的辅助功能操作。
- 同步 Agent Note、能力版本 Note 与跨平台功能矩阵。
@xiaoyumuxi xiaoyumuxi changed the title feat(vcs): macOS 宿主接入插件 VCS Provider(#827 P3) feat(vcs): macOS 宿主接入插件 VCS Provider,SVN 改为独立社区插件(#827 P3) Oct 23, 2026
@xiaoyumuxi
xiaoyumuxi changed the base branch from feat/827-svn-support to feat/827-vcs-provider-core October 23, 2026 09:43
- preview 已把 sdk/ 与 SDK 端到端测试迁到 lithe-plugin-docs:删除本分支在
  sdk/node(litheVcs、sample-vcs、vcs.test.mjs)与 rust/lithe-core/tests/plugin_sdk
  上的改动,这部分改到 lithe-plugin-docs 提交
- 契约 fixture 按能力命名:svn-provider.plugin.json 改为 vcs-provider.plugin.json,
  ID 改为 dev.lithe.fixture.vcs-provider,入口改为 provider/main.mjs;同步 Core 测试、
  vcs-provider-v1.md、model-v1.json 与功能矩阵
- 契约 README 指向 vcs-provider-v1.md 的相对链接改为绝对地址
- 统一 VCS Note 与功能矩阵去掉主仓库内的 SDK 路径,说明 SDK 端到端在 lithe-plugin-docs 运行
- 项目树、搜索、索引与工作区监听像 .git 一样隐藏 .svn(Swift 与 Rust Core 的内置隐藏列表同步),避免 .svn/pristine 进入索引
- 每个插件根单独监听自己的元数据目录(含包住工作区的 ../.svn);工作区里新出现的条目在后台检查标记,新检出的工作副本会重新识别
- 找不到 VCS 客户端时按契约报 vcs.tool.unavailable,工具窗口先显示安装提示
- 是否有基线统一由 VcsRootState.comparesWithBase 判断,工具窗口双击、辅助功能动作和项目树右键共用
- 等待 Core 判断移动归属期间开始了别的操作时,直接退回磁盘移动
- 同步 Agent Note、功能矩阵与 VcsProviderHostTests
…P3)

- 基线已按 #1442 把 SDK 移到 lithe-plugin-docs:删除 sdk/node/examples/sample-vcs 的注释改动;
  PluginManagerTests 改用契约 fixture vcs-provider.plugin.json,不再读主仓库里已不存在的 sample-vcs
- VcsProviderHostTests 跟随 fixture 改名(vcs-provider.plugin.json、入口 provider/main.mjs)
- 根 ID 只在全部由 .. 段组成时才算包住工作区的工作副本,与 Core 规则一致:工作区内名为 ..repo
  的 SVN 根不再被当成外层根,文件路径换算和标题都正确;补充回归用例
- 合入 preview 的统一动作按钮样式后,VCS 工具窗口提交栏改用 ActionButton.spacing
  (LitheTheme.Commit.buttonBorderInset 已删除)
- watchesTheMetadataDirectoryOfEveryRoot:读状态会开始全局静默期,投递 lib 的元数据事件前先推进时钟
- 统一 VCS Note、Plugins/mac/README 与功能矩阵去掉主仓库内的 SDK 路径
@xiaoyumuxi
xiaoyumuxi changed the base branch from feat/827-vcs-provider-core to preview October 23, 2026 13:03
- #1430 以 squash 合入 preview 后,本分支保留的原 Core 提交与之产生冲突;Agent Note、
  能力版本 Note、vcs-provider-v1.md、功能矩阵在 preview 上相对已合入的 07caa09 没有新改动,保留本分支版本
- zh-Hans Localizable.strings:同时保留本分支的 VCS Provider 词条与 preview 新增的 Agent 指令、技能、MCP 词条,未引入新的重复 key
@xiaoyumuxi
xiaoyumuxi merged commit bb61147 into preview Oct 23, 2026
8 of 12 checks passed
1lck added a commit that referenced this pull request Oct 25, 2026
* fix(windows): open focused files with configurable F4 command

* ci(windows): include focused F4 navigation regression

* test(windows): await process exit signals and own fixture cleanup

* fix(search): open the focused excerpt line with F4

* refactor(plugins): 契约发布到 lithe-plugin-docs,fixture 按能力改名,SDK 移出主仓库 (#1442)

* refactor(plugins): 契约发布到 lithe-plugin-docs,fixture 按能力改名,SDK 移出主仓库

- 契约 fixture 按演示的能力改名(文件名和 dev.lithe.fixture.* ID),同步更新
  标准答案、Rust Core 测试、macOS 测试与展示副本、功能矩阵和 Agent Notes。
- 两份 schema 的 $id 改为 lithe-plugin-docs 的 raw 地址;verify-shared-contracts.sh
  要求 $id 完全相等,并拒绝离开契约目录的 README 相对链接。
- 契约 README 的目录外链接改为绝对地址,说明 lithe-plugin-docs 保存完整副本,
  官方 SDK 一节指向 lithe-plugin-docs。
- 删除 sdk/、SDK 端到端测试和 Java SDK 发版工作流;Rust Core 的 CI 脚本、
  ci-macos.yml、CI 分类和 .gitignore 去掉 SDK 相关内容。
- AGENTS.md 新增两仓库同步规则,新增 Agent Note 记录决策,并更新 SDK 相关
  Note、develop-lithe 布局表、Plugins README 和 docs/ci-builds.md。

* docs(plugins): SDK 与契约的每周检查跟踪 preview 而不是默认分支 main

* fix(macos): keep marketplace details inside split bounds (#1447)

* feat(agent): 完善技能、全局指令与 MCP 服务器设置 (#1381)

* feat(agent): add native global and project skill management

* fix(macos): make skill toggles respond immediately

* feat(agent): 新增原生全局指令并稳定技能开关反馈

在 AI 设置中保留独立的指令与技能入口,直接编辑 Codex/Claude 用户指令文件,提供草稿、冲突校验和原子保存。为技能成功提示保留布局空间,覆盖连续启停、深浅主题和窄宽页面的原生几何回归。

* fix(agent): 技能保存仅锁定当前行,避免其他开关变灰

将待确认选择按点击顺序串行保存,其他技能保留原生启用外观和交互能力。覆盖同一 Agent 连续写入、单行失败回滚、队列继续、重复点击去重、项目切换及离页清理;同步 Agent Note 与平台矩阵。

* feat(agent): add shared instruction cards and native synchronization

* feat(mcp): add bundled publisher icons and common featured servers

* feat(mcp): 增加工具检测与原生工具开关

* fix(agent): preserve cancellation and native MCP tool filters

* fix(skills): publish Windows skill packages without replacement

* fix(ci): bound multi-repository tests and join search fixture teardown

* test(windows): await owned process exit signals and clean fixtures

* fix(agent): close cancellation and MCP policy lifecycle gaps

* test(ci): bound Windows frontend path roundtrip startup

* fix(ci): match raw path test names for scoped deadlines

* test(ci): scope checkout and clone integration timing allowance

* fix(ci): allow Agent Host cold compilation within Rust suite budget

* fix(macos): 终端配色同步: 主题刷新、COLORFGBG 与订阅制背景通知 (#1448)

* fix(macos): 刷新已打开终端的主题色

* feat(macos): 终端环境导出 COLORFGBG

- `COLORFGBG` 是 Terminal.app、iTerm2、tmux 等终端的行业惯例环境变量;omp 等 TUI 在进程启动时同步读取其 bg 字段(<8 深、>=8 浅)选择配色,先于任何 OSC 往返,可消除首帧按回退深色渲染的闪变。
- Lithe 终端此前未导出该变量;且终端视图加入窗口前 effectiveAppearance 跟随系统外观,直接读它会与 Lithe 主题不一致。

- `TerminalTransport` 协议新增 `reportsLightBackground: Bool?`(宿主是否渲染浅色背景,无法判定时为 nil),extension 默认 nil
- `TerminalSession` 以可选值直赋导出 `COLORFGBG`(浅色 `0;15`、深色 `15;0`;fg;bg 惯例,判读位是 bg 字段),宿主无法判定时同时清除从外层终端继承的同名值
- macOS 实现按应用主题偏好解析:视图未挂载窗口时用主题 pin 的明暗,挂载后用窗口外观
- `TerminalModuleTests` 新增 4 个用例(浅色、深色、无法判定不写入、清除继承值);更新 `terminal-shell.json` 能力矩阵

- `TerminalModuleTests` 全绿(含 4 个新增)
- 平台能力矩阵门禁通过
- 真机浅色/深色首帧配色正确,无闪变;`echo $COLORFGBG` 输出 `0;15` / `15;0`

* fix(macos): 背景通知仅推送给订阅 kitty DEC mode 2031 的程序

- 背景变化通知由无条件推送改为按订阅发送: 解析进程输出中的 CSI ? 2031 h/l (含组合 DEC mode 与跨块分片), 未订阅的 shell 不再收到响应字节
- DSR 997 按背景亮度如实报告: 997;1n 暗色、997;2n 亮色
- 新进程启动与终端 RIS 重置清除订阅状态
- 单测 15 用例: 通知编码门控与明暗状态 + 订阅解析全路径

* feat(vcs): Core 与 Node SDK 实现插件 VCS Provider 底层(#827 P1) (#1430)

* feat(vcs): Core 实现插件 VCS Provider 底层(#827 P1)

- 插件清单 API 3 新增 vcsProviders 能力、process.vcs 权限和 onVcsRoot 激活事件,git 为保留 ID;安装审查以 vcsTool 列出 VCS 命令行
- 新增 vcs.detectRoots(静态标记识别根、歧义目录与用户映射、祖先工作副本)、vcs.ownerOf(最深根归属)、vcs.decodeReply(Provider 回复校验与归一化)
- LSP 会话:只向插件会话提供 litheVcs 协商,成功后发出 vcsProvider 事件;lsp.vcsRequest 按操作生成 lithe/vcs/* 请求并检查已协商能力;Provider 错误码只保留契约白名单
- lithe/vcs/execution 转为会话日志事件,lithe/vcs/authenticate 暂按未知请求回绝
- 契约、插件 README/schema、rust-core-api、fixtures、功能矩阵与提议 Note 同步
- 修复 unregistering_a_running_function_revokes_the_call 的竞态:改为有界等待 $/cancelRequest 写出

* feat(sdk): Node SDK 支持 litheVcs 并用示例 Provider 端到端验证(#827 P1)

- backend.vcs(id, handlers, traits) 按声明的处理函数协商 VCS 能力,必需 status/baseContent/checkin/rollback,git 保留,litheVcs 不能手写进 capabilities
- 只在宿主提供 litheVcs 1 时分发 lithe/vcs/* 请求;回复必须是对象,无返回值视为 {}
- VCS 处理函数的 context.run 自动发出 lithe/vcs/execution(命令行、退出码、耗时、截断到 16 KiB 的 stderr),可用 report: false 关闭
- 导出 VCS_ERRORS 与 isVcsId,补充类型声明、README 和单元测试
- 新增 sdk/node/examples/sample-vcs 玩具 VCS,Rust 端到端测试经真实 Core 会话跑通协商、全部 11 种操作、错误码和执行报告
- 契约写明 lithe/vcs/execution 的参数;Note 与功能矩阵更新 P1 完成状态

* fix(vcs): 按评审修正祖先根判断与示例移动回滚(#827 P1)

- 只有全部由 .. 段组成的根 ID 才是工作区外的祖先根;工作区内名为 ..repo 的目录按普通路径计算深度和包含关系,补充单元测试
- 示例 Provider 回滚移动目标时把文件移回原路径、恢复基线内容并清除移动记录;端到端测试覆盖移动后回滚
- 插件能力版本笔记补充 vcsProviders、其对 serverProcess 的依赖、两端宿主尚未声明的状态,以及 litheVcs 协商

* feat(vcs): macOS 宿主接入插件 VCS Provider,SVN 改为独立社区插件(#827 P3) (#1441)

* feat(vcs): Core 实现插件 VCS Provider 底层(#827 P1)

- 插件清单 API 3 新增 vcsProviders 能力、process.vcs 权限和 onVcsRoot 激活事件,git 为保留 ID;安装审查以 vcsTool 列出 VCS 命令行
- 新增 vcs.detectRoots(静态标记识别根、歧义目录与用户映射、祖先工作副本)、vcs.ownerOf(最深根归属)、vcs.decodeReply(Provider 回复校验与归一化)
- LSP 会话:只向插件会话提供 litheVcs 协商,成功后发出 vcsProvider 事件;lsp.vcsRequest 按操作生成 lithe/vcs/* 请求并检查已协商能力;Provider 错误码只保留契约白名单
- lithe/vcs/execution 转为会话日志事件,lithe/vcs/authenticate 暂按未知请求回绝
- 契约、插件 README/schema、rust-core-api、fixtures、功能矩阵与提议 Note 同步
- 修复 unregistering_a_running_function_revokes_the_call 的竞态:改为有界等待 $/cancelRequest 写出

* feat(sdk): Node SDK 支持 litheVcs 并用示例 Provider 端到端验证(#827 P1)

- backend.vcs(id, handlers, traits) 按声明的处理函数协商 VCS 能力,必需 status/baseContent/checkin/rollback,git 保留,litheVcs 不能手写进 capabilities
- 只在宿主提供 litheVcs 1 时分发 lithe/vcs/* 请求;回复必须是对象,无返回值视为 {}
- VCS 处理函数的 context.run 自动发出 lithe/vcs/execution(命令行、退出码、耗时、截断到 16 KiB 的 stderr),可用 report: false 关闭
- 导出 VCS_ERRORS 与 isVcsId,补充类型声明、README 和单元测试
- 新增 sdk/node/examples/sample-vcs 玩具 VCS,Rust 端到端测试经真实 Core 会话跑通协商、全部 11 种操作、错误码和执行报告
- 契约写明 lithe/vcs/execution 的参数;Note 与功能矩阵更新 P1 完成状态

* fix(vcs): 按评审修正祖先根判断与示例移动回滚(#827 P1)

- 只有全部由 .. 段组成的根 ID 才是工作区外的祖先根;工作区内名为 ..repo 的目录按普通路径计算深度和包含关系,补充单元测试
- 示例 Provider 回滚移动目标时把文件移回原路径、恢复基线内容并清除移动记录;端到端测试覆盖移动后回滚
- 插件能力版本笔记补充 vcsProviders、其对 serverProcess 的依赖、两端宿主尚未声明的状态,以及 litheVcs 协商

* feat(vcs): macOS 宿主接入插件 VCS Provider(#827 P3)

SVN 插件改为独立仓库 Lithe-IDEA/lithe-plugin-svn 的社区插件
(io.github.lithe-idea.svn-support),主仓库只保留与具体 VCS 无关的部分;
原 #1432 里宿主识别 vcsProviders 的通用改动并入本提交。

- 宿主识别:声明式清单解码 vcsProviders,声明了 VCS Provider 的插件生成一个
  <pluginID>.vcs-providers 扩展模块,只承载启用状态,默认关闭;
  PluginManifest.hostCapabilities 声明 vcsProviders: [1]。
- 安装审核:显示 Provider 的启动命令、客户端命令和是否连接仓库服务器。
- Provider 会话、Core 调用(vcs.detectRoots / ownerOf / decodeReply、
  lsp.vcsRequest)、VcsProvidersFeatureModel、左侧 VCS 工具窗口、历史与差异、
  项目树状态着色和移动跟踪。
- 测试改用契约里的 svn-provider 清单 fixture 和 SDK 的 sample-vcs 样例,
  不再依赖 SVN 插件源码。
- 契约的 Subversion provider notes 改为指向插件仓库;Note、功能矩阵和
  Plugins/mac/README.md 同步说明社区插件。

* fix(vcs): 按自审修正 VCS Provider 宿主(#827 P3)

- 包住工作区的工作副本(如 ../.svn)单独监听其声明的元数据目录,
  终端里的提交或更新也会触发刷新。
- 移动前按 Core 的归属规则确认两端都属于同一根,嵌套的 Git 仓库或
  未选择 VCS 的歧义目录不会被当成 svn move。
- 窗口关闭时调用 shutdown():停掉所有 Provider,之后迟到的工作区
  扫描也不会再把 Provider 拉起来。
- 工具窗口与命令沿用宿主版本控制图标;首次读取时显示“正在读取更改…”;
  变更行补充选择、打开/查看差异、纳入提交的辅助功能操作。
- 同步 Agent Note、能力版本 Note 与跨平台功能矩阵。

* fix(vcs): 隐藏 .svn 并按根监听元数据,补齐工具缺失与比较判断(#827 P3)

- 项目树、搜索、索引与工作区监听像 .git 一样隐藏 .svn(Swift 与 Rust Core 的内置隐藏列表同步),避免 .svn/pristine 进入索引
- 每个插件根单独监听自己的元数据目录(含包住工作区的 ../.svn);工作区里新出现的条目在后台检查标记,新检出的工作副本会重新识别
- 找不到 VCS 客户端时按契约报 vcs.tool.unavailable,工具窗口先显示安装提示
- 是否有基线统一由 VcsRootState.comparesWithBase 判断,工具窗口双击、辅助功能动作和项目树右键共用
- 等待 Core 判断移动归属期间开始了别的操作时,直接退回磁盘移动
- 同步 Agent Note、功能矩阵与 VcsProviderHostTests

* fix(macos): 修正 Agent 正文留白与 AI 设置排序 (#1450)

* fix(ci): 放宽 macOS Swift 编译预算并避免构建失败叠加报告失败 (#1449)

swift-tests 的冷编译在运行 39943871840 中超过 20 分钟上限,与插件通道 39741361768 同类;编译步骤放宽到 40 分钟(job 80 分钟),测试执行预算不变。构建失败时不再叠加合并报告失败,避免同一失败被重复计数。

* feat(windows): 终端活动栏拖动停靠并修正搜索快捷键 (#1436) (#1446)

* feat(windows): dock terminal panel at bottom or right (#1436)

* fix(windows): drag terminal activity entry to either side

* fix(terminal): leave project search shortcut to workbench

* fix(terminal): focus docked sessions after the pane becomes visible

* fix(windows): Ctrl+Z 优先恢复键盘移动后的光标 (#1443)

* fix(windows): Ctrl+Z 优先恢复键盘移动后的光标 (#1438)

* ci(windows): run cursor undo regression in frontend lane

* fix(editor): coordinate explicit cursor undo with generic redo

* docs(skill): gh 不支持 YAML 表单时允许按表单字段生成正文提交 Issue (#1458)

GitHub GraphQL repository.issueTemplates 只返回 Markdown 模板,gh 无法选择
YAML Issue Forms(cli/cli#5865)。Issue 门禁本就接受包含全部必填字段的正文,
因此 submit-lithe-issue 改为:原生模板不可用时用 gh issue create --body-file
提交逐字段生成的表单正文,仍禁止空白正文、API 直建和手工添加 issue-form 标签。

* feat(macos): 编辑区 Agent 大历史秒开与 Claude Desktop 式布局;Claude 支持官方订阅与 API Key 两种模式 (#1453)

* feat(macos): 优化编辑区 Agent 对话的大历史加载与 Claude Desktop 式布局

- 大历史回放性能:loadSession 回放期间消息写入不对外发布的缓冲区,
  sessionLoaded 时一次性提交,消除 @published 字典逐事件整体复制带来的
  平方级开销;1,200 轮(约 1 万事件)接收从 27s 降到 0.45s。
- 对话窗口化:首屏只构建最近 48 项,点「显示更早的 N 项」或导航栏跳到
  旧回合再展开,首次排版从 31s 降到 0.3s,总加载 <1s。
- 历史列表:按收藏/今天/昨天/过去 7 天/过去 30 天/更早/时间未知分组,
  行改为 Agent 磁贴 + 标题 + 消息数 + 会话 ID + 相对时间 + 「…」菜单;
  排序筛选改为一次快照。选择、多选、归档、已移除、导出等能力保留。
- 编辑区会话 UI 向 Claude Desktop 靠拢:用户消息中性灰气泡、16pt 圆角
  卡片输入框(仅添加/发送)、审批模式与模型下移到卡片下方状态行;
  详情栏改为上下文/更改/会话统计三个可折叠分区,并新增「更改」。
- 标题栏新增详情栏开关按钮,原菜单项保留。工具窗口侧栏样式不变。
- 新增 AgentLargeHistoryLoadTests;同步 Agent Note、功能矩阵、zh-Hans 本地化。

* perf(macos): 历史列表滚动不再掉帧;居中对话改为 Claude Desktop 式卡片详情栏

- 历史列表:排序结果、行数据、列表版本号三层记忆;流式输出期间刷新从
  p50 14ms(25% 掉帧)降到 1.7ms(0 掉帧),纯滚动 p95 从 8.6ms 降到 1.4ms
- 时间戳解析、本地化 .lproj 查找、DateFormatter 加缓存;canExport 改为打开
  菜单时按行计算(原先每行 O(n),整表 O(n²));managementSessions 只排序一次;
  消息数与临时标题不再复制整个对话
- 历史行:标题 + 消息数 + 时间 + 「•••」,1 小时内显示「N 分钟前」、之后显示
  具体时间;菜单为置顶/重命名/分叉/归档/复制 Session ID/导出/删除;固定行高、
  菜单只在悬停或当前行挂载
- 居中输入卡片内放 Agent、权限模式、模型、添加、发送;权限模式名称本地化
- 右侧详情栏 AgentEditorDetailsColumn:圆角卡片 + ▾ 折叠,上下文图例与更改列表
  按参考图排版;工具窗口输入框的会话详情弹窗恢复原样式

* feat(macos): 编辑区文件审查统一到「更改」卡片,活动卡只保留任务与子 Agent

- 「更改」卡片内可全部保留/全部回滚、逐个文件看 diff/回滚(悬停显示),
  回滚前确认;活动卡在编辑区不再重复显示文件修改行
- 批量菜单与筛选图标统一为「置顶」术语
- 清理不再使用的参数与常量,历史缓存清理已关闭对话的计数

* feat(agent): Claude 支持官方订阅与 API Key 两种模式;居中输入框改为状态圆环,权限模式汉化

- Claude 订阅(claudeSubscription):直接使用本机 Claude Code 已登录的
  claude.ai 账号。Host 新增 claude_subscription.rs:不注入 API Key/路由,
  移除继承的 ANTHROPIC_* 覆盖变量,初始化后读取适配器的登录状态,未登录时
  提示在终端用 /login 登录;Lithe 不读取、复制或刷新任何凭据
- 订阅只属于各自适配器(Codex 订阅不能给 Claude,反之亦然);供应商管理
  新增「Claude 官方订阅(本机账号)」开关,预检文案区分 API Key 与两种订阅
- 居中模式输入卡片去掉「+」与「发送」,右侧改为额度与上下文圆环,回复中
  才显示停止按钮;详情栏移除重复的额度卡片
- 权限模式按上游 ID 显示中文(Codex:请求批准/替我审批/完全访问;Claude:
  手动/接受编辑/计划/自动/跳过权限确认),菜单标题「模式」;修正 Claude
  「手动」的 ID 为 default
- 同步 Agent Note、新增功能矩阵 agent-claude-subscription、Rust 与 Swift 测试

* fix(agent): 评审修复——窄窗口保留活动入口、Claude 订阅额度圆环、权限模式翻译不误伤其他 Agent

- 居中模式详情栏关闭或宽度不足时,输入框上方恢复活动摘要(任务、子 Agent、
  文件审查与回滚),避免这些入口消失
- 上下文圆环始终显示(未上报时为空圈);Claude 订阅接入额度圆环:解析适配器
  转发的 rate_limit_event(_claude/rateLimit),按 five_hour/seven_day 等窗口
  累积,快照在窗口重置前有效,悬停显示「截至某时刻,仅在回复时更新」,不调用
  任何接口
- 权限模式只在「上游 ID + 英文原名」都匹配时翻译,其他 Agent 的同名 ID 保持原名;
  改写原先断言保留英文名的测试,Agent Note 记录决策变更
- 编辑区居中布局测试改用 Agent 切换按钮测量输入框左缘(附件按钮已移除)

* feat(macos): 新建项目向导,插件通过 projectGenerators 注入项目模板 (#1452)

* feat(macos): 新建项目向导,插件通过 projectGenerators 注入项目模板

- Rust Core 新增能力 projectGenerators 1(pluginAPIVersion 保持 3)和
  project.generatorCatalog / generatorForm / generationPlan / checkName /
  extractArchive 命令:校验声明、计算表单(派生默认值、显示条件、错误码)、
  展开模板文件/命令/下载地址,安全解压项目压缩包。
- 新增内置官方插件 Java Project Templates:Java(Lithe/Maven/Gradle)、
  Maven Archetype、Spring Boot(start.spring.io,可改服务器 URL)。
- macOS 新建项目窗口按 IDEA 布局,复用设置窗口的原生控件;抽出共享的
  侧栏行、插件字段控件和目录选择器。在临时目录生成后整体移动到位,
  失败或取消不留残留;所选 JDK 写入新项目,模板文件随项目打开。
- 需要的语言/构建插件已停用时可一键启用,未安装时跳转插件市场搜索。
- 修复克隆仓库窗口目标路径文案缺少插值。
- 更新插件契约、schema、fixture、Core API 文档、功能矩阵、打包与资源清单、
  Agent Note。

* refactor(java): 项目模板并入 Java Support,修复 CI 与生成器命令审批

- Java、Maven Archetype、Spring Boot 三个生成器改由 Java Support 声明,移除单独的 Java Project Templates 内置插件及其分发、校验、资源清单和目录条目
- 生成器的 command 步骤计入安装确认的 programs(kind: projectGenerator),更新新增或修改命令会要求重新确认;安装确认界面显示该类程序
- 生成器所在插件自己提供的 requirement 不再重复提示启用
- 模板目录禁用换行转换,修复 Windows 检出 CRLF 导致 golden_project_plans_match 失败
- 补齐 project.* 命令变体的文档注释,修复 missing_docs

* fix(project-generators): 处理评审:下载边收边限、目标 Java 不超过 JDK、固定 Maven 插件版本

- 项目压缩包改为流式下载,超过上限立即取消;错误响应最多读取 64 KiB 用于提示
- 生成器字段新增 maximumVersion(读取前面字段的模板),Spring Boot 的目标 Java 不得高于所选 JDK,Core 返回 versionTooHigh
- Java → Maven 模板固定 maven-compiler-plugin 3.14.0 与 maven-surefire-plugin 3.5.4,Maven 3.8 下 release 属性生效、可运行 JUnit Jupiter
- 补充下载上限、错误说明、版本约束和计划拒绝的测试,同步契约 schema 与文档

* fix(macos): 为声明生成器的语言插件注册 project-generators 模块

Java Support 同时声明语言与生成器后,启动时只为有贡献的模块及构建系统、VCS 模块创建工厂,遗漏 project-generators 模块,模块图校验失败导致启动崩溃。补充注册并增加回归测试。

* fix(macos): 新建项目窗口审查修复

- 未找到 JDK 时提示安装,不再一直显示“正在查找”
- 高级设置中的字段出错时自动展开,避免创建按钮无故不可用
- Spring Server URL 规则与 Core 一致:只接受 https 或本机 http
- 下载中取消按取消处理,不再显示错误
- 表单求值复用目录加载时的插件列表,输入时不再逐键重建插件快照
- 路径缩写改用 abbreviatingWithTildeInPath,避免主目录前缀误替换

* feat(remote): 远程开发 Rust 核心——协议、轻量远端服务与传输链 (#1460)

* feat(remote): 远程开发 Rust 核心——协议、轻量远端服务与传输链

- lithe-remote-protocol:帧格式、消息信封、方法与稳定错误码、主机能力描述
- lithe-remote-server:Rust 原生远端服务(Linux 静态约 0.7 MiB),提供文件与进程能力,Linux/macOS 差异集中在平台适配器
- lithe-remote-client:本机/SSH/Docker/Podman 可叠加的传输链、校验哈希的远端安装、会话
- 新增 Linux 专用 Remote Workspace CI lane 与 verify-remote-workspace.sh(含体积上限)
- 提案 Note、协议契约文档与功能矩阵条目

* fix(remote): 修复评审指出的并发创建、临时文件权限、进程组清理、写入超时与 SSH 嵌套引用问题

- fs.writeFile:只创建(不带 expected、不允许覆盖)时用不覆盖的改名提交,并发创建同一文件只有一个成功,另一个返回 ALREADY_EXISTS
- fs.writeFile:覆盖已有文件时,临时文件创建权限不超过原文件,写完再恢复原权限,不再短暂以 0644 暴露 0600 文件的新内容
- process:组长退出后,组里还有成员时继续持有该进程组;process.kill 和断线清理以“组内已无进程”为结束依据
- 客户端会话:改由独立写线程发送,请求只入有上限的队列,同一截止时间覆盖入队、发送和等待响应;超时未发出的帧直接丢弃
- 传输链:内层 SSH 跳转生成的命令行用 '"'"' 转义单引号,支持多个 SSH 跳转嵌套;原始参数的拒绝规则不变
- 新增回归测试,同步更新协议契约和提案 Note(含 SSH 连接配置界面的字段映射参考)

* fix(remote): 服务退出前等待进行中的文件请求完成,避免残留临时文件

- 断线或 server.shutdown 后,服务在清理进程组之后最多再等 5 秒,让文件请求完成,不在写入途中退出
- 进行中请求计数改为 Mutex + Condvar,支持有界等待;上限和 BUSY 行为不变
- 新增断线时写入仍在进行的回归测试;同步协议契约和提案 Note

* feat(agent): 新增 Codex / Claude Code 原生 Hook 管理 (#1459)

* feat(agent): add native Hook library for Codex and Claude

* feat(agent): align Hook editor with reference form layout

* fix(hooks): show feedback when Windows search has no matches

* fix(macos): shell 退出后自动关闭终端标签页 (#1456)

- TerminalSession 新增 onEnded 回调: 进程自行退出时通知宿主; 宿主主动 stop、restart 或启动失败不触发
- 交互式终端 shell 退出 (Ctrl+D / exit) 后复用既有关闭路径: 移除标签并重选相邻会话, 最后一个终端关闭时隐藏终端面板
- 调试与运行终端不挂接回调, 进程结束后保留输出, 由调试会话负责清理

Co-authored-by: Lichenkang <2188718831@qq.com>

* feat(remote): 远端后端补全——文件监听、终端、登录环境、隧道与断线重连 (#1461)

* feat(remote): 远端后端补全——文件监听、终端、登录环境、隧道与断线重连

- 服务改为会话与连接分离:常驻会话(--connect/--daemon)断线后终端和构建继续运行,事件重放给下一个连接,空闲超时后结束
- 所有子进程统一由专门的创建线程启动,修正 PR_SET_PDEATHSIG 跟随线程导致误杀的问题
- 新增目录遍历、文件监听(inotify / FSEvents)、PTY 终端、登录环境解析、TCP/Unix socket 隧道、监听端口列表、fs.copy/realPath/setPermissions、server.ping/state
- 资源 id 改为客户端分配;结束进程和关闭终端时信号发给整个会话
- 客户端新增按资源分发事件、强类型 API 和本地端口转发
- 按功能拆分端到端测试;更新协议契约、提案 Note 与功能矩阵

* fix(remote): 连接结束时关闭常驻进程保留的 socket,避免代理进程滞留远端

常驻进程为“新连接顶替旧连接”保留了每个连接 socket 的一份描述符,连接结束后
它仍然打开,代理收不到结束信号,每次断开都会在远端留下一个卡住的代理进程。
BSD/macOS 上对端半关闭后 shutdown 会返回 ENOTCONN,所以改为真正关闭这份描述符,
并新增回归测试。重连相关测试耗时从约 2.3 秒降到约 0.3 秒。

* test(remote): 端口转发测试改为通过共享句柄关闭会话,消除与桥接线程退出的竞态

* fix(remote): 修复代码审查发现的 10 个问题

- fs.copy:拒绝把文件复制到自身(同一路径、经过符号链接的任一方向、硬链接),避免截断源文件;在解析链接之后检查目录是否复制进自身
- fs.copy:socket、FIFO、设备文件不复制,作为复制对象本身时返回 UNSUPPORTED,在目录树里跳过并计数,避免打开 FIFO 永久阻塞
- tunnel:新增 tunnel.shutdownWrite,先写完排队数据再半关闭;端口转发在本地半关闭时使用它,响应照常返回
- 事件带递增 seq,服务端保留到客户端 server.ack 确认为止,连接断开时队列和内核缓冲区里的事件不再丢失
- 新增 server.resume:握手后等客户端订阅完再续传,重连后接上的终端能收到断开期间的输出
- 后台每 500ms 清理只为剩余成员保留的会话,kill 和关闭终端前先清理,缩小 pid 复用的风险窗口
- 会话存活检查合并为一次进程表扫描;kill 和关闭终端改在工作线程执行,不再阻塞有顺序要求的输入
- 常驻进程收到 shutdown 后先删除 socket 再回复;新常驻进程等待旧进程释放锁而不是静默退出;代理等待时间延长到 30 秒
- accept 失败(如 EMFILE)时退避,不再空转刷日志;PortForward 同样处理
- macOS lsof 退出码 1 视为成功(无匹配或无权检查部分进程)
- 每个问题都有回归测试;同步更新协议契约和提案 Note

* feat(macos): 插件声明式原生界面与公共控件统一 (#1351) (#1423)

* feat(macos): add declarative native plugin UI and unified public controls

* fix(macos): preserve drafts and actions in shared tree interactions

* test(macos): locate history search independently of native prompt

* test(plugins): add dedicated shared button acceptance panel

* fix(plugins): include required nodes in button acceptance panel

* test(macos): exercise dependency sidebar context menu business result

* test(core): bound search source-cap fixture filesystem work

* test(windows): await descendant process termination by handle

* ci(windows): budget real submodule watch-context integration

* ci(windows): budget workspace integration and avoid rebuilding failed tests

---------

Co-authored-by: Yao Jingxi <23722032@bjtu.edu.cn>

* feat(remote): 远程开发连接窗口——SSH 连接配置、测试、主机信息与打开远程文件夹 (#1463)

* feat(remote): 远程开发连接窗口——SSH 连接配置、测试、主机信息与打开远程文件夹

- 欢迎页新增“远程开发”:左侧连接列表,右侧连接概要、连接/认证/远程项目/主机信息/高级设置分组卡片
- 认证方式支持自动、SSH Agent、私钥、密码;密码和私钥口令可记住到独立钥匙串服务 remote,只在首次被要求时自动填入,验证码、主机指纹和重复提问弹窗询问
- 测试连接显示系统、内核、CPU、内存、磁盘、运行时长、主目录和解析地址;IP 地区仅在用户点击时通过 ipinfo.io 查询
- 单连接启动:一条 SSH 连接完成探测、按 SHA-256 复用或上传远端服务并启动,密码主机只认证一次
- App 附带 Linux x86_64/ARM64 远端服务(scripts/build-remote-servers.sh,只读放在 Resources/RemoteServers)
- 打开远程文件夹:以 Application Support 下的空占位根目录打开工作区,文件树与编辑器两个端口按根目录路由到远端,保存带冲突检测
- lithe-core 新增 remote.probe/connect/readDir/readFile/writeFile/disconnect/authRespond
- 新增 Note、契约、功能矩阵、worktree 资源登记与测试

* fix(ci): 守护进程抢锁时不再连 socket 探测;Hooks 设置页改用完整搜索框

- lithe-remote-server: 抢锁失败的守护进程原先用 UnixStream::connect 判断是否已有守护进程在服务,
  这个探测连接会被获胜的守护进程当成新客户端,替换并断开真正的客户端连接,导致
  concurrent_connections_share_one_daemon 稳定失败。改为检查 socket 文件是否存在。
- AgentHooksSettingsView: 搜索框从 LitheSearchTextField + .litheSearchField() 改为 LitheSearchField,
  满足 LitheTextInputTests 对淘汰输入写法的检查。

* fix(remote): 退出时关闭远程连接;文档版本按会话和路径隔离;远程存在性来自主机列表;远程新建统一不支持

* fix(remote): 私钥路径含空格时加引号;失败分类前等 stderr 读完;连接后使用连接时的表单快照;占位目录名不折叠;主机定位排除更多非公网地址

* fix(remote): 关闭项目时释放远程连接;存在性检查共用目录列表;服务端二进制按平台惰性读取;保存超时随文件增长;退出时中止正在建立的连接

* feat(remote): 连接断开后提示并重连同一远程文件夹;新增 connection_closed 错误码

* 对齐 IDEA 的 macOS 数据库树与连接编辑器 (#1451)

* feat(macos): align database explorer and connection editor with IDEA

* fix(macos): stop database test sidecar on cancellation and document UI

* fix(macos): cancel database tree sidecars on collapse and release

* fix(macos): cancel collapsed table metadata and replace forced loads

---------

Co-authored-by: Xiaoyumuxi <23722032@bjtu.edu.cn>

* fix(agent): 合并每轮思考与工具过程,默认折叠展示 (#1464)

Co-authored-by: Xiaoyumuxi <23722032@bjtu.edu.cn>

* fix(lsp): Java 调用补全默认留空实参 (#1437) (#1440)

* fix(lsp): leave Java completion arguments empty (#1437)

* test(windows): await process exit signals and own fixture cleanup

* fix(java): retain plugin completion settings across configuration channels

* test(windows): budget multi-repository push integration cost

---------

Co-authored-by: lick <2188718831@qq.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* feat(i18n): 统一双端完整语言资源与构建时生成 (#1449)

统一 macOS 与 Windows 的完整中英文语言资源,使用 shared/i18n 作为唯一维护来源。

- 集中 9,078 条语义词条,保留 3,927 个 macOS 历史 key 与双端既有译文、默认语言和持久化标识。
- 在构建阶段生成 macOS strings、AppLanguage 和 Windows 类型化 catalog,移除 Windows 分散字典与原生双语条件文本。
- 校验语言覆盖、fallback、参数类型、原生格式 ABI、位置参数、生成结果及打包资源;运行时保持发行资源只读。
- 补齐跨平台 fixtures、功能矩阵、Agent Notes、工作树资源复用规则和三系统 i18n CI。
- 修复生成文件换行及 Node 测试文件期限问题,保留单项测试预算。

验证:Shared i18n 三系统 CI、Windows 完整 CI、插件 CI、macOS Rust Core 与 arm64 Release 包验证通过。macOS 总门禁剩余两个与基线相同的数据库树测试失败,已在 PR 记录;按维护者明确授权使用管理员权限合并,不包含无关测试修复。

Closes #1173

* docs(notes): 提议把数据库拆成双端共用的独立插件

记录数据库模块的双端评估(规则三份不一致、Windows 从未接上后端)
和插件化方案:组织仓库独立插件、网页界面、Rust 后端、官方签名,
主仓库只提供插件后端、宿主凭据、MCP 声明等通用能力。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(windows): 数据库后端未接入时如实标记并按普通文件打开

Windows 的数据库后端从未接入(backend-capabilities 中 database 为 false,
前端调用的数据库命令没有原生实现),但 .db/.sqlite/.duckdb 文件仍被送进
数据库查看器,功能矩阵也标为 implemented。

- getDatabaseTypeFromPath 遵循同一能力开关,后端不可用时这类文件走普通
  二进制/文本路由,打开与会话恢复共用此判断
- 功能矩阵中 Windows 的四项数据库能力改为 missing / not-applicable
- README 注明数据库工作台目前仅支持 macOS

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(database): 生产保护按词法判定危险 SQL,执行前先由后端确认

- sidecar 的危险 SQL 判定从字符串前缀/" WHERE " 匹配改为词法分析:去掉注释、
  字符串、引号标识符和 $$ 块;按语句逐条检查;WHERE 必须直接限定该
  UPDATE/DELETE(子查询里的 WHERE 不算);识别 WITH ... DELETE 与数据修改型
  CTE;DROP/TRUNCATE(含 ALTER ... DROP)需要确认;排除 FOR UPDATE、
  ON DELETE CASCADE、GRANT、MySQL TRUNCATE() 等非写入用法;MySQL/MariaDB
  与 PostgreSQL E'' 字符串按反斜杠转义处理,SQL Server 识别 [标识符]。
- 修复根因:执行前格式化会把 WHERE 换到新行,旧判定只认 " WHERE ",导致
  生产保护连接上所有带 WHERE 的 UPDATE/DELETE 都被拒绝。
- sidecar 新增不连库的 checkWriteProtection 方法;macOS 在生产保护连接执行写入
  前先问后端,需要确认时弹出原有确认框,避免批量执行到一半被拒。
- 补充 Rust 金样例测试与 Swift 预检测试。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(notes): 记录数据库插件化的签名、远程开发与 Windows 决策

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(plugins): 插件后端能力与函数协议 v2 宿主凭据服务

- 新增 level 3 能力 `backend` 1:插件自有的长驻进程,复用 serverProcess
  启动字段与安装审查(packagedBackend 等),需 `backend.launch` 权限和
  web 工具窗,不绑定 workspace(拒绝 ${workspaceStateDir})
- 新增权限 `credentials.store`,无 backend 时声明即无效
- launch plan 支持 `backend: true` 选择器,返回 `backend.hostServices`;
  `workspaceStateDirectory` 改为可选,仅在进程用到时必填
- 插件函数协议 v2:`lithe/host/credentials/{get,set,delete}`,Core 校验
  版本、授权与参数(key 字母表/长度、secret ≤16 KiB、拒绝未知字段),
  通过 `hostRequest` 事件交给宿主,宿主用新命令 `lsp.hostResponse` 应答;
  每会话最多 16 个未应答请求
- `lsp.startServer.hostServices` 传入授予的服务
- 契约 README、rust-core-api、schema、fixture 与黄金用例同步更新

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(notes): 记录插件后端、协议 v2 凭据与 Agent 工具走 lithe MCP 的决策

- 修正“Agent 到 app 里查找 lithe-db-mcp”的描述:它只被打包,从未被启动
- 记录后端每插件一个进程、宿主全局、授权由安装审查覆盖等取舍
- 凭据生命周期:停用/更新保留,卸载删除
- 按平台可执行文件不改契约;Agent 工具后续经现有 lithe MCP 暴露
- 待确认清空

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(agent): Claude 与 Codex 官方订阅支持多账号与手动切换 (#1457) (#1471)

* feat(agent): Claude 与 Codex 官方订阅支持多账号与手动切换 (#1457)

每个额外账号是官方 CLI 的独立配置目录(CLAUDE_CONFIG_DIR / CODEX_HOME),
Lithe 只保存名称和路径,不读取、复制或刷新任何凭据。

- Host:AgentLaunch 新增 claudeConfigDir / codexHome,只对各自的订阅模式生效且必须是绝对路径;
  Codex 的额度查询和已归档历史使用同一账号目录;Claude 已登录账号的邮箱和套餐通过 account 事件发给前端
- 设置页:Agent 管理里新增「订阅账号」卡片,显示邮箱、套餐、首选标记、5 小时/7 天用量条、重置时间、配速和「截至 …,本次未主动刷新」,用量更新逻辑放在 ⓘ 里
- 添加账号:在后台运行官方登录命令(claude auth login --claudeai / codex login),浏览器由 CLI 打开,不弹终端,可取消,5 分钟超时
- 切换:设为首选会重启该 Agent 的连接,回复中或等待授权时拒绝;额度耗尽不会自动换号
- 会话收藏、重命名、隐藏按「工作区 + Agent + 账号」分开保存,默认账号沿用原有标注
- 用量只是适配器最近一次推送的快照,按账号保存,Lithe 不调用 Anthropic 接口也不轮询
- 同步共享翻译、功能矩阵(agent-subscription-multi-account)和 Agent Note

* fix(agent): 技能列表与开关跟随首选 Codex 账号目录 (#1457)

* fix(agent): Claude 技能跟随首选账号目录,切换账号后刷新技能页,新账号名避免重复 (#1457)

* docs: plan Windows plugin parity with macOS (#1468)

* docs(notes): 规划 Java Support 独立分发与内置包迁移 (#1473)

* feat(macos): 宿主运行插件后端并通过 Keychain 提供凭据服务

- 新增 MacPluginBackendSessions:每个插件一个后端进程、应用全局共享,
  由插件网页首次调用 functions.* 时按需启动,以 ${stateDir} 为根目录和
  工作目录;插件停用时停止、重新启用后可再启动,包替换/卸载前停止且本次
  运行不再启动;设置变化时重启
- 后端会话以 hostServices 启动;LanguageServerRuntimeSession 处理
  hostRequest 事件并经新命令 lsp.hostResponse 应答(离开主线程发送)
- 新增 MacPluginCredentialStore:每个插件独立的 Keychain service,
  读取不弹密码框;卸载时随插件状态目录一起删除,停用/更新保留
- 网页桥接:functions.list/invoke 省略 instance 时调用本插件后端,
  不弹同意框(安装审查已覆盖);无后端的插件返回 plugin.web.forbidden
- 安装时校验后端打包可执行文件;hostCapabilities 声明 backend: [1]
- Swift 契约:launch request 的 workspaceStateDirectory 可为空、
  backendLaunchPlan、descriptor.declaresBackend、事件携带 method
- Core 修正:lsp.hostResponse 的字段按契约拼写为 hostRequestID,
  测试改为从线上 JSON 解码以覆盖字段名
- README 更新 macOS 宿主能力说明

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(macos): wait for backend host responses with a continuation instead of polling

The test-stability gate rejects real-time sleeps. The scripted Core now
resumes waiters as answers arrive, with a five-second watchdog.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(plugins): list the Rust SDK for plugin backends in the contract

sdk/rust in lithe-plugin-docs implements plugin-function protocols 1 and 2
with the credentials host service for packaged plugin backends, and its
sample backend runs an end-to-end scenario against Core.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(database): read the proxy URL the macOS client sends

The client encodes DatabaseConnection.proxyURL as `proxyURL`, but the
sidecar's serde camelCase name was `proxyUrl`, so a connection's proxy
command was silently dropped and connections went direct. The field now
reads `proxyURL` and still accepts `proxyUrl`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(database): end the SSH tunnel client with the request on every path

SQL Server and MongoDB requests opened a tunnel and never stopped its ssh
client, so each such request left an orphaned ssh process holding the
local port after the sidecar exited. MySQL, PostgreSQL, SQLite, Redis,
and Nacos stopped it only on their normal path. SshTunnel now kills and
reaps the client when dropped, which covers early returns and every
adapter.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(plugins): 插件网页桥接第 2 版加入文件对话框

插件后端是无界面的子进程,数据库插件导入导出、备份恢复和 DBX 导入都需要
用户选文件。桥接版本升为 2(lithe.version),新增 dialog.openFile 与
dialog.saveFile:对话框由宿主弹出并写明发起的插件,同一页面同时只开一个,
页面只拿到用户选中的绝对路径(取消为 null),读写交给插件后端;页面在对话框
打开期间关闭则拿不到结果。旧宿主返回 plugin.web.unknownMethod,页面据版本号
决定是否提供导入导出。

同步更新插件契约 README、网页内容 Agent Note 与跨平台功能矩阵。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(windows): 声明式插件宿主(契约 v1)——包存储、安装链、设置、运行计划与 Web 工具窗口 (#1424)

* docs(plugins): 提出 Windows 声明式插件宿主提案 Note

* feat(windows): 声明式插件宿主 v0 —— 包存储、启动校验与语言服务器启动接线

- 新增 src-tauri plugin_host 模块:包存储布局(app_local_data_dir/plugins 与
  plugin-state,bundled 从资源目录只读加载)、启动扫描(经
  plugins.declarative.validate 携带 hostCapabilities,拒绝包隔离并展示原因)、
  启动计划解析(packaged 入口拒绝 reparse point 与路径逃逸,runtime/
  systemCommand 走 PATH 与 LITHE_<TOOL>_PATH 约定)
- 共享 fixtures 验收:invalid-manifests.json 全部 154 个用例在 Windows 二进制
  内断言同一稳定错误码;合法样例按契约模式与 v0 能力门控模式分别断言
- 前端:resolve-editor-lsp-launch 在 Worker 扩展无服务器时回落契约插件启动;
  bootstrap 增加 declarative plugins 扫描步骤
- Note 转正为 implemented 并记录 M1 落地形状与 M2-M4 切分;矩阵
  declarative-plugin-contract Windows 状态随代码更新为 partial(pending)

* feat(windows): 声明式插件宿主 M2 —— 磁盘导入链、管理界面与版本探测

- plugin_host/install.rs:ZIP/目录→私有快照(拒绝 reparse point、路径逃逸、
  超限文件与恶意 ZIP 条目)→plugins.marketplace.installReview 全量审查→
  确认时摘要比对拒绝快照调包→staging 复验后激活;卸载、回滚、启用/停用
- launch.rs:runtime 启动按 versionArguments 探测实际版本,低于
  minimumVersion 拒绝启动;版本 token 解析容忍 v 前缀、引号与 go/java 输出
- 设置新增一级页"声明式插件(契约 v1)":安装审查卡(未认证发布者提示、
  权限与完整程序声明展开)、启用/停用/卸载/回滚,与 Worker 扩展分开列出;
  en-US 与 zh-CN 全套文案
- install_extension_from_url 等 Worker 非语言市场命令注册为显式占位错误
  (extensionStore.notAvailable),调用方得到可诊断失败而非命令不存在
- 矩阵 plugin-marketplace/plugin-extension-management/declarative-plugin-contract
  Windows 证据与 notes 随代码更新;Note 增补 M2 记录

* feat(windows): 声明式插件宿主 M3 —— 声明式设置、运行计划与契约 PHP 包

- 能力声明提升:languageServers [1,2]、settings [1,2],settings-v2 fixture
  由能力门控改为接受
- plugin_host/settings.rs:全局值(plugin-settings/<id>.json,默认值遗忘规则)
  与项目覆盖(工作区 .lithe/plugin-settings.json,空项清理、损坏拒写)双层
  存储;resolveSettings / storeSetting / workspaceConfiguration 三个命令;
  launch 请求现携带已存设置
- plugin_host/run_plans.rs:runPlan/testPlan 命令,展开 Core 模板后走共享
  run 链路(resolveRunLaunch → startRunProcess),进程归属复用 Worker 扩展
  的 ExtensionProcessOwner
- 设置编辑 UI:按声明 scope/effect 渲染控件,显示值来源徽标,immediate
  效果经 workspaceConfiguration 下推;show/hide 折叠进插件行
- Plugins/win/Official/PhpSupportContract:契约版 PHP bundled 包(API 2,
  launch kind runtime),随安装器资源分发;端到端测试覆盖 validate、
  runPlan、testPlan、resolveSettings。Worker 版 PHP 保留:其 composer
  scripts 动态运行动作在契约 v1 无等价能力,删除会造成功能退化,完整
  迁移推迟(Note 已记录)
- 矩阵 declarative-plugin-settings Windows partial、declarative-plugin-contract
  证据与 notes 更新;Note 增补 M3 记录

* feat(windows): 声明式插件宿主 M4 —— Web 工具窗口(ui 2)

- plugin_host/web.rs:lithe-plugin:// 自定义 scheme 只服务启用包内普通文件
  (拒 reparse point、路径逃逸、超 16MiB、非白名单扩展名),响应带
  CSP(default-src 'none'、拒 eval 与联网、frame-ancestors 'none')、
  nosniff、no-store、CORP
- window.lithe 桥 v0:document-start 注入冻结桥;context、
  ui.getState/setState(宿主持有状态,64KiB 上限)、workspace.openFile、
  事件泵;build.*/functions.* 在 Windows 构建系统能力接入前返回
  plugin.web.unknownMethod
- 页面生命周期命令:open(去重聚焦)/close;禁用卸载清状态
  (forget_plugin_state)
- 能力声明 ui 提升为 [1,2],web-panel fixture 转为被接受(门控测试同步)
- 管理区块新增 Web 工具窗口列表(打开/关闭),en-US/zh-CN 文案
- 矩阵 plugin-web-tool-windows Windows partial、declarative-plugin-contract
  evidence/notes 更新;Note 增补 M4 记录

* chore(windows): 清理 plugin_host/web.rs 未使用的 PageRequest 结构与 Deserialize 导入

* fix(windows): 修复插件宿主审查意见 —— 权限隔离、启动信封解包与端到端接线

P1(两项):
- 插件 WebView 脱离主窗口通配 capability:main.json 收窄为 main/workspace-*,
  新增 plugin-web capability(core:event 最小集,无 fs/http/shell/dialog);
  桥身份改由调用 webview label 反解(bridge_identity),核对插件启用、
  窗口声明与归属,伪造参数/跨插件/非插件窗口一律 plugin.web.forbidden
- launch 解包 Core 响应信封后再解析(outcome["plan"]),新增走真实
  Core 命令的回归测试(此前单测绕过了信封导致该路径必然失败)

P2:
- 设置编辑器按 ID 从宿主 catalog 取完整 manifest(新增
  declarative_plugins_manifest 命令),resolve/workspaceConfiguration 不再
  传 ID 占位清单;加载与解析错误保持可见
- 运行入口接通:新增 declarative_plugins_language_owner 归属查询,run
  动作发现接入 useRunActionDiscovery(source: declarative),运行菜单
  直接分发;删除会漂移的前端目录缓存
- 停用/卸载/回滚前关闭插件全部 Web 窗口并清状态;scheme 文件服务只服务
  enabled 包
- workspace.openFile 接前端监听(plugin-web-open-file.ts):限工作区根内
  路径,走 handleFileSelect(带 line/column)
- 版本探测宿主只跑 versionArguments,判断委托 Core
  checkRuntimeVersion(共享 runtime-versions 语义),删除自建解析器

* fix(windows): 修复第二轮 review 意见 —— IPC 命令隔离与端到端接线收口

P0:
- invoke_handler 包装插件页门控:label 为 plugin-web-* 的调用只允许
  declarative_plugins_web_bridge_request(改为直调的普通函数,消费原始
  Invoke,绕过宏推断问题),其余应用命令(run_start_process 等进程/文件/
  HTTP 面)一律 resolver.reject——插件页面无法再通过原始 Tauri IPC 调用
  宿主命令
- generate_handler 宏在非直接实参位置无法推断 R:用
  Box<InvokeHandler<Wry>> 在绑定处钉定(本地最小复现 crate 验证)

P2:
- initializePluginWebOpenFileListener 真正接入 bootstrap(此前只有定义)
- immediate 设置:编辑器取 Core 展开的 configuration 后经
  lsp.updateWorkspaceConfiguration 下推到运行中的 LSP 会话
- 停用/卸载时 Rust 发 declarative-plugin-lifecycle 事件,前端进程 owner
  停止该插件全部声明式运行会话
- test plan 产品入口:declares_tests 标记进入 catalog,运行菜单的声明式
  动作按插件测试模板走 testPlan(v1 传当前文件供项目标记判定)
- 同版本重装激活失败时备份/恢复原版本目录,不再出现安装记录指向缺失
  字节的隔离状态(新增恢复路径测试)

P3:
- 共享契约 README 更新 Windows ui: [1,2] 状态与桥 v0 方法范围

* fix(windows): close declarative plugin review gaps

* fix(windows): address plugin host review gaps

* fix(windows): harden declarative plugin page and probe boundaries

* fix(windows): drain declarative plugin owners before package changes

Preserve plugin identity and cancel in-flight starts; enforce launch requirements, scope web pages and events to their owners, and expose declarative UI contributions. Add bounded regression coverage and document the remaining parity work.

* test(windows): isolate plugin host in terminal lifecycle fixture

Keep the real activity rail and terminal docking coverage while stubbing declarative plugin state and native window launch at the feature boundary. This prevents the fixture's narrow pane mocks from being loaded by the unrelated workspace services.

* feat(macos): Agent 对话显示工具图片缩略图、点击放大,并将后台任务通知显示为状态行 (#1462) (#1472)

* feat(macos): Agent 对话显示工具图片缩略图、点击放大,并将后台任务通知显示为状态行 (#1462)

* feat(macos): 图片放大支持缩放,折叠过程显示缩略图,适配更多 Claude Code 特殊消息格式 (#1462)

* fix(macos): 导航栏不再把 Claude Code 特殊消息当作提问,图片查看器不再让转录重绘 (#1462)

* fix(macos): 修复 Agent 图片显示评审问题:id 去重、哈希、焦点、缓存与解析边界 (#1472)

- 图片 id 去重,避免 ForEach 重复 id
- 指纹改用 SHA-256,避免主线程逐字节循环
- 用户消息解析结果按消息缓存
- 查看器 ←/→ 仅在持有焦点时翻页,拖动限制在画面边缘内
- 只移除消息首尾的模型专用块,不吞用户中间引用的标签
- 图片按原文位置排序,超出上限的引用显示 +N
- read 只对存在的文件生成缩略图,解码失败显示占位
- 缓存限制成本,键含修改时间,解码任务随行取消
- 内联数据须能被 ImageIO 识别,否则退回文字条目

* feat(macos): 后台任务通知并入后续过程区,恢复 Claude 会话时补全压缩前的完整历史 (#1472)

- 成功的后台任务通知不再单独成行,进入随后一轮的折叠“思考过程”;失败、被终止或后面没有过程的通知仍显示
- Claude 的英文 shell 任务摘要按界面语言显示(后台命令已完成:…)
- Rust 宿主在 session/load 前只读取会话文件中最后一个压缩点之前的记录,转成回放更新,压缩前的用户消息、回复、思考和工具调用都能查看
- 读取范围:只读 projects/*/<会话 id>.jsonl,按所选账号目录解析,大小和条数有上限
- 新增翻译放在 shared/i18n,更新功能矩阵与 Agent Note

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* perf(macos): 后台通知判断复用用户消息解析缓存

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix(macos): 回放时相邻的用户消息不再合并成一条

连续的用户消息(例如后台通知后紧跟用户输入)在回放时被拼成一个气泡,导致通知标记无法识别而显示原文。
按上游 messageId 区分用户消息;压缩前的历史也带上记录 uuid。

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix(agent): 恢复 Claude Desktop 开始的会话时显示可读历史

- 宿主把 mcp__ccd_turn__wrap_up 改写成 Agent 回复,吞掉其后续 tool_call_update
- 宿主把 mcp__ccd_turn__update_plan(整表/增量)改写成完整 ACP plan 更新
- 压缩前文回放补上对话中途排队的用户消息(queued_command),工具调用带上 name
- 历史回放时计划快照作为清单显示在折叠过程之间,导出为任务列表,不计入消息数
- 折叠的过程标题附工具摘要(如运行了 N 条命令)

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>

* feat(plugins): list the database plugin and move the built-in module's data into it

- OfficialPluginCatalog lists dev.lithe.plugin.database as a publisher
  package downloaded from the marketplace; language-only fields move into
  an optional Entry.language, so a non-language plugin needs none.
- MacDatabasePluginMigration moves the former module's connections,
  folders, SQL history, and forever-kept passwords into the plugin's
  ${stateDir} and credentials once, before its backend first starts
  (MacPluginBackendSessions gains a prepareState hook). The old data stays
  for older Lithe versions; the plugin's own state always wins.
- Workbench notifications can carry one action and then stay until used.
  People with saved connections and no database plugin get one prompt
  with an "Open Marketplace" action.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* refactor: remove the built-in database module; the database is a plugin now

Lithe no longer ships a database module. The official plugin
dev.lithe.plugin.database (Lithe-IDEA/lithe-plugin-database) replaces it,
and the earlier commit moves saved connections into it.

- macOS: delete LitheDatabaseModule, the database views, adapters,
  recovery store, coordinator, sidecar locator, brand icons, dbx fixtures,
  and the database tool windows, editor tabs, theme tokens, console gutter
  and AppModel branches. Generic tests that used the database as a sample
  now use other modules. Dropdown/context-menu parameters only the database
  used are gone. Idle sleep keeps a visible module window open; only
  shutdown closes it.
- Rust: delete lithe-db-sidecar and lithe-db-mcp.
- Windows: delete features/database and its sidecar packaging, the
  databases extension contribution, and every database branch; openBuffer
  loses its two database-only parameters. No plugin adaptation yet.
- CI and scripts: delete the database workflow, validation docker setup
  and sidecar/MCP build and smoke scripts; packaging, preview, verifiers,
  CI change classification and lane reuse drop the database.
- i18n: drop strings only the removed UIs used and regenerate.
- Feature matrix, Agent Notes, README, docs and Skill: the database is an
  official plugin; the plugin note is implemented, the multi-schema tree
  note is archived.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(plugins): ship Database as a Lithe Store community plugin

Lithe's official signing path has never released a plugin and its v2
private key is out of reach, so the Database plugin is a community
plugin (io.github.lithe-idea.database, unsigned) listed in Lithe Store
like the other seven.

- OfficialPluginCatalog no longer lists the database plugin; the optional
  Entry.language refactor that only it needed is reverted.
- An unsigned plugin ID proves nothing, so MacDatabasePluginMigration now
  moves the old connections and passwords only into a copy installed from
  Lithe Store whose index entry names Lithe-IDEA/lithe-plugin-database.
  A copy from disk or another source gets nothing and leaves no marker,
  so installing from Lithe Store later still migrates. The backend
  sessions' prepareState hook receives the installation record for this.
- Feature matrix, README and the Agent Note describe the community plugin,
  why official signing is deferred, and the new trust boundary.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(database): record the macOS acceptance of the plugin migration

The migration from the former built-in module was accepted on a macOS
development-identity build: the one-time notice, installing Database 0.1.0
from Lithe Store, and the connections, folders, history, and passwords
arriving in the plugin as the Agent Note describes. The matrix marks the
migration row verified on macOS; the other database rows stay pending.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(agent): 恢复压缩过的 Claude 会话时保留压缩前用户消息里的截图 (#1479)

* fix(agent): 恢复压缩过的 Claude 会话时保留压缩前用户消息里的截图

* fix(agent): 压缩前历史回放的截图超过客户端大小上限时不再发送

* feat(agent): 兼容 Claude Desktop 会话独有机制,Agent 面板以卡片呈现 (#1480)

* feat(agent): 兼容 Claude Desktop 会话独有机制,Agent 面板以卡片呈现

- agent host 识别 Desktop 工具(章节、建议回复、任务、PR、目录、可视化),给出可读标题并在 _meta.lithe.claudeDesktop 中附带卡片
- claude.ai UUID 连接器显示为 Connector: <工具>
- macOS 面板渲染卡片:建议回复跟在回合总结后,卡片操作只填入输入框
- 可视化在禁网、禁导航的非持久 WKWebView 中渲染
- Desktop 事件包装与跨会话通知按上下文显示,不算用户发言
- 共享 LitheChipFlowLayout,更新 i18n、契约、Agent Note 与功能矩阵

* fix(agent): 可视化页面的 sendPrompt 只在用户点击或按键之后才填入输入框

* fix(agent): 按 review 修复可视化外链出口、任务失败记录丢失和压缩历史输入被截断

---------

Co-authored-by: Xiaoyumuxi <23722032@bjtu.edu.cn>
Co-authored-by: muchen <145200703+Mucheen@users.noreply.github.com>
Co-authored-by: 十二翼堕落天使 <61737634+icefery@users.noreply.github.com>
Co-authored-by: Lichenkang <2188718831@qq.com>
Co-authored-by: arkleselect <166632698+arkleselect@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant