Repository navigation
fix(desktop): 确认安装即启用插件,卸载先停进程再清理插件状态目录 - #1846
Merged
Merged
Conversation
- 商店、社区源或磁盘安装在审查框确认后直接启用插件;用户此前明确禁用过的选择保留,卸载清除选择后重装又会启用(pluginstate.EnableUnlessChosen、pluginmanager.EnableInstalled)。 - 卸载删除插件的整个状态目录 .state/<插件 ID>(含插件解压的 JDK 源码副本等),先改名进 .trash 再删除;其他插件和 host-secret 不动(pluginpkg.RemoveState、StateDirectory)。 - 卸载先停止语言服务器和插件后端,再删包和状态;禁用先记录禁用再停止后端(pluginservice.Service.Uninstall / Disable)。此前禁用、卸载都不停后端,卸载也是删完包才停语言服务器。 - 修正 TestContentProviderRegistrationRules 未加锁写 BackendHost.sessions 的数据竞争。 - 新增 Agent Note,更新功能矩阵;既有债务建单 #1841、#1842、#1843。 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1lck
marked this pull request as ready for review
November 13, 2026 07:07
This was referenced Nov 13, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
关联 Issue / Linked issue
PR 类型 / Type
改动说明 / What changes
背景 / Why
真实走一遍“Lithe Store 安装 Java Navigation → F12 → 卸载”时发现两个问题:
<插件根>/.state/<插件 ID>(例如解压出来的 JDK 源码)还留在磁盘上([Bug] Viva 卸载插件后残留插件状态目录 .state/<插件 ID>(如 JDK 源码副本) #1845)。排查时还发现:卸载是先删包、后停语言服务器;插件后端在禁用和卸载时都不会停止。改动 / Changes
启用(
pluginstate、pluginmanager、workbench)pluginstate.Store.EnableUnlessChosen:在同一把锁里,没有记录才记为启用;用户已有选择(启用或禁用)都保留。包注释改为说明这条规则。pluginmanager.Manager.EnableInstalled:确认插件已安装(否则返回ErrUnknownPlugin),再调用上面的方法。workbench.confirmPluginInstall:提交成功后(包括只有批准记录写入失败的ApprovalError)在同一个后台任务里调用EnableInstalled,失败记plugin_enable日志;修正原来“新安装默认启用”的误导注释。卸载清理状态(
pluginpkg、pluginmanager、pluginservice)pluginpkg.StateDirectory:.state的唯一定义;pluginservice的pluginStateDirectory改为引用它。pluginpkg.RemoveState(root, id):校验根目录和插件 ID,把.state/<id>改名进.trash再删除;只处理目录、不跟随符号链接,不存在不算错误。.state/host-secret和其他插件的目录不动。插件设置在偏好目录,不受影响。Manager.Uninstall在删除版本、批准记录、启用选择之后调用RemoveState;更新相关注释。停止顺序(
pluginservice、workbench)pluginservice/lifecycle.go:Service.Uninstall(ctx, id, server):先摘除并停止插件后端、停止语言服务器(等进程退出,有界),再Manager.Uninstall。Service.Disable(ctx, id, server):先记录禁用,再停止语言服务器和后端,停止期间不会被重新拉起。workbench.stopPluginServer拆出detachPluginServer(移出登记表、设墓碑、取消、撤诊断、释放文档,返回会话),stopPluginServer行为不变。workbench.uninstallPlugin:窗口线程先detachPluginServer,后台调用Service.Uninstall(原来是先删包,删完才停服务器,且不停后端)。workbench.setPluginEnabled(false):窗口线程先detachPluginServer,后台调用Service.Disable(原来不停后端)。启用路径不变。测试
pluginstate:TestEnableUnlessChosenRecordsOnlyAFirstChoice。pluginmanager:TestUninstallRemovesThePluginState、TestEnableInstalledKeepsAnExplicitChoice。pluginservice:TestUninstallStopsTheBackendBeforeRemovingThePlugin、TestDisableStopsTheBackend。workbench:TestConfirmedInstallIsEnabledAndUninstallRemovesItsState(从磁盘装一个没有程序的插件,确认后已启用,卸载后包和状态目录都不在)。TestContentProviderRegistrationRules未加锁写BackendHost.sessions的数据竞争(-race下失败;打开工作区会在后台 goroutine 里遍历 sessions)。文档与矩阵
.agents/notes/implemented/bug-fix/2026-11-13-viva-plugin-install-enables-and-uninstall-cleans-state.md。2026-11-10-viva-plugin-host-services-and-backend-sessions.md(原文说停用、卸载会停后端,此前并不成立;补充卸载删除.state/<id>),并在2026-10-25-java-plugin-distribution-foundation.md的“下载清单默认禁用”处加指向新 Note 的说明。plugin-extension-management.json:补证据路径、Viva 验证动作和本次 macOS 验收说明,状态不变(partial / pending)。不在本 PR 范围内 / Out of scope
build.go、debug_start.go、vcs.go三处写死".state":[Feature] Viva 工作台三处写死插件状态目录名 ".state",应统一用 pluginpkg 的定义 #1841。类型专属:fix
复现与根因
App.java状态栏“LSP 未启动”,F12 无反应;期望:直接启用,可以跳转。String.trim,再卸载。实际:<插件根>/.state/io.github.lithe-idea.java-navigation/0.0.1/jdk-sources/.../String.java仍在;期望:.state/<插件 ID>随卸载删除。pluginstate规定“没有记录即禁用”,confirmPluginInstall不写记录;pluginpkg.Uninstall明确不动状态目录,Manager.Uninstall也不删;uninstallPlugin先删包后停服务器;pluginservice.DetachBackend没有任何调用方。检查项
pluginmanager_test.goTestUninstallRemovesThePluginState:the plugin's state survivedpluginmanager_test.goTestEnableInstalledKeepsAnExplicitChoice:fresh: enabled = false ... want truepluginstate_test.goTestEnableUnlessChosenRecordsOnlyAFirstChoice:fresh: changed = falseworkbench/plugins_test.goTestConfirmedInstallIsEnabledAndUninstallRemovesItsState(暂存工作台改动后运行):the confirmed installation is not enabledpluginservice/lifecycle_test.go两个测试(去掉后端停止后运行):the backend was not stopped before the package was removed、the disabled plugin's backend was not stoppedManager.Uninstall只有工作台调用;stopPluginServer其余调用方(lsp_status.go)行为不变;DetachBackend原来没有调用方;pluginStateDirectory只在pluginservice内部使用。旧 Swift/Tauri 代码已移出本仓库。-race的已有测试数据竞争(一行加锁)。.agents/notes/implemented/bug-fix/记录范围检查 / Scope checks
功能矩阵 / Feature matrix
shared/platform-feature-matrix/features/plugin-extension-management.json:两端的实现状态和验证状态、证据路径、owner、验证动作都如实填写;没有运行验证的保持pending./scripts/platform-feature-matrix/verify-platform-feature-matrix.sh;改了平台实现路径的,还运行了./scripts/platform-feature-matrix/verify-platform-feature-matrix-change.sh origin/preview HEAD.artifacts/下生成的矩阵视图统一日志系统 / Structured logging
operationFailed事件(plugin_enable、plugin_uninstall两个已有 operation),没有新增事件、没有直接写 stderrgenerate-log-events.mjs --check和verify-log-usage.mjs:没有新增或修改日志事件声明,也没有新的日志调用方式界面文案 / i18n
N/A:没有新增或修改任何用户可见文字。仍运行了
verify-app-language-localization.mjs和generate-i18n.mjs --check,均通过。逻辑归属 / Logic placement
pluginpkg、pluginstate、pluginmanager)refactorIssue:这是缺陷修复,迁移需要新设计跨仓库的 Core 插件生命周期接口(C ABI、fixture、PINNED_CORE_REVISION),已提 [Feature] Viva 插件生命周期规则(启用选择、卸载清理与停止顺序)仍在 Go 平台层,应迁入 Rust Core #1842,本 PR 只在原有 Go 模块内补规则,没有新增平台层模块性能与内存 / Performance and memory
pluginInstallTimeout、pluginServerStopTimeout、backendStopTimeout),在后台任务里执行a.background里;窗口线程只做登记表摘除设置 / Settings
N/A:没有新增或修改设置项。
插件契约 / Plugin contract
N/A:没有改契约、能力版本、插件函数协议或宿主方法。
发行包与资源 / Bundle and resources
.state/<id>,并运行了scripts/desktop/verify/verify-runtime-bundle-immutability.sh(通过)无用代码与重构 / Dead code and refactoring
stopPluginServer仍被lsp_status.go使用)refactor标签的 Issue,没有在本 PR 顺手处理:[Feature] Viva 工作台三处写死插件状态目录名 ".state",应统一用 pluginpkg 的定义 #1841、[Feature] Viva 插件生命周期规则(启用选择、卸载清理与停止顺序)仍在 Go 平台层,应迁入 Rust Core #1842验证 / Verification
scripts/desktop/desktop-go.sh test ./... -count=1(加入后端停止前的版本)scripts/desktop/desktop-go.sh test ./internal/workbench ./internal/pluginservice ./internal/pluginmanager ./internal/pluginstate ./internal/pluginpkg -count=1(变基到 42d6fb9 后)scripts/desktop/desktop-go.sh test -race ./internal/pluginservice -count=3、./internal/pluginmanager ./internal/pluginstate ./internal/pluginpkg、./internal/workbench -run 'Plugin|TestConfirmedInstall'run-go-tests-with-timing.mjs(与test-stability-macos.sh相同阈值,7 个新增或改动的测试)verify-test-stability.sh --base origin/preview --head HEADverify-platform-feature-matrix-change.sh origin/preview HEAD、verify-platform-feature-matrix.sh./scripts/agent-notes/verify-agent-notes.shverify-app-language-localization.mjs、generate-i18n.mjs --checkscripts/desktop/verify/verify-runtime-bundle-immutability.sh-tags vivahead构建的客户端在无头模式下运行(画面为应用真实渲染),全新临时用户目录,线上 Lithe Store。依次断言:Store 列出插件 → 审查框 → 确认后“已启用” → 状态栏“LSP 就绪” → F12 跳到Greeter.greet→ F12 跳进 JDKString.trim→ 卸载 → 插件包、进程、.state/<插件 ID>都不在 → 再按 F12 不跳转、不重新拉起进程 → 退出后无残留进程未能执行的检查和原因:
scripts/desktop/desktop-go.sh vet和test -count=1:pluginstate、pluginmanager、pluginpkg、pluginservice、pluginhost全部通过(preview 42d6fb9 基线同样通过)。workbench包在这台机器上超过 Go 默认的 10 分钟上限(基线也超时,超时时正在运行的测试只跑了 7 秒,属于机器偏慢,不是卡死),没有得到结论,按维护者决定未再延长超时复测。Windows 特有的风险是删包时文件被运行中的进程占用,本 PR 已改成先停进程再删包,这一点没有实测。./...测试是在加入后端停止那部分改动之前跑的;之后只改了pluginservice和workbench,这两个包及其他受影响包在变基后已重新运行并通过。提交前确认 / Final checks
preview创建(已变基到 42d6fb9);目标分支preview.build/、target/、dist/、.artifacts/等产物,没有凭据、个人路径和未脱敏的日志或截图🤖 Generated with Claude Code