Repository navigation
feat(plugin-api): 插件后端发起原生运行与调试,声明调试适配器行为与输出链接(API-22/23/30) - #1746
Conversation
Adds the Core side of the plugin-initiated Run and debug API (Refs #1495): - serverProcess 4: launches, runtime dependencies and runSelectedRuntime name tool definitions by ID, listed in the manifest's requiresTools; toolchains.instantiateLaunch expands a definition's launch template. Versions 1 and 2 keep their closed runtime lists. - run.decodeStart and debug.decodeBackendConfiguration validate the params of lithe/host/run/start and lithe/host/debug/start; run/stop and the run/didExit notification join the plugin-function host protocol with the run.start and debug.start permissions and plugin.host.toolUnresolved. - debugAdapters 3: adapter features (hot code replace, step filters) and defaults drive the debug engine instead of recognising an adapter by ID. - outputLinkMatchers 1: outputLinks.match and outputLinks.decodeResolution find console links from patterns the plugin declares. Fixtures cover each new request, rejection and manifest.
…output links README, schema, toolchains.md and rust-core-api.md describe serverProcess 4 tool references, run/start, run/stop, debug/start, run/didExit, debugAdapters 3 features and defaults, and outputLinkMatchers 1 (Refs #1495).
…e the registry builder
…through Rust Core
RunService starts a plugin run like a build provider run, reports its end exactly once, and keeps the output and the plugin's rerun action after it ends. The Run tool window shows such a run even without generated Run configurations, and Restart goes back through the plugin.
…in the project window
A plugin whose only contribution is console links still needs a module so the user can enable it and startup finds a factory. The module has no contributions, so such a plugin also activates without a restart.
…k matchers Rust Core matches the lines the console renders against the matchers of the enabled plugins. A located file opens like the host's own console links; a link with a resolve function asks the plugin's backend on click. Without any matcher the console does no extra work. The host now advertises outputLinkMatchers 1 and debugAdapters 3.
…code changes Adds the shared English and Chinese entries for the messages the plugin run host, the debug start and the generic Apply code changes action show, and regenerates the string tables.
…put links Add the three capability records, mark API-22, API-23 and API-30 in the plugin API plan with what this change opens, and correct the contract README: run/start and debug/start take a context, run/stop takes none.
…ink code The log usage check requires a reasoned log-exempt marker where a catch only returns or a try? discards the failure.
…run window port The test window could not conform to PluginRunWindowPort: the compiler inferred different sendability for the main-actor closure parameters of the async requirements across modules. The protocol, AppModel and the test window now all name them @mainactor @sendable.
Core's second empty-plugin check did not count outputLinkMatchers, so a plugin with nothing but console link matchers was refused as declaring no language server or execution provider. The contract now says matchers alone are a complete plugin. The run/stop test expected invalidParams for an unknown option; the contract and the host answer unsupportedOption with details.option, so the test now checks that.
- Plan doc: keep this PR's delivered API-22/23/30 rows, take preview's API-29 rows, and keep the C-LS setStatus note. - A declared features.hotCodeReplace now wins over the host's legacy service update, which only remains for adapters that declared nothing, matching the legacy_java narrowing in the debug engine. Adds a test that one button shows. - Contract README no longer names runtimes when describing the closed tool lists of serverProcess 1 to 3. - Lock the lowered counts: engine.rs nameComparisons 6 -> 5 and the manifest schema's schemaEnums 13 -> 5.
Lithe Review结论: 未发现需要阻塞合并的问题。以下四项均为非阻塞的 P2 建议。 Findings
Scope Check
Suggestions
Summary实现复用了现有执行与调试基础设施。建议补齐默认参数、动态链接失效、协议错误分类及 I/O 线程边界;现有 Core 和服务替身测试没有覆盖这些完整生产路径。 Verification
|
…un-debug-api # Conflicts: # rust/lithe-core/src/lsp/interface/mod.rs # rust/lithe-core/src/tests/declarative_plugins.rs # scripts/architecture/language-specifics-baseline.json # shared/contracts/plugins/v1/README.md # shared/contracts/plugins/v1/plugin-manifest.schema.json
…un-debug-api # Conflicts: # macos/Sources/LitheCoreContracts/Plugins/DeclarativePluginContracts.swift # macos/Sources/LitheModuleAPI/Plugins/PluginTypes.swift # rust/lithe-core/src/plugins/capabilities.rs # rust/lithe-core/src/tests/declarative_plugins.rs # shared/contracts/plugins/v1/README.md # shared/contracts/plugins/v1/fixtures/manifest/invalid-manifests.json # shared/contracts/plugins/v1/plugin-manifest.schema.json
# Conflicts: # macos/Sources/Lithe/Platform/MacOS/MacServiceContainer.swift # scripts/architecture/language-specifics-baseline.json # shared/contracts/plugins/v1/fixtures/manifest/invalid-manifests.json # shared/contracts/rust-core-api.md
Lithe 运行验收版本: 对照:共同祖先
未覆盖:
工作副本与运行状态已清理;可复用编译缓存按 12 GiB / 7 天预算保留。 |
合入 #1742(插件函数中转)。冲突全部是两边在同一位置各自新增: plugins 模块声明、HOST_METHODS 表(run/debug 与 functions 方法并存)、 错误码表(-32025 与 -32027..-32071 不重叠)、manifest 字段、 provider_query_trigger 与 runtime_tools、capability 列表、契约 fixture。
preview 合入了 #1745(插件自有语言服务器会话与后端决定启动方式)。冲突处理: - serverProcess 版本改为累积语义:选中运行时的调试适配器需要 2,后端 决定启动方式的语言服务器需要 3,requiresTools 需要 4;4 覆盖 2 和 3, 清单仍须声明覆盖所用特性的最低版本。capabilities 列表为 [1, 2, 3, 4], schema、契约 README 同步说明。macOS 宣告的版本保持 preview 的 [1, 3]。 - 主机通知沿用本分支的 grant 字段与 admitted(),admitted() 改用 #1745 的 holds_service,按方法授予的服务也能收到对应通知;run/didExit 与两个 languageServer 通知并存。 - 权限、错误码(-32022..-32026 按序)、通知参数校验、README 章节、契约 fixture、MacServiceContainer 的宿主服务注册、计划文档 API-22 行均取并集。
#1746 新增的 makeDeclaredFeature 仍用旧的 GenericDebugFeatureModel(sessions:) 初始化, 而本 PR 给初始化器增加了必填的 paging 参数,补上 paging: LinkedCoreDebugPaging()。 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* feat(core): #1662 车道 C 运行/调试下沉(RUN-03/06/07/14) - RUN-03:Core 新增 build.resolveTestRunOutcome 通用归约(超时/取消不声明测试结果,失败优先于退出码, 退出码 0 但没有执行选中测试判为失败);macOS LanguageTestService 与 Windows maven.store 改为调用,删除旧的按退出码判定 - RUN-06:Core 新增 debug.planVariablePage / reduceVariablePage;macOS 删除本地分页状态机; Windows 保留 named/indexed 数量,只自动请求非 expensive Scope(expensive 改为手动加载),请求携带 filter/start/count 并提供加载更多 - RUN-07:Windows 栈帧完整消费 sourceReference / instructionPointerReference / isFiltered,sourceReference 帧不再当磁盘文件打开 - RUN-14:Core 新增 debug.planDisassemblyWindow / reduceDisassemblyPage;macOS 删除本地窗口二分、负偏移回退与耗尽判定;Windows host 未开放 disassemble/readMemory,功能矩阵标明 - 共享 fixture、i18n 词条、rust-core-api 说明、功能矩阵与 v1 baseline 条目一并更新 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(macos): RUN-03 测试按新判定断言终态 带失败用例期望 .failed,零测试期望 .failed 并断言“没有找到任何测试”文案,正常通过仍期望 .passed。 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * 修复 rebase 后 DebugModuleTests 编译错误 #1746 新增的 makeDeclaredFeature 仍用旧的 GenericDebugFeatureModel(sessions:) 初始化, 而本 PR 给初始化器增加了必填的 paging 参数,补上 paging: LinkedCoreDebugPaging()。 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Refs #1495
这个 PR 做了什么
让插件后端可以请求宿主在 Run 窗口运行一个进程、启动调试会话,并在清单里声明调试适配器的行为和控制台输出中的链接。执行和展示仍由宿主负责,插件只提交请求。宿主和 Core 没有按适配器名新增分支。唯一带 Java 字样的新名字是
legacy_java,它把 preview 原有的 Java 判断收窄到旧适配器上,见下文“原有的 Java 特例”。API-23:
run/*与工具 ID 引用lithe/host/run/start、lithe/host/run/stop和通知lithe/host/run/didExit。需要requires.serverProcess: 4和权限run.start。${temporaryFile:<name>},运行结束后删除。plugin.host.toolUnresolved,details为{tool, reason},reason是notFound或unusable。process.run之上加了宿主的展示:Run 窗口条目、停止、再次运行。toolchains.instantiateLaunch(按用户选中的安装展开工具定义的启动模板)和run.decodeStart。API-30:
debug/start与适配器的 features、defaultslithe/host/debug/start,需要权限debug.start,只能使用调用方插件自己声明的适配器。配置由 Core 校验,noDebug和以__开头的键是保留键。debugAdapters升到 3。features.hotCodeReplace、features.stepFilters和defaults.stepFilters由共享的 Core 调试引擎执行,宿主不再按适配器名识别这些行为。debug.decodeBackendConfiguration。API-22:输出链接匹配器
outputLinkMatchers1。插件在清单里声明正则,Core 负责匹配并决定链接指向哪里,宿主只负责加样式和转发点击。scope可写run或test,不写表示两处都生效。resolve:直接捕获path/line/column分组,目标文件存在时才显示为链接。resolve:点击时调用插件函数取得位置。outputLinkMatchers算作贡献,会以 “declares no language server or execution provider” 拒绝这种插件;现已补上,并加了 Rust 测试,契约 README 的 “Output link matchers” 一节也写明了。outputLinks.match和outputLinks.decodeResolution。契约与文档
shared/contracts/plugins/v1/:fixtures/run/run-start.json、fixtures/run/output-link-matchers.json、fixtures/run/tool-reference-launch.plugin.json、fixtures/debug-adapters/debug-start.json、fixtures/debug-adapters/debug-adapter-features.plugin.json。README 顶部的 fixture 表在这两个目录的行里写明了它们。run/start和debug/start带context,run/stop不带。plugin-backend-run-start、plugin-debug-start-and-adapter-features、plugin-output-link-matchers。macOS 为已实现、待验证,Windows 为未实现。docs/development/macos-plugin-api-plan.md的 API-22、23、30 三行已更新。没有新增 API 编号。其他小改动
home,即用户所选安装的根目录,工具定义的启动模板可以用${home}引用它。按可执行文件选中的工具没有home。MacToolchainDiscovery.registry(of:),原有工具解析和新的启动模板展开共用。log-exempt理由。PluginRunWindowPort的闭包参数在协议、AppModel实现和测试替身里都显式写成@MainActor @Sendable。原来测试替身跨模块实现这个协议时,两边推断出的 Sendable 属性不一致,测试编译不过。run/stop测试里带未知字段force的请求,期望从invalidParams改为unsupportedOption,并断言details.option为force。宿主的实现本来就是这样回答的,与契约 README 中“方法未定义的字段返回 -32018”的规定一致,原来是测试写错了。原有的 Java 特例
这个 PR 只增加通用机制,不删除 Java 特例。下面这些原有逻辑要等 Java 插件接上新接口后再删:
adapter_id == "java"有三处判断:stepFilters、Launch 和 RedefineClasses。本 PR 把它们收窄为只对没有声明 features 的旧适配器(legacy_java)生效,已声明 features 的适配器一律走声明。features.hotCodeReplace时,GenericDebugFeatureModel只显示“应用代码变更”,原有的“更新服务”(canUpdateJavaService)只留给没有声明的适配器。这与调试引擎里legacy_java的收窄规则一致,同一个会话不会同时出现两个按钮,新增测试aDeclaredHotCodeReplaceReplacesTheHostServiceUpdateSoOneButtonShows覆盖这一点。java适配器工厂、步进过滤界面和 DevTools vmArg 本 PR 不动。已知限制
hostCapabilities暂不宣告serverProcess4,因为语言服务器启动和runSelectedRuntime还不能解析工具 ID。使用工具 ID 的插件要等 Java 迁移时一并宣告。debug.target {kind:"launch"}暂不支持,返回plugin.host.unsupportedOption,details.option为debug.target。configurationType下恰好有一个支持 attach 的适配器。attach 在run/start返回之后异步进行。${entry}的工具定义不能通过run/start的工具 ID 运行。didExit不带退出码或信号。features.hotCodeReplace.prepareFunction补上。.ask链接不参与上一处/下一处导航。run/stop按调用方插件 ID 限定,需要run.start权限。所以只有debug.start权限的插件,不能通过 API 停掉自己的调试会话。合并顺序与后续事项
projectGenerators2)已合入 preview(5665e6e59),本分支已合入并处理冲突,见“验证”一节。validate_server_process_version。语言服务器 PR 的后端启动要求serverProcess恰好为 3,本 PR 加 4。后合并的那个需要合入最新 preview,并保留语言服务器 PR 的版本语义。notFound。rust/lithe-core/src/debug/engine.rs的 nameComparisons 从 6 降到 5,plugin-manifest.schema.json的 schemaEnums 从 13 降到 5(tool的封闭列表改成工具定义 ID 引用)。插件自有语言服务器 PR(feat(plugin): 插件自有语言服务器会话与后端决定启动方式(API-25,含 API-12/20/22) #1745)也改了scripts/architecture/language-specifics-baseline.json,后合并的那个需要合入 preview 后重新运行--update-baseline。node scripts/contract.mjs sync --revision <合并后的 preview commit>同步契约。reference/protocol-changelog.md登记合入日期、本 PR、PR 作者,以及改动的协议:serverProcess4(requiresTools,运行时按工具定义 ID 引用)、debugAdapters3(features、defaults)、outputLinkMatchers1;run.start、debug.start;lithe/host/run/start、lithe/host/run/stop、lithe/host/debug/start和通知lithe/host/run/didExit;plugin.runtime.undeclared、plugin.run.invalidStart等。新版本号同时写进该页“按协议查首次出现”的表。
需要确认的问题
run/start运行进程时,是否需要首次授权确认?现在只靠run.start权限和插件包签名。debug.target {kind:"launch"},即由适配器自己启动进程?debug.start权限的插件,是否应该能通过run/stop停掉自己的调试会话?entitlements 和 Info.plist 都没有改。
验证
合入 preview c5c6812 后的复验
以 merge 方式依次合入 ef6f853、5665e6e59 和 c5c6812,带进了 #1744(Core 生成文件 URI)、#1747(插件契约 fixtures 按功能分目录)、#1748(Git watcher)、#1750(协议登记规则)、#1729(Windows 终端停靠宽度)、#1740(项目生成器工具字段,含 rustfmt 修正)、#1751(宿主方法按 API 编号登记)、#1752(删除工具链契约草案)和 #1730(编辑器 Provider 与编辑器动作第 2 版)。
前两次合并的冲突及处理:
git mv移到fixtures/run/和fixtures/debug-adapters/。引用这些 fixture 的 Rust 测试(declarative_plugins.rs、plugin_run_debug.rs)、Swift 测试(DeclarativeDebugAdapterConsoleTests)、契约 README 和三条功能矩阵记录都改到了新路径;仓库里没有残留旧路径。PluginOutputLinkTests中“没有匹配器的插件”和“resolve 匹配器需要后端”两个测试,原来按 fixtures 根目录拼接editor-actions.plugin.json,改为editor/editor-actions.plugin.json。capabilities.rs和 SwifthostCapabilities里两边取并集:projectGenerators用 preview 的[1, 2];debugAdapters、outputLinkMatchers、serverProcess保留本分支的版本;serverProcess4,见“已知限制”。projectGenerators、toolchains,本分支的outputLinks,以及原有的debugAdapters、grammars。合入 c5c6812 的冲突及处理:
MacServiceContainer:preview 的编辑器 Provider 服务和本分支的 Run 宿主服务、输出链接服务都保留;判断模块是否可用的闭包提成局部常量isModuleUsable,同时给插件回调和输出链接来源使用。shared/contracts/rust-core-api.md:保留本分支新增的toolchains.instantiateLaunch、run.decodeStart、debug.decodeBackendConfiguration、outputLinks.match、outputLinks.decodeResolution五个操作及其说明。invalid-manifests.json:两边的用例都保留。scripts/architecture/language-specifics-baseline.json:preview 删除了工具链契约草案,plugin-editor-actions.ts等文件的计数也下降了,基线随之更新;plugin-manifest.schema.json的schemaEnums降到 5,并用--update-baseline锁定。已知的 preview 问题:
scripts/architecture/verify-core.sh的服务边界检查要求每个 AppModel 扩展不超过 600 行,而 preview 的AppModel+CodeNavigation.swift已有 627 行,本 PR 没有改这个文件,所以本地这一项不通过。CI 工作流不运行verify-core.sh。复验结果(macOS、Apple Silicon 本地):
scripts/rust-core/verify-rust-core-static.sh(与 CI 相同,cargo fmt --check只查lithe-core):通过。cargo test -p lithe-core:共 1909 个测试,完整运行时 1900 个通过。另外 9 个remote::sessions::integration_tests失败,原因是两个工作树同时跑完整检查,本地 socket 报 EAGAIN(os error 35);单独重跑这一组,18 个全部通过。scripts/macos/test/test-macos.sh --filter,覆盖 PluginOutputLink、PluginRunHostService、PluginDebugAdapter、DeclarativeDebugAdapterConsole、DebugModule、PluginManagementPresentation、PluginEditorProvider、PluginEditorAction:11 个套件 258 个测试全部通过。verify-shared-contracts.sh、verify-module-boundaries.sh。git diff --check。.agents/skills/write-stable-tests/scripts/verify-test-stability.sh --platform all --base c5c68126b --head HEAD:通过。更早的验证
分支先 rebase 到 preview 的 c63bcd2,之后以 merge 方式合入 dbe8441(#1727)。合入时
docs/development/macos-plugin-api-plan.md有冲突:本 PR 已交付的 API-22、23、30 行用本分支内容,API-29 行用 preview 内容,插件自有语言服务器 PR 的 setStatus 备注保留。合入 #1727 后的复验(#1727 不改 Rust,合入时本 PR 的改动只涉及 Swift、契约 README 和基线):
node scripts/architecture/verify-no-host-language-specifics.mjs:每项计数与基线一致。scripts/architecture/verify-core.sh、scripts/architecture/verify-module-boundaries.sh、node scripts/i18n/verify-app-language-localization.mjs、node scripts/i18n/generate-i18n.mjs --check、日志用法与日志事件、git diff --check:全部通过。scripts/macos/test/test-macos.sh --filter 'PluginOutputLinkTests|PluginRunHostServiceTests|PluginDebugAdapterTests|DeclarativeDebugAdapterConsoleTests|DebugModuleTests|PluginManagementPresentationTests':9 个套件共 233 个测试全部通过。合入 #1727 之前的验证(均在 macOS、Apple Silicon 本地完成):
cargo test -p lithe-core:1908 个通过,0 失败(单元测试 1875 个,集成测试 33 个)。scripts/macos/test/test-macos.sh --filter 'PluginOutputLinkTests|PluginRunHostServiceTests|PluginDebugAdapterTests|DeclarativeDebugAdapterConsoleTests|DebugModuleTests':覆盖输出链接、Run 宿主服务、插件调试适配器、声明式调试适配器控制台、调试模块等套件,共 225 个测试(8 个套件)全部通过。scripts/architecture/verify-shared-contracts.sh、Rust Core 注释规范、Agent Note、功能矩阵及其变更检查。node scripts/i18n/verify-app-language-localization.mjs、node scripts/i18n/generate-i18n.mjs --check。scripts/macos/verify/verify-runtime-bundle-immutability.sh)、模块边界。git diff --check,以及改动的.rs文件的 rustfmt。node scripts/sdk-e2e.mjs --source <本工作树> --ref feat/1495-plugin-run-debug-api:构建、Java、Node、Rust 四组共 9 个测试全部通过。这一项是在 rebase 前的 896defbbb 上跑的;rebase 只带进 preview 中与本 PR 无关的 Git 颜色、跳转到行和 AutoBuild 改动。之后的 Core 修复只放宽了“只声明输出链接匹配器”的清单校验。cargo check --bin lithe-windows:只有 preview 原有的两个 Windows 专属错误(project_window_registry.rs的os::windows和as_raw_handle),本 PR 没有新增。Windows 实际构建以 CI 为准。