Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
2f8b0d5
feat(plugins): execute native build tasks in workspace providers (#1495)
Mucheen Oct 26, 2026
97783bb
Merge commit 'd369c9ab2f4385c1ac595aa46a9a5d2884709642' into codex/is…
Mucheen Oct 27, 2026
3e21778
feat(plugins): discover and execute native provider tests (#1495)
Mucheen Oct 27, 2026
ee0bdd5
Merge commit '32021a86f0c6c4ad2964dbbe3c2bb7854d84ad67' into codex/is…
Mucheen Oct 27, 2026
7e833e9
Merge preview baseline for provider run preparation
Mucheen Oct 27, 2026
0545723
feat(plugins): prepare and persist provider application runs (#1495)
Mucheen Oct 27, 2026
215f67d
feat(plugins): prepare native provider debug sessions (#1495)
Mucheen Oct 27, 2026
58ca81c
feat(plugins): share read-only provider model inputs (#1495)
Mucheen Oct 27, 2026
be5a105
Merge preview and verify native Provider workflows (#1495)
Mucheen Oct 27, 2026
0eca520
Merge preview TCP debugging while preserving Provider identities (#1495)
Mucheen Oct 28, 2026
9f702e1
fix(build): isolate producer revisions and own run saves
Mucheen Oct 28, 2026
f582bf3
feat(plugins): Java Support 独立分发、迁移与按需安装 (#1483)
Mucheen Oct 28, 2026
2cc32e6
docs(plugins): inventory Maven and Java migration for #1495 (#1513)
Mucheen Oct 28, 2026
360255a
merge: resolve preview conflicts for #1517
Mucheen Oct 28, 2026
5784b4c
fix(run): 统一跨平台启动环境、容错扫描与构建事件过滤 (#1543)
1lck Oct 28, 2026
9a78c66
docs(plugins): plan macOS public APIs and SDK documentation (#1548)
xiaoyumuxi Oct 28, 2026
e907686
merge: reconcile #1517 with latest preview run policies
Mucheen Oct 28, 2026
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 @@ -6,6 +6,10 @@

编辑器只依赖统一的语言能力接口,不直接绑定某一种语言服务器。轻量能力可以不启动外部进程;需要 LSP 时,由 Rust Core 统一管理进程、协议和结果。以后新增语言服务,应接入这条公共路径,而不是在 Swift 和平台层各写一套生命周期。

### 通用 Runtime 与 Java 领域适配的范围

本笔记的通用 LSP 传输、会话、文档版本和取消边界仍然适用。下文记录的 Core `languages/jdt.rs` 与 Swift Java 专属语义只是当前实现位置;[#1495 的迁移提案](../../proposed/architecture/2026-10-26-maven-java-domain-plugin-migration.md) 将逐项替换并删除这些领域分支,不另建第二套通用 LSP Runtime,也不把当前目录位置视为长期归属要求。

## 问题

语言能力不应等同于"已经启动一个 LSP 进程":轻量本地能力(关键字、当前
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,19 @@ Run 控件,也不在 `java-run-launch` 或平台 adapter 再做一次 `blocksR
用户点击后可以在准备状态可见的同时排队等待 Core。否则快照更新时序会产生“面板
已就绪、启动仍被准备中拦截”的自相矛盾状态。

### 每一步使用自己的工具链环境(#1216)

Windows 曾先填入自动发现的 JAVA_HOME,再用“仅为空时插入”应用 Maven JDK,
导致用户选的 Maven JDK 永远无法覆盖先填的 Java 值。两个宿主现在调用 Core 的
execution.resolveEnvironment:继承环境低于当前步骤选定的工具链,用户显式
字符串最高。Maven 资源处理步骤即使继承主程序的 Java 绑定,也选择 Maven JDK;
后续 JVM 保持项目 JDK。Windows 环境键按不区分大小写处理。

平台仍负责定位可执行文件与 JDK home,Core 不探测机器、不执行 Maven,也不
复制上游构建模型。不要在 Windows 调换两次 insert 就结束:这会让后续前置
步骤继续各自解释优先级。共享 fixture 和真实 Windows 宿主解析测试覆盖选定
Maven JDK、显式覆盖及资源步骤;#1133 的 Maven 原生资源步骤保留,不改成手工复制。

## 考虑过的备选方案

- 先执行 `mvn compile`,再手工猜 `target/classes` 与依赖:被否。自定义输出目录、
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ PHP Support 已经验证了独立插件包、固定 Intelephense 版本和插件

插件包不编译、不链接任何 Swift 代码,也不做 codesign,因此与架构和宿主构建无关。

唯一的例外是自带运行时的 Java Support:它的包里有每个架构各一份的 JDK,因此与架构有关,并且只随应用发行、由应用的代码签名覆盖。它的组装步骤在插件自己的目录里,见 [Java 语言服务器是一个声明式插件](2026-10-13-java-language-server-as-declarative-plugin.md)。
唯一的例外是自带运行时的 Java Support:它的包里有每个架构各一份的 JDK,因此与架构有关,当前仍随应用发行,内置副本由应用的代码签名覆盖;独立安装副本要求完整包的发布者签名。双架构发布输入与迁移已准备,官方索引完整上架后构建会省去内置资源;自动上架仍暂停,见[按来源校验与独立发布基础](2026-10-25-java-plugin-distribution-foundation.md)。它的组装步骤在插件自己的目录里,见 [Java 语言服务器是一个声明式插件](2026-10-13-java-language-server-as-declarative-plugin.md)。

下载和组装逻辑放在插件专属的准备脚本里(PHP 迁出前是 `prepare-php-language-server.sh`,已随迁移删除)。后续插件可以复用相同的构建阶段和校验结构,但不能把某个语言的路径、版本或下载地址硬编码到宿主应用中。

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,16 @@

## 先说结论

Java 的语言服务器 JDT LS(Eclipse 的 Java 语言服务器,提供补全、诊断和跳转)不再是 Lithe.app 里写死的一部分,而是官方插件 Java Support(`dev.lithe.plugin.java-support`)。插件包拥有 JDT LS、Lombok、调试和测试扩展,以及它运行所用的 JDK;`plugin.json` 声明这些文件在包内的位置和启动方式。这个插件随应用发行、默认启用,用户可以卸载和恢复。
Java 的语言服务器 JDT LS(Eclipse 的 Java 语言服务器,提供补全、诊断和跳转)不再是 Lithe.app 里写死的一部分,而是官方插件 Java Support(`dev.lithe.plugin.java-support`)。插件包拥有 JDT LS、Lombok、调试和测试扩展,以及它运行所用的 JDK;`plugin.json` 声明这些文件在包内的位置和启动方式。过渡期随应用发行、默认启用,用户可以卸载和恢复;完整双架构官方下载上架后默认应用省去资源,迁移与安装引导由[后续分发决策](2026-10-25-java-plugin-distribution-foundation.md)规定。

宿主不再知道 JDT LS 或 JDK 放在哪里。它只做两件事:按插件的声明启动语言服务器;为声明了 `jdt` 宿主集成(由宿主实现、插件按名字启用的一段专用逻辑)的服务器启用 Java 的工程模型、`jdt://` 虚拟文档、测试和调试支持。

对日常开发的直接影响:需要某个插件专属的资源时,在该插件的清单里声明;不要在宿主的通用代码里按语言或工具的名字加分支。

### 当前边界与后续迁移

本笔记记录资源声明式插件化的已实现状态;`hostIntegration: jdt` 及宿主 Java Run/Test/Debug 是这个中间状态的事实,不是长期保留要求。[#1495 的领域迁移提案](../../proposed/architecture/2026-10-26-maven-java-domain-plugin-migration.md) 已列出生产调用、上游所有者、数据和删除条件。后续应在通用能力与全部消费者切换后删除 JDT 宿主专属实现;此前不能仅因资源已进插件就宣称领域迁移完成,也不能提前删除仍被调用的功能。

## 问题

迁移之前 JDT LS 和声明式插件契约有三处不一致:
Expand Down Expand Up @@ -104,9 +108,9 @@ dev.lithe.plugin.java-support/

`LitheOfficialPluginVerifier` 的规则随之调整:Mach-O 原生代码只允许出现在清单 `packagedRuntime` 声明的顶层目录内;包内任何位置都不允许符号链接。

### 5. 随应用发行、默认启用、可卸载
### 5. 过渡期内置与独立安装

- **随应用发行**:Java 是主场景,首次启动必须离线可用,所以包在 `Lithe.app/Contents/Resources/OfficialPlugins/` 下,信任方式是 `sameTeamAsHost`(由应用自身的代码签名封住)。
- **过渡期随应用发行**:原设计为 Java 保持首次启动离线可用,过渡包在 `Lithe.app/Contents/Resources/OfficialPlugins/` 下,清单主签名要求为 `publisherPackage`,内置副本通过 `bundledSignatureRequirement: sameTeamAsHost` 依靠应用自身的代码签名;只有真实位于宿主 bundle 内且来源为 bundled 的副本能用这个例外。按来源校验与独立发布基础见[后续决策](2026-10-25-java-plugin-distribution-foundation.md)。
- **默认启用**:随应用发行的包替代的是内置功能,它的模块默认开启;下载安装的插件,模块清单默认值仍是关闭,但用户在确认窗口里确认的首次安装(插件市场、社区源、磁盘包)会把它的模块记为启用,重启后直接生效,与 IntelliJ IDEA 安装即启用一致;更新和重装不改用户已有的启用选择。否则构建插件装好后 Build 工具窗口不出现,用户会以为界面没有注入。
- **卸载**:app bundle 运行时只读,包本身删不掉。卸载记录在用户目录的 `<app-support>/Lithe/Plugins/.removed-bundled-plugins.json`,宿主重启后不再注册这个插件,并在那次启动时删除它的语言服务器状态(卸载后到重启前,语言服务器仍在运行并写入该目录,所以不在点击时删除;重启前恢复则不会丢失索引)。插件管理里仍然列出它并提供“恢复”。
- **卸载时 JDT 状态的清理**:JDT LS 的工作区索引(`<cache>/Lithe/language-servers/jdtls/`)和 Equinox 配置区(`jdtls-configuration/`)在宿主缓存里,不在插件自己的 `PluginState/<plugin-id>/` 下,插件包管理器删不到。所以由 `jdt` 集成自己清理:启动时 `pluginsDidLoad` 拿到扫描结果,如果没有任何“未卸载”的已安装插件声明 `jdt` 集成,就在后台删除这两个目录(不碰同目录下其他语言服务器的缓存)。扫描本身失败(拿不到已安装列表)、或插件已安装但启动时被拒绝,都不算卸载,状态保留。这样宿主既不用写死 Java Support 的插件 ID,也不需要把缓存搬进插件状态目录。
Expand All @@ -115,7 +119,7 @@ dev.lithe.plugin.java-support/
### 正确做法

- 语言服务器依赖特定运行时:把运行时放进插件包并声明 `packagedRuntime`。只有“用户机器上任意够新的版本都行”时才用宿主发现加 `minimumVersion`。
- 某个服务器需要宿主代码配合:做成具名宿主集成,集成要读的文件由插件在 `resources` 里声明。
- 现有服务器需要宿主代码配合时,按已声明的具名集成及 `resources` 解析文件;这不授权继续扩展语言专属宿主分支。新增或迁移领域能力按 #1495 的通用契约与后端边界处理。
- 插件只提供语言服务器、运行/测试/调试仍用宿主内置实现:在 `hostIntegration.capabilities` 里逐项声明。迁移一个语言到插件后,必须在打包出的应用里实际点一次工具栏运行、调试和测试面板;只跑集成测试发现不了能力目录里丢掉的标记。
- 插件专属的构建步骤:放在插件目录的 `assemble-package.sh` 里。

Expand Down Expand Up @@ -170,7 +174,7 @@ dev.lithe.plugin.java-support/
- Rust 引擎里仍按提供方 ID `java` 启用 JDT 适配;Java 的运行、测试和调试仍是宿主内置实现,尚未成为扩展点,由插件通过 `hostIntegration.capabilities` 声明后启用。
- Windows 仍把 JDT LS 和 JDK 放在安装目录里,没有接入这份契约。

尚未完成、需要单独提案的部分:把 `jdt://` 虚拟文档等协议扩展改成清单里的声明式特性;Debug、Run/Test 扩展点;Java Support 改为从市场下载;Windows 接入。
尚未完成、需要继续推进的部分:把 `jdt://` 虚拟文档等协议扩展改成清单里的声明式特性;Debug、Run/Test 扩展点;Java Support 的正式市场下载与迁移;Windows 接入。独立分发已具备来源签名校验和双架构发布基础,但自动发布暂停,计划见[独立分发提案](../../proposed/architecture/2026-10-24-java-support-independent-distribution.md)。

## 验证

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,20 @@

Lithe 现在用一套统一的构建模型描述所有项目级构建工具(Build Tool,例如 Maven、Gradle、Cargo、Go)。插件在 `plugin.json` 的 `buildSystems`(插件 API 级别 3)里用纯 JSON 声明:怎样认出工程、用哪个可执行文件、有哪些选项、任务、运行入口和测试,以及怎样读工具的输出。思路与 LSP 插件化相同:插件只提供数据,通用逻辑只在 Rust Core 实现一次。

Rust Core 负责校验声明、识别工程、展开每一条命令行,并把输出解码成统一的形状,通过 13 个 `build.*` JSON 命令交给宿主。宿主只负责找可执行文件、启动进程、监听文件和保存用户选择,代码里不按构建系统的名字写分支。因此社区插件不改宿主代码就能加入一个新构建工具。
Rust Core 负责校验声明、识别工程、展开每一条命令行,并把输出解码成统一的形状,通过 `build.*` JSON 命令交给宿主。宿主只负责找可执行文件、启动进程、监听文件和保存用户选择,代码里不按构建系统的名字写分支。因此社区插件不改宿主代码就能加入一个新构建工具。

映射(`map`)只从解码后的文档里挑值。挑值以外的逻辑由插件自己处理:读 JSON、YAML 清单,从工具读任务,计算父子关系,这些都交给插件自带的脚本输出规范格式(第 6 节)。声明和规范格式都表达不了的工具(Gradle Tooling API 等),由插件自带的 Provider 进程回答。Provider 就是语言服务器那种进程:共用启动字段、校验和启动计划,只多回答 `lithe/build/model`、`lithe/build/dependencies`,回复仍由 Core 解码(第 9 节)。

目前落地的是 Core、共享契约和 macOS 宿主(第 10 节)。macOS 为每个启用的构建系统各开一个工具窗口,向 Core 声明 `buildSystems: [1]` 和 `buildProviders: [1]`,并在用户点击加载模型或依赖时启动 Provider、发送 `lithe/build/*`;Windows 宿主还没有接入。API 3 的清单按能力分版本,声明式构建系统使用 `buildSystems`,两种写法的 Provider 都额外使用 `buildProviders: 1`;插件市场只在宿主声明支持对应能力时才列出 API 3 的版本,见[声明式插件按能力分版本](2026-10-17-plugin-capability-versions.md)。宿主接入和 Maven 迁移的计划见[构建系统 Provider 提案](../../proposed/architecture/2026-10-17-build-system-provider-api.md)。

### 当前实现范围与删除条件

这里的统一模型、Provider 和通用工具窗口已经落地;下文记录的 `MavenService`、Run/Debug/Agent 旧消费者及 Maven 导入兼容路径仍是当前实现,不能把它们解释为 Maven 领域迁移已完成或必须长期保留。[#1495 的迁移清单](../../proposed/architecture/2026-10-26-maven-java-domain-plugin-migration.md) 按入口列出替换与删除条件:最新宿主/匹配插件接管所有消费者并完成数据迁移后,删除旧服务、旧配置读取和 fallback。Build Provider v1 的模型/依赖能力与宿主执行声明式 CLI 任务,也不等同于插件后端已拥有构建执行。

### Provider 任务与测试执行补充(2026-10-26)

当前增加 `buildProviders: 2/3/4` 与 `litheBuild` 协议 2/3/4:原生 Build 任务、测试发现/执行和应用启动准备通过类型化请求进入同一个工作区 Provider,不要求网页,不使用插件私有函数。测试报告复用原有解析器,应用准备交给既有 Run 进程所有者。本文关于版本 1 仅有模型/依赖的说明仍适用于版本 1;具体版本准入、进度、取消与删除条件见[Build Provider 原生任务执行](2026-10-26-build-provider-task-execution.md)。这不代表命令模型运行配置、服务编排或 Java/Maven 业务迁移已经完成。

## 问题

在这次改动之前,构建工具的知识分散在三处:
Expand Down Expand Up @@ -233,7 +241,7 @@ Gradle 的 `offline` 和 `userHome` 是用户自己选的值,不是猜测,
macOS 接入规则(2026-10-18):

- `BuildSystemService` 在无进程检测后,用当前模型接受的有效选项调用 `build.languageImport`。只按返回的 `kind` 转发,不按插件或构建系统 ID 判断。Maven 安装路径来自 `MacBuildToolResolver.languageImportExecutable` 的被动发现,不执行版本探测、Wrapper 或运行时探测;找不到工具仍可使用 JDT 的默认安装设置。
- 一个 JDT 会话可同时带一个 Maven 和一个 Gradle 输入。检测到多个相同种类的实例时,先选工作区根,再选最浅的根,最后按路径和稳定 ID 排序;不合并不同 reactor 的 Profiles 或机器路径。没有对应插件输入时保留原 Maven 设置兼容路径;`MavenService` 仍是 Run/Debug/Agent 业务的现有提供者。
- 一个 JDT 会话可同时带一个 Maven 和一个 Gradle 输入。检测到多个相同种类的实例时,先选工作区根,再选最浅的根,最后按路径和稳定 ID 排序;不合并不同 reactor 的 Profiles 或机器路径。没有对应插件输入时,当前实现仍读取原 Maven 设置兼容路径;`MavenService` 仍是 Run/Debug/Agent 业务的现有提供者。这是待迁移状态:#1495 的 M3–M8 消费者完成切换后删除此路径,不作为新能力的失败回退。
- 打开项目、编辑器同步、Run/Debug、测试发现、Java 入口点与维护操作在启动前都受同一份准备结果约束。维护入口先结束模块激活和插件注册,再等待导入;首次启动在 Java 运行时准备完成后还要重新等待当前结果,因为此前已经准备好的配置可能在挂起期间失效。最后一次等待结束后直接调用同步启动,不能在二者之间再插入异步工作。入口携带包含重开代次的 `WorkspaceIdentity`,每个异步边界后重查并检查取消;同步启动入口在配置尚未准备好时拒绝启动,不能借旧 Maven 上下文绕过等待。
- 检测、选项或插件变化使导入结果失效并重新计算。命令模型加载后可能收窄可选值,因此发布模型和生效选项后也要重新归一化;受监听文件变化影响时,立即清除旧输入并取消旧检测,再沿用 500 毫秒合并等待重算,等待期间不能读取保存前的配置。直接发起的检测会取消尚未到期的合并任务,避免迟到的重复检测再次清空刚准备好的配置。完成时同时校验工作区代次、检测 UUID 和取消状态,再通知同一工作区的 Java 会话;Maven 优先原地更新,Gradle 等下次会话启动。若运行中的会话拒绝 Maven 更新(例如它启动时没有 Maven 输入),调用现有 `reloadJavaWorkspace` 恢复,不能只留下警告。Java 准备协调器串行持有这项恢复:新发布先取消并等待旧恢复结束清理,再应用最新配置;旧恢复取消了自己创建的会话时,新发布继续承担重启,不能把此时的 `noSession` 当成无需处理。工作区替换、关闭、停用 Java 或会话关闭会取消恢复;包含同路径重开的代次检查阻止旧任务启动新会话。等待者有 30 秒期限,各自取消只释放自己的 continuation;停止或重置取消所有等待者,旧检测不能清除新检测或更新新工作区。
- 停用或移除 Maven 构建插件后,没有插件或兼容输入的活动会话也必须清除旧 Profiles、settings、仓库和工具路径。会话管理器记录启动时实际传入的 Maven 上下文,仅向带过 Maven 输入的同一会话发送空配置;纯 Gradle 会话首次启动仍传 `nil`,不能为了将来清除而给所有 Java 会话注入空 Maven 输入。停止或清除会话时同时释放记录,重开后的会话不能继承旧配置的清除资格。
Expand Down
Loading
Loading