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 @@ -33,7 +33,7 @@ Issue #1351 要把 Maven、Gradle 这类插件从“只给声明”推进到“
| 插件提供插件函数 | 插件 | 插件后端 | `lithe/function/invoke` |
| 插件调用宿主能力 | 宿主 | 宿主 | `lithe/host/*`,按协议版本逐个开放 |

开发者判断时只问一句:**结果要不要被 Lithe 理解?** 要被 IDE 工作流、展示层或另一个平台使用的,就是领域能力,必须有类型化契约;只给插件自己界面用的,才是插件函数。
开发者判断时先问:**宿主需要理解哪个能力的数据?** 参与构建等原生领域工作流的结果走对应领域契约;高亮、文档和编辑器动作走独立扩展点的类型化契约,不因宿主需要展示就强塞进 Build/LSP/Debug。插件私有业务继续用插件函数,独立扩展点可以在用户操作时绑定同一插件的函数;边界见[独立插件能力与领域契约](2026-10-31-plugin-capability-and-domain-boundaries.md)。

### 2. 禁止回调自己

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

## 先说结论

安装、更新、回退、卸载、启用、停用一个插件时,只有“它的每一项贡献在宿主里都有运行期实现”的插件才免重启生效。判断由宿主后端决定,写在 `PluginDescriptor.canActivateWithoutRestart`,不是 `plugin.json` 里的字段,所以插件契约没有变化,也不需要同步 lithe-plugin-docs。这条规则目前只落地了第一阶段:只有“纯调试适配器插件”(只贡献 `debugAdapters`,以及它声明的语言和设置,没有后端、没有其他模块)满足条件。
安装、更新、回退、卸载、启用、停用一个插件时,只有“它的每一项贡献在宿主里都有运行期实现”的插件才免重启生效。判断由宿主后端决定,写在 `PluginDescriptor.canActivateWithoutRestart`,不是 `plugin.json` 里的字段,所以插件契约没有变化,也不需要同步 lithe-plugin-docs。这条规则目前落地了两类:第一阶段的“纯调试适配器插件”(只贡献 `debugAdapters`,以及它声明的语言和设置,没有后端、没有其他模块),和第二阶段的“纯语法高亮插件”(只贡献带 `grammar` 或编辑配置的语言,见 [独立插件编辑器 API](2026-10-31-plugin-editor-extension-apis.md))。两者也可以出现在同一个插件里。

满足条件的插件不进模块图,而是登记在一个**内存实时注册表**(`MacLivePluginRegistry`)里。注册表用后台线程扫描已安装目录,主线程只读取扫描结果快照。其他插件的路径完全不变:仍然写成 `.updateStaged`,等重启才生效。

Expand All @@ -23,7 +23,7 @@

### 1. 由后端能力决定,不是清单字段

`canActivateWithoutRestart` 现在的定义是:有调试适配器、没有 `backend` 声明、模块列表恰好是 `[debugAdaptersExtension(<插件 id>)]`,且该模块没有其他贡献。
`canActivateWithoutRestart` 现在的定义是:没有 `backend` 声明、模块列表非空,且每个模块都是 `debugAdaptersExtension(<插件 id>)` 或 `grammarsExtension(<插件 id>)`,并且没有其他贡献。语法模块只承载启用状态,它的运行期登记、撤回和查找由 `MacPluginEditorLanguages` 完成(编辑器每次变化都收到完整的语言列表,撤回就是从列表里拿掉)。

- 正确做法:新增一种贡献(例如语言服务器)的热激活时,先实现它的运行期登记和撤回,再在这个谓词里放行。
- 错误做法:在 `plugin.json` 里加 `restartRequired: false` 让插件作者声明。作者不了解宿主哪些贡献有运行期实现;声明错了,用户看到的是“装上了但没生效”。
Expand Down Expand Up @@ -97,12 +97,13 @@
5. 传给 Core 的 `registrationGeneration` 是准备调试适配器时注册表的 `generation`,Core 只比较是否相等,不解释数值。
6. `stopSessions(ofPlugin:)` 只停该插件拥有的会话。会话记录的所有者是创建时选中的插件;同一个语言下另一个插件的会话继续运行。
7. debug-only 声明里的文件扩展名会并入语言;扩展名集合变化会让该语言的服务器按原有规则重启。
8. 目前仍然需要重启的贡献:语言服务器、运行/测试、构建系统、VCS、项目生成器、界面贡献、`backend`、网页窗口。后续阶段按“先有运行期登记和撤回,再放进谓词”的顺序逐类加入,每类单独验证。
8. 目前仍然需要重启的贡献:语言服务器、运行/测试、编辑器动作后端(因为它依赖 `backend`)、构建系统、VCS、项目生成器、界面贡献、`backend`、网页窗口。后续阶段按“先有运行期登记和撤回,再放进谓词”的顺序逐类加入,每类单独验证。

## 验证

- `macos/Tests/LitheTests/PluginLiveActivationTests.swift`:谓词的正反例(含契约 fixture)、debug-only 语言与插件 id 排序无关、注册表的收录/代数/启用/撤回/按 id 取第一个、后台扫描不在主线程、扫描失败保留旧登记、另一窗口的通知触发重扫、管理器的安装/更新/回退/启用/卸载流程。等待事件使用带本地期限的 `ChangeLatch`,不用真实 sleep。
- `LanguageProviderCatalogSourceTests`(debug-only 声明不抢语言、顺序无关、不触发扩展提示、每次 load 读取实时声明)、`DebugModuleTests`(`providersSource` 每次调用都查)、`LanguageIntelligenceModuleTests`(出现调试器不会停正在运行的语言服务器)。
- `macos/Tests/LitheTests/PluginEditorLanguagesTests.swift`:纯语法插件满足谓词、带后端的工具插件不满足;实时语法随插件出现和消失。
- `scripts/macos/verify/verify-runtime-bundle-immutability.sh` 和 `./scripts/agent-notes/verify-agent-notes.sh`。

## 适用范围
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Agent 笔记:独立插件能力与领域契约的边界

状态:已实现

## 先说结论

领域契约的目的,是让同一类事实和工作流只有一个稳定模型,而不是要求所有插件都成为语言、构建或调试提供者。普通工具插件可以独立使用高亮、文档和编辑器动作 API;底层复用同一个进程、函数调用或 JSON-RPC 通信机制,不改变它的业务归属。本笔记落地的是设计与审查规则,不表示下文提到的工具链、配置编辑或编辑器扩展提案已经全部实现。

## 问题

用户在三组讨论中反复指出同一种偏差:实现者为了接入已有模块,把工具专属知识重新写回宿主,或者把独立能力强行套成某个领域操作。

- [PR #1581 的方案评论](https://github.com/1lck/Lithe-IDEA/pull/1581#issuecomment-6498462433):版本管理器的别名、版本文件覆盖规则和安装布局属于插件/上游;封闭的 `miseToml | toolVersions` 枚举不等于通用扩展。新增另一种管理器应只改插件,不改 Core。
- [PR #1581 的后续评论](https://github.com/1lck/Lithe-IDEA/pull/1581#issuecomment-6499617033):查询和观察机制可内置,观察对象仍需声明;相关输入变化应撤销并重载整份查询结果。环境信息可以统一展示,工具专属设置必须由插件注入,而不是固定模板。
- [PR #1558 的正式评审](https://github.com/1lck/Lithe-IDEA/pull/1558#pullrequestreview-5715250513):不透明测试选择器、统一测试结果和通用运行选项合理;XML 专属配置绑定、`runtime: jvm`、固定 Maven 工具链名、固定 Java 准备任务 ID 不合理。调试应声明适配器与连接目标,不经宿主 Java 特判;临时迁移要单独跟踪退出条件。
- PR #1617 的本次设计讨论:HTTP 工具插件解析文本并提供高亮和按钮,不因此成为 LSP(语言服务器协议)、Build 或 Debug 插件;播放图标也不是接入原生 Run 工作流的证据。

以上评论中的示意字段和拆分顺序是各自提案的讨论材料,不作为已经发布的正式 API。

## 决策

### 按语义分三类,不按实现文件名分

| 类别 | 宿主需要理解什么 | 应放在哪里 |
| --- | --- | --- |
| 领域模型 | 构建目标、测试结果、调试会话等同领域事实 | 对应的类型化领域契约 |
| 独立扩展点 | 文档范围、图标、动作调用目标、语法资源等有限数据 | 独立的编辑器或宿主能力契约 |
| 插件业务 | HTTP 请求结构、版本别名、工具配置格式、框架启动参数 | 插件自身或成熟上游 |

旧规则“结果要被 IDE 理解就是领域能力”过宽。正确判断应是:宿主理解的是哪个稳定能力的语义?理解编辑器动作的范围和标题,不代表宿主需要理解 HTTP,更不代表它属于构建领域。

正确做法:HTTP 插件通过独立编辑器动作 API 绑定自己的函数;宿主只管理显示、明确点击、版本、取消和所有权。不要这样做:新增 `http`/`sql` 运行种类,让 Build Provider 报一个假任务,或者向通用命令通知加入专用 `runMarker` 对象。

### 共享机制,不共享不相干的业务模型

身份、权限、会话、能力发现、请求 ID、超时、取消、过期结果隔离和清理可以复用。不另建每工具一个进程/RPC 框架;也不因为复用了名字带 `lsp` 的内部传输实现,就要求普通后端提供语言智能。

插件参与已有原生领域时必须使用该领域的统一模型。例如向原生 Build 窗口提供工程模型不能改走私有函数逃过 Core 解码。独立 API 同样需要可校验的输入输出;“独立”不等于任意 JSON 直接进入界面或跨插件调用。

### 新工具接入不修改宿主的工具知识

工具定义负责可执行入口、探测和环境;提供方返回安装与作用域事实;使用方引用工具 ID。工具名、框架名、解析格式、任务用途之间的关联必须显式声明,不靠文件名巧合、魔法字符串或固定私有 ID。

配置格式及其优先级由工具/插件负责;宿主只管理已确认来源、版本冲突、安全写入和回读。声明的观察输入变化后撤销相关快照,不能保留一部分来自旧输入的“有效”结果。权限描述必须对应实际影响,发现运行时不能暗中获得替换任意宿主命令的权力。

### 版本演进不机械扩大

先复用已有 API,新增能力优先用已发布协议允许的能力发现和可选扩展。旧宿主可忽略的可选展示允许降级;不可忽略的启动、安全或必需行为需要明确准入。清单新增资源字段仍按该清单能力版本管理,不放宽严格解码来伪装兼容。所有公共变化照常更新契约、消费者和官方 SDK 验证,独立 API 也不例外。

## 考虑过的备选方案

- 全部经 LSP/Build/Debug 接入:现成模型多,但普通工具被迫提供假领域对象,宿主逐渐堆积专属分支,拒绝。
- 全部经无类型函数:接口少,却让宿主无法统一理解真正的构建、测试或编辑器贡献,绕过校验,拒绝。
- 每种工具单开一套协议:短期直接,但复制生命周期并让新增工具依赖宿主发版,拒绝。
- 用受限独立扩展点绑定既有函数:宿主只定义自己需要理解的数据,插件保留业务自由度,采用。

## 后果

收益是独立工具不会污染领域模块,真正参与领域工作流的插件仍共享一个模型;新增同类工具只改插件。代价是实现者必须先说明契约所有者、调用方向和第二个使用场景,而不是沿最方便的模块塞字段。已有历史特判不在一次功能 PR 中无界清理;新代码不能继续扩大,必要迁移记录退出条件。

## 验证

- `./scripts/agent-notes/verify-agent-notes.sh`:决策引用、路径和笔记结构。
- `./scripts/architecture/verify-service-boundaries.sh`:职责边界;不能替代人工审查工具专属分支。
- `./scripts/architecture/verify-shared-contracts.sh`:正式契约与 fixture 一致性。
- 审查时用两个语义不同的工具走同一扩展点,检查是否需要新增工具名枚举、宿主解析器或固定调用 ID;运行期验证继续遵循所属能力的验收和矩阵要求。

## 适用范围

- `.agents/skills/develop-lithe/SKILL.md`
- `.agents/skills/lithe-code-review/`
- `shared/contracts/plugins/v1/`
- `rust/lithe-core/src/plugins/`
- `macos/Sources/Lithe/Application/Features/`
- `macos/Sources/Lithe/Platform/MacOS/Plugins/`
Loading
Loading