Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ Java 的语言服务器 JDT LS(Eclipse 的 Java 语言服务器,提供补全
- `launch.kind: "runtime"`:用运行时启动包内入口文件,不需要启动脚本。运行时有两种来源:插件自带(`packagedRuntime`,宿主只启动包内这一个文件),或由宿主发现并按 `minimumVersion` 检查版本。
- 启动模板变量 `${pluginDir}`、`${stateDir}`、`${workspaceStateDir}`、`${arch}`,以及 `initializationOptions`。
- `settings`:用户可调的选项(整数、枚举、布尔),在启动模板里写 `${setting:<id>}` 引用。Java Support 用它暴露 JDT LS 的最大堆内存和日志级别,决策见 [声明式插件设置](../feature/2026-10-14-declarative-plugin-settings.md)。
- `hostIntegration`:`{ id, capabilities, resources }`。只有 `dev.lithe` 命名空间的插件可以声明,因为它让受信任的宿主代码去读插件的文件。
- `hostIntegration`:`{ id, capabilities, resources }`。任何插件都可以声明,不再限于 `dev.lithe` 命名空间(最初只给官方命名空间,2026-11-05 放开)。放开的理由:集成虽然是宿主代码,但只读取声明它的插件自己包内的资源,并把它们交给该插件自己启动的语言服务器或 Java 子进程(扩展 bundle、Lombok agent、测试运行器、调试),没有给插件增加任何权限;普通插件经用户在安装确认窗口确认后,本来就能运行自带的服务器进程。宿主不认识的集成名仍以 `plugin.integration.unsupported` 拒绝。构建系统的 `hostIntegration`(目前只有 `maven`)是另一个声明,仍只给官方命名空间,规则见[构建系统插件契约](2026-10-17-build-system-plugin-contract.md)。
- 两个 Core 命令:`plugins.declarative.languageServerLaunchPlan` 展开启动计划,`plugins.declarative.checkRuntimeVersion` 解析并比较运行时版本。

API 1 的行为完全不变:已发布的 PHP、Go 包声明 API 1,其参数里的 `${...}` 仍按字面量传递。
Expand Down Expand Up @@ -177,6 +177,10 @@ dev.lithe.plugin.java-support/

能把 Java 的全部逻辑搬出宿主,也是 Maven 这类带业务逻辑的模块最终需要的形态。但它要先设计取消、超时、崩溃隔离和权限,而 JDT LS 的启动和资源归属用声明就能解决。两者不冲突,协议可以之后单独提案。

### `hostIntegration` 继续只给官方命名空间

最初的做法。它假定“集成运行受信任的宿主代码,所以只能让官方插件用”。2026-11-05 放弃:Java 插件改为普通插件(不再区分官方和普通插件),这条限制会让它的下载版被宿主拒绝;而且限制没有保护到东西,因为集成读取的路径都必须在声明它的插件包内,交给的也只是这个插件自己启动的进程,普通插件经用户确认安装后本来就能运行自带的服务器进程。放开后宿主仍只执行自己实现的集成,不认识的名字被拒绝,所以普通插件拿到的是“按名字启用一段宿主已有的逻辑”,不是执行任意代码的新途径。

## 后果

收益:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@

### 2. ID 和执行权限不能靠声明自证

工具 ID 是显式关联,不靠命令名关联。社区插件定义自己的工具时使用 `<pluginID>:<tool>`;不带前缀的短名只允许经宿主验证的官方签名插件定义。这里的“官方”来自安装验证后的发布者身份,不能来自清单中的自称字段、插件 ID 前缀或显示名称。重复 ID 拒绝后来的注册者,不允许覆盖已有定义。
工具 ID 是显式关联,不靠命令名关联。任何插件都可以定义不带前缀的短名(如 `java`),也可以定义限定名 `<pluginID>:<tool>`;宿主不再给 Core 提供“是否官方”的来源证明(2026-11-05 起,原先短名只允许经宿主验证的官方签名插件定义)。限定名的前缀必须是定义者自己的插件 ID,所以不同插件的限定名不会冲突。

短名可能撞车。同一个短名被多个已启用插件定义时,它不归属任何一方:这些定义一个都不注册,其余定义照常注册,`toolchains.registry` 的结果用 `conflicts: [{tool, pluginIDs}]` 报告每个被争用的工具(按 `tool` 排序,`pluginIDs` 也排序)。被争用的工具不会出现在 `toolchains.discoveryPlan` 里,使用方解析它时按“无人声明”处理。macOS 设置页为每个冲突显示一条诊断,提示用户只保留一个插件启用;Swift 不替用户挑插件。插件 ID 重复仍然整批拒绝,不允许覆盖已有定义。

社区提供方可以回答 `java` 等短名,但结果只对它已声明、请求已授权、且存在已启用定义的工具生效。提供方不能通过返回 `git` 的同名文件取得宿主命令替换权。安装审查须列出被影响的工具、运行的后端和探测参数;`toolchains.provide` 的说明必须表达“影响工具选择”,不能只说读取目录。

Expand Down Expand Up @@ -140,6 +142,8 @@ macOS 的声明式路线由 `MacToolchainDiscovery` 执行,宿主不认识任
- **安装发现只用提供方。** 表达能力最强,但目录规律固定的工具也要打包原生后端、走进程生命周期,并在安装后重启;这类工具保留声明式扫描作为不运行插件代码的路线。
- **让版本管理器直接改 PATH 或注入任意命令。** 能解决 Dock 的环境缺失,却把发现权限扩大成替换宿主程序的权限,也丢掉工具 ID、来源和使用方关系,因此不采用。
- **提供方主动推送并为每个项目常驻。** 可减少部分查询,但增加生命周期与一致性成本;当前请求式方案已有取消、期限和输入失效边界,先不新增常驻推送协议。
- **短名只允许经宿主验证的官方签名插件定义(旧规则)。** 它能防止社区插件占用 `java`,但需要宿主向 Core 提供“是否官方”的证据,并要求每个定义短名的插件都是官方插件。2026-11-05 放弃:Lithe 不再区分官方插件和普通插件,Java 插件以普通插件 `io.github.lithe-idea.java-support` 发布,这条规则会让它无法定义 `java`;改用限定名又会让使用方(例如 Maven 的 Java 前置条件)写死某个 Java 插件的 ID。
- **短名先到先得,或按插件 ID 排序决定归属。** 这两种做法都能给出唯一答案,但顺序可以被恶意插件操纵:先到先得让它抢在 Java 插件前面启用,按插件 ID 排序让它起一个排在前面的 ID,结果都是 `java` 指向它自己的可执行文件布局。排序结果还会因为用户装了一个无关插件而改变。因此改为“争用即不归属”:谁都拿不到,用户在设置页看到冲突和涉及的插件,自己决定保留哪个。
- **每个运行时一条选择链或一个设置表单。** 局部实现直接,但 JDK、Maven 和其他命令继续出现不同优先级;选择、显示与执行会再次漂移,因此采用同一候选机制和通用展示骨架。

## 验收标准
Expand All @@ -157,7 +161,8 @@ macOS 的声明式路线由 `MacToolchainDiscovery` 执行,宿主不认识任

## 风险

- **声明会影响启动目标。** 清单 schema 只能检查形状,不能证明官方身份、文件存在或可执行;实现必须同时具备安装验证、平台文件证据、Core 通用限制和启动边界复核。
- **声明会影响启动目标。** 清单 schema 只能检查形状,不能证明文件存在或可执行;实现必须同时具备安装验证、平台文件证据、Core 通用限制和启动边界复核。
- **短名争用会让工具暂时没有人声明。** “争用即不归属”能防止抢占,但一个用户确认安装的插件也能通过定义同名短名,让 `java` 在它启用期间没有任何定义,相关设置行和使用方随之报告缺少定义。此时设置页能列出涉及的插件,用户停用其一即可恢复;宿主不会静默改变任何启动目标,也没有为此增加自动裁决。
- **版本比较再次泄漏工具语义。** 已安装版本需要统一的可比较结果,未知版本不能靠工具名修补;Java 8 的特殊输出应由定义的探测规则处理,无法规范的版本不能静默参与“最新”选择。
- **文件监听遗漏或查询失败。** 新建文件、符号链接替换和丢失事件可能留下旧快照,必须覆盖目录身份变化和失败状态;不能把失败翻译成“已更新”。
- **源优先级仍可能冲突。** 原生与兼容声明之间、多个原生项目要求之间不能仅靠稳定排序得到业务答案;需要明确冲突结果与用户可行动入口。
Expand All @@ -171,7 +176,7 @@ macOS 的声明式路线由 `MacToolchainDiscovery` 执行,宿主不认识任
- `./scripts/agent-notes/verify-agent-notes.sh`:中文笔记格式、生命周期、链接与路径。
- `./scripts/architecture/verify-shared-contracts.sh`:现行共享契约及 JSON 有效性;不检查 Core 语义,语义由下面的 Core 测试保护。
- `./scripts/platform-feature-matrix/verify-platform-feature-matrix.sh`:矩阵记录实际 Core 切片与平台待接入状态,不把纯数据测试标成产品运行时已验证。
- `cargo test --manifest-path rust/Cargo.toml -p lithe-core --lib toolchain_definitions -- --test-threads=1`:短 ID 来源、重复归属、嵌套字段失败即拒绝、只报告安装的提供方,以及定义插件为自己的工具声明提供方。
- `cargo test --manifest-path rust/Cargo.toml -p lithe-core --lib toolchain_definitions -- --test-threads=1`:任何插件可定义短 ID、多个插件定义同一短 ID 时都不注册且 `conflicts` 排序稳定、其余定义照常注册、重复插件 ID 整批拒绝、嵌套字段失败即拒绝、只报告安装的提供方,以及定义插件为自己的工具声明提供方。
- `cargo test --manifest-path rust/Cargo.toml -p lithe-core --lib toolchain_pins -- --test-threads=1`:目录按组件继承、失效数据、跨平台路径语法、数量边界和 legacy 数据保留。
- `cargo test --manifest-path rust/Cargo.toml -p lithe-core --lib toolchain_resolution -- --test-threads=1`:通过正式命令验证四层选择、真实回复解码、冲突和版本规则,以及设置页候选的登录 Shell home、跳过原因和自动选择;文件事实与探测结果由隔离快照注入,不访问本机工具。
- macOS 稳定性测试 `--filter 'MacToolchainDiscoveryTests|ToolchainSettings'`:真实临时目录与注入的 home 和探测,验证扫描、隐藏项与未匹配条目、工作区链接不探测、同版本冲突、拒绝的声明不扫描、Core 解析出的生效层与未满足要求、固定值只在自己的目录生效且不进入自动检测,以及隔离预览样例清单通过 Core 准入;不运行本机安装的工具。
Expand All @@ -198,8 +203,8 @@ Build 和 Provider Run 新增独立的运行前解析,复用这里的扫描、
设置页的检测结果来授权进程。用户目录 pin 只读,解析后重新核对原生路径、安装与来源
文件身份、工作区上下文及插件清单;Wrapper 只在显式执行时允许,不作被动版本探测。

Maven 社区插件使用 `<plugin-id>:maven` 定义,Java Support 的短 ID 仍要求独立官方来源
证明。`executableResolution: 2` 同时供工具定义和已有 Build toolchain 候选使用,不能把
Maven 社区插件使用 `<plugin-id>:maven` 定义。短 ID(如 `java`)不再要求独立官方来源
证明,任何插件都可以定义;多个已启用插件定义同一短 ID 时都不注册(见第 2 节)。`executableResolution: 2` 同时供工具定义和已有 Build toolchain 候选使用,不能把
后者误判成“没有定义就未使用能力”,也不能放开旧候选的未知字段。Windows 和旧 Java
消费者的切换尚未完成,原有选择链只可随真实消费者迁移逐项删除。

Expand All @@ -220,6 +225,7 @@ Maven 社区插件使用 `<plugin-id>:maven` 定义,Java Support 的短 ID 仍
- **每行读哪个目录。** 有固定值的行读固定值所在目录的结果;其余行读最近一个有自己版本文件的目录(没有就是根目录)。
- **已知限制。** 一是 `PATH` 上的命令永远不会被 Core 选中,因为页面不传 `commandHomes`;Core 跳过所有层时,页面把这条命令当作“版本未验证”的兜底显示,后续见 [#1641](https://github.com/1lck/Lithe-IDEA/issues/1641)。二是 `mvnw`、`gradlew` 这类项目文件候选不参与解析,因为 `discoveryPlan` 不提供它们的路径,也没有项目代码授权;要支持它就得改插件契约,不在本轮做,后续见 [#1640](https://github.com/1lck/Lithe-IDEA/issues/1640)。
- **冲突要用户选,现在只能看。** Core 遇到同层版本管理器不一致时返回 `chooseProvider`,遇到同版本的多个安装时返回 `chooseInstallation`,并且明确不允许靠排序替用户决定。页面现在只显示冲突原因,没有选择按钮,因为写入还没实现。计划中,用户的选择存成本机 `local.json` 里的固定值:固定值格式已在契约里,优先级最高,还会被 `.lithe/.gitignore` 排除。`providerChoices` 的存放位置契约里没有定义,单独保存它需要先改契约。选择入口、固定值的添加与切换以及 Lithe 全局默认的写入,后续见 [#1639](https://github.com/1lck/Lithe-IDEA/issues/1639)。
- **短 ID 争用只显示,不选择。** `toolchains.registry` 返回的 `conflicts` 每项对应设置页上的一条诊断,内容是被争用的工具和涉及的插件,并提示只保留一个插件启用。页面不在 Swift 里挑一个插件,也不给被争用的工具生成行;用户停用其一后,下一次加载时工具恢复。


### 阶段 D 的使用方默认值与符号继承(实现中)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ A0 提交时的基线快照(以 baseline 文件为准):

| 编号 | 决定 |
| --- | --- |
| Q1 | 2026-11-05 改定:不再区分官方插件和普通插件,Java 插件和 Cargo、Maven、Gradle 一样是普通插件,ID 为 `io.github.lithe-idea.java-support`,vendor 为 `Lithe Community`,`signatureRequirement: "none"`,不再带发布者签名和 `packageTrust`,从外部仓库 [Lithe-IDEA/lithe-plugin-java](https://github.com/Lithe-IDEA/lithe-plugin-java) 构建,由 Lithe Store 自动收录。工具短 ID `java` 保留。E1 必须先做两件事,否则宿主会拒绝这个包:一是去掉 `languageServers[].hostIntegration` 按 ID 命名空间判定官方的限制(`plugins/declarative.rs` 的 `is_official_namespace`);二是允许普通插件声明不带 `:` 的短工具 ID(`toolchain/definitions.rs` 的 `verifiedOfficial` 要求)。旧 ID `dev.lithe.plugin.java-support` 按 [#1357](https://github.com/1lck/Lithe-IDEA/pull/1357) 迁移 Go 和 PHP 的做法处理:保留在 `OfficialPluginCatalog` 并填写 `communityReplacementID`,引导用户换装新 ID。在此之前 Java 仓库只发预发布 |
| Q1 | 2026-11-05 改定:不再区分官方插件和普通插件,Java 插件和 Cargo、Maven、Gradle 一样是普通插件,ID 为 `io.github.lithe-idea.java-support`,vendor 为 `Lithe Community`,`signatureRequirement: "none"`,不再带发布者签名和 `packageTrust`,从外部仓库 [Lithe-IDEA/lithe-plugin-java](https://github.com/Lithe-IDEA/lithe-plugin-java) 构建,由 Lithe Store 自动收录。工具短 ID `java` 保留。E1 必须先做两件事,否则宿主会拒绝这个包,两件事都已完成:(a) `languageServers[].hostIntegration` 不再按 ID 命名空间判定官方,任何插件都可以声明(构建系统的 `hostIntegration: maven` 不变,仍只给官方命名空间,后续整体删除);(b) 普通插件可以定义不带 `:` 的短工具 ID,`toolchains.registry` 不再接收 `verifiedOfficial`,多个已启用插件定义同一短 ID 时按“争用即不归属”处理:这些定义都不注册,结果里的 `conflicts` 列出它们,macOS 设置页为每个冲突显示一条诊断。旧 ID `dev.lithe.plugin.java-support` 按 [#1357](https://github.com/1lck/Lithe-IDEA/pull/1357) 迁移 Go 和 PHP 的做法处理:保留在 `OfficialPluginCatalog` 并填写 `communityReplacementID`,引导用户换装新 ID。这项迁移推迟到 lithe-plugin-java 发布第一个 Release 时再做,否则会把用户引向不存在的插件。在此之前 Java 仓库只发预发布 |
| Q2 | E1 之后旧版 1.1.0 必须更新,不保留兼容翻译 |
| Q3 | 共享前端内置的 TextMate 语法、主题、文件关联里的 Java 项,算通用语言目录数据,进白名单 |
| Q4 | 作废:不做商店索引 v2 |
Expand Down
2 changes: 2 additions & 0 deletions macos/Resources/en.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -4693,6 +4693,7 @@
"Tokens of context this Agent may use. The context ring reads as full at this size. Codex applies it as its context window; for Claude Code the model decides its own size, so this sets where it compacts when no threshold is given. Leave empty for the Agent's default. Applies after reconnecting." = "Tokens of context this Agent may use. The context ring reads as full at this size. Codex applies it as its context window; for Claude Code the model decides its own size, so this sets where it compacts when no threshold is given. Leave empty for the Agent's default. Applies after reconnecting.";
"Too many files to check for one tool; some installations were skipped." = "Too many files to check for one tool; some installations were skipped.";
"Tool" = "Tool";
"Tool %@ is defined by more than one enabled plugin (%@), so none of these definitions is used. Keep only one of these plugins enabled." = "Tool %@ is defined by more than one enabled plugin (%@), so none of these definitions is used. Keep only one of these plugins enabled.";
"Tool Window" = "Tool Window";
"Tool Windows" = "Tool Windows";
"Tool activity (%lld)" = "Tool activity (%lld)";
Expand Down Expand Up @@ -9815,6 +9816,7 @@
"native.toolchainSettings.theProjectRoot" = "the project root";
"native.toolchainSettings.theSavedToolchainSettingsAreInvalid" = "The saved toolchain settings are invalid.";
"native.toolchainSettings.tooManyFilesForOneTool" = "Too many files to check for one tool; some installations were skipped.";
"native.toolchainSettings.toolDefinedBySeveralPlugins" = "Tool %1$@ is defined by more than one enabled plugin (%2$@), so none of these definitions is used. Keep only one of these plugins enabled.";
"native.toolchainSettings.toolDefinitionInfo" = "This row comes from the tool definition of an enabled plugin. Lithe has no built-in tools.";
"native.toolchainSettings.toolchainSources" = "Toolchain Sources";
"native.toolchainSettings.toolsInfo" = "Each tool uses the first source that has a value: a fixed version, then project version files, then global defaults, then automatic discovery. Installed versions are checked by running each tool's own version command. Enabled version managers report what version files ask for.";
Expand Down
Loading
Loading