From a972d4204ce4c178d0314872119c11db8d435341 Mon Sep 17 00:00:00 2001 From: Mucheen <1528136628@qq.com> Date: Thu, 22 Oct 2026 14:58:19 +0800 Subject: [PATCH 1/5] feat(plugins): support configured build executable paths --- .../2026-10-21-plugin-settings-surfaces.md | 23 ++++++- macos/Resources/en.lproj/Localizable.strings | 2 + .../zh-Hans.lproj/Localizable.strings | 2 + .../Core/Rust/RustBuildSystemOperations.swift | 11 ++- .../MacOS/Build/MacBuildToolResolver.swift | 16 +++++ .../Platform/MacOS/MacServiceContainer.swift | 1 + .../Execution/BuildSystemContracts.swift | 9 ++- .../Services/BuildSystemService.swift | 21 ++++-- .../LitheModuleAPI/Plugins/PluginTypes.swift | 2 +- .../BuildSystemServiceTests.swift | 28 +++++++- .../MacBuildToolResolverTests.swift | 48 +++++++++++++ .../RustBuildSystemOperationsTests.swift | 8 +++ rust/lithe-core/src/build/commands.rs | 22 ++++-- rust/lithe-core/src/build/invocation.rs | 33 ++++++++- rust/lithe-core/src/build/manifest.rs | 22 +++++- rust/lithe-core/src/plugins/capabilities.rs | 2 +- rust/lithe-core/src/plugins/declarative.rs | 1 + rust/lithe-core/src/plugins/settings.rs | 16 +++++ rust/lithe-core/src/tests/build_systems.rs | 66 ++++++++++++++++++ shared/contracts/plugins/v1/README.md | 19 +++++ .../v1/fixtures/build-tool-path.plugin.json | 69 +++++++++++++++++++ .../v1/fixtures/invalid-manifests.json | 2 +- .../plugins/v1/plugin-manifest.schema.json | 8 ++- .../features/build-system-plugins.json | 7 +- .../features/cargo-build-plugin.json | 7 +- 25 files changed, 411 insertions(+), 34 deletions(-) create mode 100644 shared/contracts/plugins/v1/fixtures/build-tool-path.plugin.json diff --git a/.agents/notes/implemented/architecture/2026-10-21-plugin-settings-surfaces.md b/.agents/notes/implemented/architecture/2026-10-21-plugin-settings-surfaces.md index 97101f79b1..bfed95934d 100644 --- a/.agents/notes/implemented/architecture/2026-10-21-plugin-settings-surfaces.md +++ b/.agents/notes/implemented/architecture/2026-10-21-plugin-settings-surfaces.md @@ -65,9 +65,28 @@ macOS 设置窗口现在可以由插件“注册”页面:插件在 `plugin.js 为了保证“立即生效”真的不需要新进程,Core 在校验时拒绝把 `immediate` 设置用在命令行参数或 `initializationOptions` 里。 -### 5. 宿主能力版本 +### 5. 构建工具的可执行文件路径 -macOS 的 `hostCapabilities` 声明 `settings: [1, 2]` 和 `languageServers: [1, 2]`。Windows 还没有这些界面和推送,所以仍只声明 1,需要 v2 的插件在 Windows 上会被市场隐藏,而不是装上后行为不完整。 +只声明一个 file 设置不会改变构建进程。`buildSystems` 2 增加通用的 +`invocation.executableSetting`,引用全局 file 设置,生效方式为 reload 或 +nextRun。Core 负责校验引用和解析值;macOS 每次计划时读取该插件的全局值, +由平台 adapter 检查文件权限和版本,并把同一个路径用于模型 Provider 与构建、 +测试、运行。留空恢复自动发现。已指定路径失效时必须报错,不能回退到 PATH +中的另一份工具,否则模型与执行可能使用不同安装。工具父目录也放到进程 +PATH 前,供工具启动同目录的辅助程序。 + +路径只允许全局作用域,避免共享项目配置静默选择本机可执行文件。不要在 +Cargo 或其他插件 ID 下写宿主分支。插件只需声明 file 字段和引用;版本 1 +宿主通过能力协商拒绝安装,避免出现可保存但不生效的设置。 + +该设置写入既有用户偏好存储,没有新缓存或安装目录写入,不影响包签名和 +Sparkle delta。通用夹具 `build-tool-path.plugin.json`、Core 校验、Swift +路径解析与 Provider 失败回归覆盖这条边界。Cargo 专属真实执行回归仍由独立 +插件仓库维护;独立仓库的发布宿主 pin 必须在宿主变更提交后同步更新。 + +### 6. 宿主能力版本 + +macOS 的 `hostCapabilities` 声明 `settings: [1, 2]`、`languageServers: [1, 2]` 和 `buildSystems: [1, 2]`。Windows 还没有这些界面和推送,所以仍只声明 1,需要 v2 的插件在 Windows 上会被市场隐藏,而不是装上后行为不完整。 ## 考虑过的备选方案 diff --git a/macos/Resources/en.lproj/Localizable.strings b/macos/Resources/en.lproj/Localizable.strings index 9cf8fe9dfb..7649b309d3 100644 --- a/macos/Resources/en.lproj/Localizable.strings +++ b/macos/Resources/en.lproj/Localizable.strings @@ -2086,3 +2086,5 @@ "Zoom Out" = "Zoom Out"; "Reset Page Zoom (100%)" = "Reset Page Zoom (100%)"; "Page Zoom" = "Page Zoom"; + +"The configured build tool is not executable: %@" = "The configured build tool is not executable: %@"; diff --git a/macos/Resources/zh-Hans.lproj/Localizable.strings b/macos/Resources/zh-Hans.lproj/Localizable.strings index bc733d54e5..6876470521 100644 --- a/macos/Resources/zh-Hans.lproj/Localizable.strings +++ b/macos/Resources/zh-Hans.lproj/Localizable.strings @@ -3664,3 +3664,5 @@ "Zoom Out" = "缩小"; "Reset Page Zoom (100%)" = "恢复页面缩放(100%)"; "Page Zoom" = "页面缩放"; + +"The configured build tool is not executable: %@" = "配置的构建工具无法执行:%@"; diff --git a/macos/Sources/Lithe/Core/Rust/RustBuildSystemOperations.swift b/macos/Sources/Lithe/Core/Rust/RustBuildSystemOperations.swift index b348b153b7..754f7dd0b8 100644 --- a/macos/Sources/Lithe/Core/Rust/RustBuildSystemOperations.swift +++ b/macos/Sources/Lithe/Core/Rust/RustBuildSystemOperations.swift @@ -41,11 +41,13 @@ struct RustBuildSystemOperations: BuildSystemPlanning { return outcome.value.languageImport } - func invocationPlan(_ target: BuildSystemTarget, root: String) throws -> BuildInvocation { + func invocationPlan( + _ target: BuildSystemTarget, root: String, settings: [String: ToolingJSONValue] = [:] + ) throws -> BuildInvocation { let outcome: Outcome = try execute( "build.invocationPlan", target: target, - request: InvocationRequest(root: root, platform: "macos") + request: InvocationRequest(root: root, platform: "macos", settings: settings) ) return try outcome.value.invocation.invocation() } @@ -289,6 +291,7 @@ struct RustBuildSystemOperations: BuildSystemPlanning { private struct InvocationRequest: Encodable { let root: String let platform: String + let settings: [String: ToolingJSONValue] } private struct VersionRequest: Encodable { @@ -500,6 +503,7 @@ struct RustBuildSystemOperations: BuildSystemPlanning { } private struct WireInvocation: Decodable { + let configuredExecutable: String? let executables: [WireExecutable] let environmentInputs: [String] let runtimeDependencies: [WireRuntime] @@ -521,7 +525,8 @@ struct RustBuildSystemOperations: BuildSystemPlanning { ) }, versionArguments: version?.arguments, - minimumVersion: minimumVersion + minimumVersion: minimumVersion, + configuredExecutable: configuredExecutable ) } } diff --git a/macos/Sources/Lithe/Platform/MacOS/Build/MacBuildToolResolver.swift b/macos/Sources/Lithe/Platform/MacOS/Build/MacBuildToolResolver.swift index 342836daf8..3b55c0f26d 100644 --- a/macos/Sources/Lithe/Platform/MacOS/Build/MacBuildToolResolver.swift +++ b/macos/Sources/Lithe/Platform/MacOS/Build/MacBuildToolResolver.swift @@ -46,6 +46,18 @@ final class MacBuildToolResolver: BuildToolResolving { } var problems: [String] = [] + if let path = invocation.configuredExecutable { + let url = URL(fileURLWithPath: path) + guard path.hasPrefix("/"), fileStorage.isExecutable(at: url) else { + throw BuildToolResolutionError(String(localized: "The configured build tool is not executable: \(path)")) + } + environment["PATH"] = url.deletingLastPathComponent().path + ":" + (environment["PATH"] ?? "") + if let tool = try await accept( + url, invocation: invocation, environment: environment, + checkVersion: checkVersion, problems: &problems + ) { return tool } + throw BuildToolResolutionError(Self.unavailableMessage(displayName, problems: problems)) + } for candidate in invocation.executables { switch candidate { case .projectFile(let path, let requires): @@ -97,6 +109,10 @@ final class MacBuildToolResolver: BuildToolResolving { /// Project import needs the installation path for global settings, but /// must not run build code or a version probe merely by opening a project. func languageImportExecutable(_ invocation: BuildInvocation, workspaceURL: URL) -> URL? { + if let path = invocation.configuredExecutable { + let url = URL(fileURLWithPath: path) + return path.hasPrefix("/") && fileStorage.isExecutable(at: url) ? url : nil + } let environment = runtime.processEnvironment() for candidate in invocation.executables { switch candidate { diff --git a/macos/Sources/Lithe/Platform/MacOS/MacServiceContainer.swift b/macos/Sources/Lithe/Platform/MacOS/MacServiceContainer.swift index 898b37fe63..44360be73f 100644 --- a/macos/Sources/Lithe/Platform/MacOS/MacServiceContainer.swift +++ b/macos/Sources/Lithe/Platform/MacOS/MacServiceContainer.swift @@ -404,6 +404,7 @@ final class MacServiceContainer { ), runner: MacBuildCommandRunner(processRegistry: processRegistry), providers: buildProviderSessions, + settings: { pluginSettings.values(forPlugin: $0) }, sources: { // Enablement is read on every detection, so turning a // plugin off takes its build systems away at once. diff --git a/macos/Sources/LitheCoreContracts/Execution/BuildSystemContracts.swift b/macos/Sources/LitheCoreContracts/Execution/BuildSystemContracts.swift index fe90e005b7..0f7acce19f 100644 --- a/macos/Sources/LitheCoreContracts/Execution/BuildSystemContracts.swift +++ b/macos/Sources/LitheCoreContracts/Execution/BuildSystemContracts.swift @@ -427,6 +427,8 @@ package struct BuildModel: Equatable, Sendable, Decodable { /// The executables of one build system on this platform, in Core's order. package struct BuildInvocation: Equatable, Sendable { + /// Explicit global file setting; failure must not fall back to discovery. + package let configuredExecutable: String? package enum Executable: Equatable, Sendable { /// A wrapper script inside the project. Always runs project code. case projectFile(path: String, requires: [String]) @@ -467,11 +469,12 @@ package struct BuildInvocation: Equatable, Sendable { package init( executables: [Executable], environmentInputs: [String] = [], runtimeDependencies: [RuntimeDependency] = [], versionArguments: [String]? = nil, - minimumVersion: String? = nil + minimumVersion: String? = nil, configuredExecutable: String? = nil ) { self.executables = executables; self.environmentInputs = environmentInputs self.runtimeDependencies = runtimeDependencies; self.versionArguments = versionArguments self.minimumVersion = minimumVersion + self.configuredExecutable = configuredExecutable } } @@ -929,7 +932,9 @@ package protocol BuildSystemPlanning: Sendable { options: [String: ToolingJSONValue], executableURL: URL? ) throws -> BuildLanguageImport? - func invocationPlan(_ target: BuildSystemTarget, root: String) throws -> BuildInvocation + func invocationPlan( + _ target: BuildSystemTarget, root: String, settings: [String: ToolingJSONValue] + ) throws -> BuildInvocation func checkToolVersion(_ target: BuildSystemTarget, runtime: String?, output: String) throws -> BuildVersionCheck func resolveOptions( _ target: BuildSystemTarget, diff --git a/macos/Sources/LitheExecutionModule/Services/BuildSystemService.swift b/macos/Sources/LitheExecutionModule/Services/BuildSystemService.swift index 72bf44398c..705d4a9cd5 100644 --- a/macos/Sources/LitheExecutionModule/Services/BuildSystemService.swift +++ b/macos/Sources/LitheExecutionModule/Services/BuildSystemService.swift @@ -119,6 +119,7 @@ package final class BuildSystemService: ObservableObject { private let stateLocator: any BuildSystemStateLocating private let runner: any BuildCommandRunning private let providers: (any BuildProviderRequesting)? + private let settings: @MainActor (String) -> [String: ToolingJSONValue] private let waitForRedetection: @Sendable () async throws -> Void private let sources: @MainActor () -> [BuildSystemPluginSource] @@ -178,6 +179,7 @@ package final class BuildSystemService: ObservableObject { stateLocator: any BuildSystemStateLocating, runner: any BuildCommandRunning, providers: (any BuildProviderRequesting)? = nil, + settings: @escaping @MainActor (String) -> [String: ToolingJSONValue] = { _ in [:] }, waitForRedetection: @escaping @Sendable () async throws -> Void = { try await Task.sleep(for: .milliseconds(500)) }, @@ -189,6 +191,7 @@ package final class BuildSystemService: ObservableObject { self.stateLocator = stateLocator self.runner = runner self.providers = providers + self.settings = settings self.waitForRedetection = waitForRedetection self.sources = sources } @@ -331,7 +334,10 @@ package final class BuildSystemService: ObservableObject { var executables: [String: URL] = [:] for input in inputs { guard case .maven? = imports[input.entry.id], - let invocation = try? planner.invocationPlan(input.entry.target, root: input.entry.instance.root) + let invocation = try? planner.invocationPlan( + input.entry.target, root: input.entry.instance.root, + settings: self.settings(input.entry.source.pluginID) + ) else { continue } executables[input.entry.id] = self.tools.languageImportExecutable(invocation, workspaceURL: workspaceURL) } @@ -1192,7 +1198,9 @@ package final class BuildSystemService: ObservableObject { ) async throws -> BuildCommandRequest { let planner = planner let target = entry.target - let invocation = try planner.invocationPlan(target, root: entry.instance.root) + let invocation = try planner.invocationPlan( + target, root: entry.instance.root, settings: settings(entry.source.pluginID) + ) let tool = try await tools.resolve( invocation, displayName: entry.instance.displayName, @@ -1262,13 +1270,15 @@ package final class BuildSystemService: ObservableObject { } /// The executable the build system's invocation resolves to, as a run - /// would use it. A failure is not the provider's: it still loads and - /// looks the tool up itself, so the reason only goes to Build Output. + /// would use it. Automatic discovery may fall back to the provider's lookup; + /// an explicit selection must fail rather than use a different installation. private func providerTool(_ entry: BuildSystemEntry, workspaceURL: URL, owner: CommandOwner) async throws -> URL? { let planner = planner let target = entry.target + let invocation = try planner.invocationPlan( + target, root: entry.instance.root, settings: settings(entry.source.pluginID) + ) do { - let invocation = try planner.invocationPlan(target, root: entry.instance.root) guard !invocation.executables.isEmpty else { return nil } return try await tools.resolve( invocation, displayName: entry.instance.displayName, workspaceURL: workspaceURL @@ -1278,6 +1288,7 @@ package final class BuildSystemService: ObservableObject { } catch is CancellationError { throw CancellationError() } catch { + if invocation.configuredExecutable != nil { throw error } if canAppend(owner) { appendOutput( "\n" + String(localized: "The provider looks up the build tool itself: \(error.localizedDescription)") + "\n", diff --git a/macos/Sources/LitheModuleAPI/Plugins/PluginTypes.swift b/macos/Sources/LitheModuleAPI/Plugins/PluginTypes.swift index c3c8a9e3ae..7f015dc8ae 100644 --- a/macos/Sources/LitheModuleAPI/Plugins/PluginTypes.swift +++ b/macos/Sources/LitheModuleAPI/Plugins/PluginTypes.swift @@ -491,7 +491,7 @@ public struct PluginManifest: Equatable, Codable, Sendable { /// not running it, so an entry is added only with its host support. public static let hostCapabilities: [String: [Int]] = [ "buildProviders": [1], - "buildSystems": [1], + "buildSystems": [1, 2], "executionProviders": [1], "languageServers": [1, 2], "languages": [1], diff --git a/macos/Tests/LitheExecutionModuleTests/BuildSystemServiceTests.swift b/macos/Tests/LitheExecutionModuleTests/BuildSystemServiceTests.swift index 68b8c2d39a..a1666af12b 100644 --- a/macos/Tests/LitheExecutionModuleTests/BuildSystemServiceTests.swift +++ b/macos/Tests/LitheExecutionModuleTests/BuildSystemServiceTests.swift @@ -1482,6 +1482,27 @@ struct BuildSystemServiceTests { #expect(harness.service.output.contains("Maven is not installed.")) } + @Test + func providerDoesNotFallBackWhenAnExplicitExecutableFails() async throws { + let planner = FakeBuildPlanner() + planner.detection = BuildDetection(instances: [try Self.instance(modelSource: "provider")]) + planner.providerRequest = Self.providerRequest(method: "lithe/build/model") + let providers = FakeBuildProviders() + let harness = Harness(planner: planner, providers: providers, settings: { pluginID in + #expect(pluginID == "dev.example") + return ["toolPath": .string("/custom tools/build")] + }) + harness.tools.failure = BuildToolResolutionError("Selected executable is unavailable.") + defer { harness.service.stop() } + harness.service.reset(workspaceURL: Self.workspace) + #expect(await harness.waitForEntries { $0.first?.modelState == .notLoaded }) + harness.service.loadModel(Self.instanceID) + #expect(await harness.waitForEntries { if case .failed = $0.first?.modelState { return true }; return false }) + #expect(providers.sent.isEmpty) + guard case .failed(let message)? = harness.service.entries.first?.modelState else { return } + #expect(message.contains("Selected executable is unavailable.")) + } + /// Command sources resolve their tool when the command runs; planning /// never resolves it a second time for them. @Test @@ -1726,6 +1747,7 @@ private final class Harness { runner: any BuildCommandRunning = FakeBuildRunner(), sources: [BuildSystemPluginSource] = [fixtureSource()], providers: (any BuildProviderRequesting)? = nil, + settings: @escaping @MainActor (String) -> [String: ToolingJSONValue] = { _ in [:] }, waitForRedetection: @escaping @Sendable () async throws -> Void = {} ) { let enabledSources = SourceList(sources) @@ -1737,6 +1759,7 @@ private final class Harness { stateLocator: stateLocator, runner: runner, providers: providers, + settings: settings, waitForRedetection: waitForRedetection, sources: { enabledSources.value } ) @@ -2032,8 +2055,9 @@ private final class FakeBuildPlanner: BuildSystemPlanning, @unchecked Sendable { )) } - func invocationPlan(_ target: BuildSystemTarget, root: String) throws -> BuildInvocation { - BuildInvocation(executables: [.command("fake")]) + func invocationPlan(_ target: BuildSystemTarget, root: String, settings: [String: ToolingJSONValue]) throws -> BuildInvocation { + let configured: String? = if case .string(let path)? = settings["toolPath"] { path } else { nil } + return BuildInvocation(executables: [.command("fake")], configuredExecutable: configured) } func checkToolVersion(_ target: BuildSystemTarget, runtime: String?, output: String) throws -> BuildVersionCheck { diff --git a/macos/Tests/LitheTests/MacBuildToolResolverTests.swift b/macos/Tests/LitheTests/MacBuildToolResolverTests.swift index 7d95050082..605a4b199d 100644 --- a/macos/Tests/LitheTests/MacBuildToolResolverTests.swift +++ b/macos/Tests/LitheTests/MacBuildToolResolverTests.swift @@ -6,6 +6,54 @@ import Testing @Suite("Build tool resolver version output") @MainActor struct MacBuildToolResolverTests { + @Test + func configuredPathWithSpacesWinsOverDiscoveryAndSuppliesItsDirectory() async throws { + let root = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString) + defer { try? FileManager.default.removeItem(at: root) } + let executable = root.appendingPathComponent("custom tools/build-tool") + try FileManager.default.createDirectory(at: executable.deletingLastPathComponent(), withIntermediateDirectories: true) + try Data("#!/bin/sh\nprintf 'fixture 2.0\\n'\n".utf8).write(to: executable) + try FileManager.default.setAttributes([.posixPermissions: 0o755], ofItemAtPath: executable.path) + let runtime = ProjectRuntimeService(runtimeLocator: BuildProbeRuntimeLocator(home: root), store: BuildProbeEmptyStore()) + let resolver = MacBuildToolResolver(runtime: runtime, processRunner: MacProcessRunner(), fileStorage: MacFileStorage()) + let invocation = BuildInvocation( + executables: [.command("unavailable")], versionArguments: ["--version"], + minimumVersion: "2", configuredExecutable: executable.path + ) + let resolved = try await resolver.resolve(invocation, displayName: "Fixture", workspaceURL: root) { _, output in + BuildVersionCheck(satisfied: output.contains("fixture 2.0"), version: "2.0") + } + #expect(resolved.executableURL == executable) + #expect(resolved.environment["PATH"]?.hasPrefix(executable.deletingLastPathComponent().path + ":") == true) + #expect(resolver.languageImportExecutable(invocation, workspaceURL: root) == executable) + } + + @Test(arguments: ["missing", "non-executable", "old"]) + func unusableConfiguredPathNeverFallsBackToAvailableWrapper(_ failure: String) async throws { + let root = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString) + defer { try? FileManager.default.removeItem(at: root) } + try FileManager.default.createDirectory(at: root, withIntermediateDirectories: true) + let configured = root.appendingPathComponent("configured") + if failure != "missing" { + try Data("#!/bin/sh\nprintf 'fixture 1.0\\n'\n".utf8).write(to: configured) + try FileManager.default.setAttributes([.posixPermissions: failure == "old" ? 0o755 : 0o644], ofItemAtPath: configured.path) + } + let fallback = root.appendingPathComponent("wrapper") + try Data("#!/bin/sh\nexit 0\n".utf8).write(to: fallback) + try FileManager.default.setAttributes([.posixPermissions: 0o755], ofItemAtPath: fallback.path) + let runtime = ProjectRuntimeService(runtimeLocator: BuildProbeRuntimeLocator(home: root), store: BuildProbeEmptyStore()) + let resolver = MacBuildToolResolver(runtime: runtime, processRunner: MacProcessRunner(), fileStorage: MacFileStorage()) + let invocation = BuildInvocation( + executables: [.projectFile(path: "wrapper", requires: [])], versionArguments: ["--version"], + minimumVersion: "2", configuredExecutable: configured.path + ) + await #expect(throws: BuildToolResolutionError.self) { + try await resolver.resolve(invocation, displayName: "Fixture", workspaceURL: root) { _, _ in + BuildVersionCheck(satisfied: false, version: "1.0") + } + } + } + @Test func languageImportDiscoversWrapperWithoutExecutingItOrRuntimeProbes() throws { let root = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString) diff --git a/macos/Tests/LitheTests/RustBuildSystemOperationsTests.swift b/macos/Tests/LitheTests/RustBuildSystemOperationsTests.swift index 85cd849038..19b04f9e48 100644 --- a/macos/Tests/LitheTests/RustBuildSystemOperationsTests.swift +++ b/macos/Tests/LitheTests/RustBuildSystemOperationsTests.swift @@ -68,6 +68,14 @@ struct RustBuildSystemOperationsTests { #expect(resolution.dropped == ["features"]) } + @Test + func invocationUsesTheGlobalExecutableSetting() throws { + let target = try Self.target("build-tool-path", "fixture") + let custom = try operations.invocationPlan(target, root: ".", settings: ["toolPath": .string("/opt/custom tools/build")]) + #expect(custom.configuredExecutable == "/opt/custom tools/build") + #expect(try operations.invocationPlan(target, root: ".").configuredExecutable == nil) + } + @Test func invocationAndVersionProbe() throws { let target = try Self.target("cargo-build", "cargo") diff --git a/rust/lithe-core/src/build/commands.rs b/rust/lithe-core/src/build/commands.rs index ca59ff02eb..e8d7181236 100644 --- a/rust/lithe-core/src/build/commands.rs +++ b/rust/lithe-core/src/build/commands.rs @@ -17,7 +17,8 @@ use super::outputs::{ }; use super::plans::{self, OutputPlanRequest, TaskPlanRequest, TestPlanRequest}; use crate::plugins::declarative::{ - decode_payload, outcome, validate_manifest_value, PluginRejection, Validation, + decode_payload, outcome, validate_manifest_value, DeclarativePluginManifest, PluginRejection, + Validation, }; use crate::protocol::CoreError; use serde::de::DeserializeOwned; @@ -51,6 +52,17 @@ fn with_build_system( command: &str, key: &'static str, run: impl FnOnce(&BuildSystemDeclaration, &T) -> Validation, +) -> Result { + with_manifest(payload, command, key, |build_system, request, _| { + run(build_system, request) + }) +} + +fn with_manifest( + payload: Value, + command: &str, + key: &'static str, + run: impl FnOnce(&BuildSystemDeclaration, &T, &DeclarativePluginManifest) -> Validation, ) -> Result { let payload: BuildPayload = decode_payload(payload, command)?; Ok(outcome(validate_manifest_value(payload.manifest).and_then( @@ -68,7 +80,7 @@ fn with_build_system( ), ) })?; - run(build_system, &payload.request).map(|value| (key, value)) + run(build_system, &payload.request, &manifest).map(|value| (key, value)) }, ))) } @@ -84,12 +96,12 @@ pub(crate) fn build_detect_command(payload: Value) -> Result { /// `build.invocationPlan`: executable candidates and version probes. pub(crate) fn build_invocation_plan_command(payload: Value) -> Result { - with_build_system( + with_manifest( payload, "build.invocationPlan", "invocation", - |build_system, request: &InvocationRequest| { - invocation::invocation_plan(build_system, request) + |build_system, request: &InvocationRequest, manifest| { + invocation::invocation_plan(build_system, request, manifest) }, ) } diff --git a/rust/lithe-core/src/build/invocation.rs b/rust/lithe-core/src/build/invocation.rs index 19a9f422c7..1029b57d62 100644 --- a/rust/lithe-core/src/build/invocation.rs +++ b/rust/lithe-core/src/build/invocation.rs @@ -11,10 +11,13 @@ use super::manifest::{ BuildSystemDeclaration, ExecutableCandidate, Platform, RuntimeDependency, VersionProbe, }; use crate::plugins::declarative::{ - reported_version, validate_minimum_version, version_components, PluginRejection, Validation, + reported_version, validate_minimum_version, version_components, DeclarativePluginManifest, + PluginRejection, Validation, }; +use crate::plugins::settings::SettingLayers; use serde::Deserialize; use serde_json::{json, Value}; +use std::collections::BTreeMap; #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase", deny_unknown_fields)] @@ -22,6 +25,9 @@ pub(crate) struct InvocationRequest { /// Instance root, workspace-relative. pub(crate) root: String, pub(crate) platform: Platform, + /// Global plugin settings. Project files cannot select a local executable. + #[serde(default)] + pub(crate) settings: BTreeMap, } #[derive(Debug, Deserialize)] @@ -103,6 +109,7 @@ fn runtime(runtime: &RuntimeDependency, root: &str, platform: Platform) -> Value pub(crate) fn invocation_plan( build_system: &BuildSystemDeclaration, request: &InvocationRequest, + manifest: &DeclarativePluginManifest, ) -> Validation { let root = decode::request_path(&request.root, "root")?; let invocation = &build_system.invocation; @@ -116,7 +123,23 @@ pub(crate) fn invocation_plan( ), )); } - Ok(json!({ + let configured_executable = invocation.executable_setting.as_ref().and_then(|id| { + manifest + .resolve_settings(SettingLayers { + global: &request.settings, + project: &BTreeMap::new(), + }) + .into_iter() + .find(|setting| &setting.id == id) + .and_then(|setting| { + setting + .value + .as_str() + .filter(|path| !path.is_empty()) + .map(str::to_owned) + }) + }); + let mut plan = json!({ "buildSystemID": build_system.id, "root": root, "executables": executables, @@ -128,7 +151,11 @@ pub(crate) fn invocation_plan( .collect::>(), "version": invocation.version.as_ref().map(|probe| json!({ "arguments": probe.arguments })), "minimumVersion": invocation.minimum_version, - })) + }); + if let Some(path) = configured_executable { + plan["configuredExecutable"] = json!(path); + } + Ok(plan) } /// `build.checkToolVersion`: reads the probe output of the build tool or of diff --git a/rust/lithe-core/src/build/manifest.rs b/rust/lithe-core/src/build/manifest.rs index 79cab6abbc..d4e2837724 100644 --- a/rust/lithe-core/src/build/manifest.rs +++ b/rust/lithe-core/src/build/manifest.rs @@ -192,6 +192,10 @@ pub(crate) enum Nesting { #[derive(Debug, Clone, Deserialize, Serialize)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub(crate) struct Invocation { + /// Optional global file setting selecting the executable. An empty value + /// keeps discovery; a configured path must never fall back silently. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub(crate) executable_setting: Option, /// Candidates in preference order; the host takes the first that exists. pub(crate) executables: Vec, #[serde(default, skip_serializing_if = "Vec::is_empty")] @@ -965,6 +969,7 @@ fn check_target_tags(tags: &mut Vec, scopes: &[Scope], field: &str) -> V /// against. pub(crate) struct DeclarationContext<'a> { pub(crate) plugin_api_version: u32, + pub(crate) build_systems_version: u32, pub(crate) official: bool, /// Setting IDs a provider's launch templates may name. pub(crate) declared_settings: &'a crate::plugins::settings::DeclaredSettings, @@ -1242,7 +1247,7 @@ impl BuildSystemDeclaration { self.validate_provider(field, context)?; self.validate_detection(field)?; let option_ids = self.validate_options(field)?; - self.validate_invocation(field, &option_ids)?; + self.validate_invocation(field, &option_ids, context)?; let model_templates = self.validate_tasks(field, &option_ids)?; self.validate_model(field, &option_ids)?; self.validate_run(field, &option_ids, &model_templates)?; @@ -1411,9 +1416,22 @@ impl BuildSystemDeclaration { Ok(ids) } - fn validate_invocation(&mut self, field: &str, options: &BTreeSet) -> Validation<()> { + fn validate_invocation( + &mut self, + field: &str, + options: &BTreeSet, + context: &DeclarationContext<'_>, + ) -> Validation<()> { let invocation = &mut self.invocation; let field = format!("{field}.invocation"); + if let Some(id) = &invocation.executable_setting { + if context.build_systems_version < 2 || !context.declared_settings.is_executable(id) { + return Err(invalid( + format!("{field}.executableSetting"), + "An executable setting requires buildSystems 2 and a global file setting with effect reload or nextRun.", + )); + } + } if invocation.environment_inputs.len() > MAX_LIST { return Err(invalid( format!("{field}.environmentInputs"), diff --git a/rust/lithe-core/src/plugins/capabilities.rs b/rust/lithe-core/src/plugins/capabilities.rs index cfae7aad21..d4b8a2d5f8 100644 --- a/rust/lithe-core/src/plugins/capabilities.rs +++ b/rust/lithe-core/src/plugins/capabilities.rs @@ -46,7 +46,7 @@ pub(crate) const BUILD_PROVIDERS: &str = "buildProviders"; /// capability keeps the meaning its section had at API level 2. pub const SUPPORTED_CAPABILITIES: &[(&str, &[u32])] = &[ (BUILD_PROVIDERS, &[1]), - (BUILD_SYSTEMS, &[1]), + (BUILD_SYSTEMS, &[1, 2]), (EXECUTION_PROVIDERS, &[1]), (LANGUAGE_SERVERS, &[1, 2]), (LANGUAGES, &[1]), diff --git a/rust/lithe-core/src/plugins/declarative.rs b/rust/lithe-core/src/plugins/declarative.rs index 5dabae94f1..a7a88f4da5 100644 --- a/rust/lithe-core/src/plugins/declarative.rs +++ b/rust/lithe-core/src/plugins/declarative.rs @@ -895,6 +895,7 @@ impl DeclarativePluginManifest { &mut self.build_systems, &crate::build::DeclarationContext { plugin_api_version: self.plugin_api_version, + build_systems_version: self.requires.get("buildSystems").copied().unwrap_or(1), official: is_official_namespace(&self.id), declared_settings: &declared_settings, language_servers: &server_languages, diff --git a/rust/lithe-core/src/plugins/settings.rs b/rust/lithe-core/src/plugins/settings.rs index f3044c4e48..25c9506200 100644 --- a/rust/lithe-core/src/plugins/settings.rs +++ b/rust/lithe-core/src/plugins/settings.rs @@ -246,6 +246,8 @@ struct SettingOption { /// Setting IDs a template may name, with the restrictions their kinds carry. #[derive(Debug, Clone, Default)] pub(crate) struct DeclaredSettings { + /// Global paths that may explicitly select a build executable. + executables: BTreeSet, /// Settings a launch reads when it starts. launch: BTreeSet, /// Settings that are only pushed to a running server. @@ -256,6 +258,11 @@ pub(crate) struct DeclaredSettings { } impl DeclaredSettings { + /// Whether the global file setting may select the build executable. + pub(crate) fn is_executable(&self, id: &str) -> bool { + self.executables.contains(id) + } + /// Whether a start-time template may name the setting. pub(crate) fn contains(&self, id: &str) -> bool { self.launch.contains(id) @@ -606,6 +613,15 @@ impl SettingDeclaration { pub(crate) fn declared(settings: &[SettingDeclaration]) -> DeclaredSettings { let mut declared = DeclaredSettings::default(); for setting in settings { + if setting.kind == "file" + && setting.scope() == SettingScope::Global + && matches!( + setting.effect(), + SettingEffect::Reload | SettingEffect::NextRun + ) + { + declared.executables.insert(setting.id.clone()); + } if setting.effect() == SettingEffect::Immediate { declared.immediate.insert(setting.id.clone()); } else { diff --git a/rust/lithe-core/src/tests/build_systems.rs b/rust/lithe-core/src/tests/build_systems.rs index 33df31c95c..1ff564c743 100644 --- a/rust/lithe-core/src/tests/build_systems.rs +++ b/rust/lithe-core/src/tests/build_systems.rs @@ -1592,3 +1592,69 @@ fn task_categories_and_option_placements_are_display_only() { assert_eq!(plan["status"], "ok", "{plan}"); assert!(plan.to_string().contains("\":run\""), "{plan}"); } + +/// A global executable selection is validated by the same settings rules as +/// launch settings. No filesystem access or per-tool branch belongs in Core. +#[test] +fn explicit_build_tool_path_requires_supported_global_file_setting() { + let manifest: Value = + serde_json::from_str(contract_file!("fixtures/build-tool-path.plugin.json")).unwrap(); + assert_eq!(validate(manifest.clone())["status"], "ok"); + let invoke = |settings: Value| { + call( + "invocationPlan", + manifest.clone(), + "fixture", + json!({ + "root": ".", "platform": "macos", "settings": settings + }), + ) + }; + assert_eq!( + invoke(json!({}))["invocation"].get("configuredExecutable"), + None + ); + assert_eq!( + invoke(json!({"toolPath": ""}))["invocation"].get("configuredExecutable"), + None + ); + let path = "/opt/custom tools/build-tool"; + assert_eq!( + invoke(json!({"toolPath": path}))["invocation"]["configuredExecutable"], + path + ); + assert_eq!( + invoke(json!({"toolPath": "relative"}))["invocation"].get("configuredExecutable"), + None + ); + for platform in ["macos", "linux", "windows"] { + let result = call( + "invocationPlan", + manifest.clone(), + "fixture", + json!({ + "root": ".", "platform": platform, "settings": {"toolPath": "C:\\Tools\\build.exe"} + }), + ); + assert_eq!(result["status"], "ok"); + assert_eq!( + result["invocation"]["configuredExecutable"], + "C:\\Tools\\build.exe" + ); + } + for (field, value) in [ + ("scope", json!("project")), + ("type", json!("directory")), + ("effect", json!("restart")), + ] { + let mut invalid = manifest.clone(); + invalid["settings"][0][field] = value; + assert_eq!(validate(invalid)["status"], "rejected", "{field}"); + } + let mut old = manifest.clone(); + old["requires"]["buildSystems"] = json!(1); + assert_eq!(validate(old)["status"], "rejected"); + let mut missing = manifest; + missing["buildSystems"][0]["invocation"]["executableSetting"] = json!("missing"); + assert_eq!(validate(missing)["status"], "rejected"); +} diff --git a/shared/contracts/plugins/v1/README.md b/shared/contracts/plugins/v1/README.md index ba81f07cdf..a7a0c93cde 100644 --- a/shared/contracts/plugins/v1/README.md +++ b/shared/contracts/plugins/v1/README.md @@ -1471,3 +1471,22 @@ macOS 动作的可见、可用、勾选和激活中状态由宿主计算,不 条件脚本。窗口尚在激活时,其打开命令在工具栏、菜单和命令面板禁用;窗口入口 仍可取消显示。多个窗口同时请求同一插件模块时只构造一次;禁用或关闭会取消 并清理在途激活,旧的菜单或命令引用不能重新调用已禁用的贡献。 + +#### Configured build executable (`buildSystems` 2) + +`invocation.executableSetting` names a declared **global** `file` setting with +`effect: "reload"` or `"nextRun"` (also requires `settings: 2`). The field is part +of install review. Project settings cannot choose an executable. See +[`build-tool-path.plugin.json`](fixtures/build-tool-path.plugin.json). + +`build.invocationPlan` accepts optional `request.settings`, the plugin's stored +global values. Core applies the declared setting validation/default and emits +`invocation.configuredExecutable` only for a nonempty value. Empty/absent values +retain the existing ordered executable candidates. A host advertising +`buildSystems: 2` must use a configured path directly, verify executability and +version, and report a failure instead of falling back to another installation. +The executable's parent directory precedes PATH for its process. All command +sources, tasks/tests and provider `tool.executable` hints must use that same +selection; a provider must not do independent discovery when an explicit path +fails. Passive language import may inspect existence but never execute a probe. +Older hosts advertise only version 1 and reject version 2 plugins. diff --git a/shared/contracts/plugins/v1/fixtures/build-tool-path.plugin.json b/shared/contracts/plugins/v1/fixtures/build-tool-path.plugin.json new file mode 100644 index 0000000000..60677df97f --- /dev/null +++ b/shared/contracts/plugins/v1/fixtures/build-tool-path.plugin.json @@ -0,0 +1,69 @@ +{ + "schemaVersion": 2, + "id": "dev.lithe.fixture.build-tool-path", + "displayName": "Build path fixture", + "version": "0.1.0", + "pluginAPIVersion": 3, + "requires": { + "buildSystems": 2, + "settings": 2 + }, + "vendor": { + "id": "org.example", + "displayName": "Example", + "signatureRequirement": "publisherPackage" + }, + "permissions": [ + "process.build" + ], + "activationEvents": [ + "onBuildSystem:fixture" + ], + "languages": [], + "settings": [ + { + "id": "toolPath", + "type": "file", + "title": "Build tool", + "default": "", + "scope": "global", + "effect": "reload", + "page": { + "buildSystemID": "fixture" + } + } + ], + "buildSystems": [ + { + "id": "fixture", + "displayName": "Fixture", + "detection": { + "markers": [ + "build.fixture" + ] + }, + "invocation": { + "executableSetting": "toolPath", + "executables": [ + { + "kind": "command", + "command": "fixture-build" + } + ] + }, + "tasks": [ + { + "id": "build", + "displayName": "Build", + "group": "build", + "scopes": [ + "workspace" + ], + "arguments": [ + "build" + ] + } + ] + } + ] +} diff --git a/shared/contracts/plugins/v1/fixtures/invalid-manifests.json b/shared/contracts/plugins/v1/fixtures/invalid-manifests.json index 967ce21f2f..e87056a025 100644 --- a/shared/contracts/plugins/v1/fixtures/invalid-manifests.json +++ b/shared/contracts/plugins/v1/fixtures/invalid-manifests.json @@ -825,7 +825,7 @@ { "name": "future capability version", "base": "cargo-build.plugin.json", - "edits": [{ "op": "set", "path": "/requires/buildSystems", "value": 2 }], + "edits": [{ "op": "set", "path": "/requires/buildSystems", "value": 3 }], "expectedCode": "plugin.api.unsupported" }, { diff --git a/shared/contracts/plugins/v1/plugin-manifest.schema.json b/shared/contracts/plugins/v1/plugin-manifest.schema.json index 1b45e5dadd..4b331e1e26 100644 --- a/shared/contracts/plugins/v1/plugin-manifest.schema.json +++ b/shared/contracts/plugins/v1/plugin-manifest.schema.json @@ -22,7 +22,7 @@ "additionalProperties": false, "properties": { "buildProviders": { "description": "Required exactly when any buildSystems[].provider is present, including own-process and shared language-server providers. Declares host support for Provider orchestration, independent of declarative buildSystems and serverProcess launch support.", "enum": [1] }, - "buildSystems": { "description": "Declarative build detection, models, and command plans; does not imply buildProviders support.", "enum": [1] }, + "buildSystems": { "description": "Declarative build detection, models, and command plans; does not imply buildProviders support.", "enum": [1, 2] }, "executionProviders": { "enum": [1] }, "languageServers": { "enum": [1] }, "languages": { "enum": [1] }, @@ -1095,6 +1095,12 @@ "executables" ], "properties": { + "executableSetting": { + "type": "string", + "description": "buildSystems 2: global file setting with effect reload or nextRun; empty uses discovery, nonempty must be used without fallback.", + "pattern": "^[a-z][a-zA-Z0-9]*$", + "maxLength": 120 + }, "executables": { "type": "array", "items": { diff --git a/shared/platform-feature-matrix/features/build-system-plugins.json b/shared/platform-feature-matrix/features/build-system-plugins.json index 801252cc65..2145df1621 100644 --- a/shared/platform-feature-matrix/features/build-system-plugins.json +++ b/shared/platform-feature-matrix/features/build-system-plugins.json @@ -2,7 +2,7 @@ "id": "build-system-plugins", "area": "扩展", "group": "插件与主题", - "capability": "构建系统插件(API 3 buildSystems):插件用 JSON 声明构建工具的识别、可执行文件、选项、任务、运行入口、测试和输出格式,或由插件自带、与语言服务器同类的 Provider 进程回答模型和依赖,Rust Core 统一校验、生成命令行或 Provider 请求并解码结果,宿主为每个构建系统打开一个按声明(icon、presentation、category)布局的工具窗口", + "capability": "构建系统插件(API 3 buildSystems):插件用 JSON 声明构建工具的识别、可执行文件、选项、任务、运行入口、测试和输出格式,或由插件自带、与语言服务器同类的 Provider 进程回答模型和依赖,Rust Core 统一校验、生成命令行或 Provider 请求并解码结果,宿主为每个构建系统打开一个按声明(icon、presentation、category)布局的工具窗口;支持全局可执行文件路径,留空自动发现,指定失效报错", "macos": { "evidence": [ "rust/lithe-core/src/build", @@ -23,7 +23,8 @@ "rust/lithe-core/src/lsp/interface/build_provider.rs", "macos/Sources/Lithe/Platform/MacOS/Build/MacBuildProviderSessions.swift", "macos/Sources/Lithe/Platform/MacOS/Plugins/MacPluginLanguageServerLaunchResolver.swift", - "macos/Tests/LitheTests/PluginMarketplaceServiceTests.swift" + "macos/Tests/LitheTests/PluginMarketplaceServiceTests.swift", + "shared/contracts/plugins/v1/fixtures/build-tool-path.plugin.json" ], "implementationStatus": "partial", "verificationStatus": "pending" @@ -38,5 +39,5 @@ "verificationStatus": "not-applicable" }, "owner": "Extensions", - "verification": "macOS 已接入 static、command、hostIntegration、provider 四种模型来源:宿主向 Core 声明 buildSystems 与 buildProviders 能力,插件市场因此列出兼容的 API 3 声明式和 Provider 版本;Provider 进程按插件、构建系统和工作区各自独立,经各自 stdio 用 JSON-RPC(LSP 基础协议)与宿主通信,initialize 协商 capabilities.experimental.litheBuild 后宿主才经 lsp.buildRequest 发送 lithe/build/model、lithe/build/dependencies,回复交给 Core 解码;共享写法只复用同一插件的语言服务器会话;进程只在用户加载模型或依赖时启动,切换工作区、关闭项目窗口、停止执行模块、停用或更新插件、退出应用时停止;ExecutionFeatureGraph.stop 经 BuildSystemService.stop 同时回收已就绪和初始化中的 Provider,停止后的初始化完成也不得重新登记会话;状态写入插件状态目录;每个已启用的构建系统插件在打开工作区后各有一个右侧工具窗口(标题为 displayName、图标为 icon),不依赖识别结果,工作区没有对应工程时窗口内显示未检测到该构建系统,工具栏放运行、参数任务、刷新和 presentation=toolbar 的开关,树顶部是 presentation=tree 的勾选选项,工程下按 category(缺省按 group)分级列出任务,再列测试、目标和依赖;内置 Maven 窗口与共享 Build 窗口已删除,Build Output 显示输出、诊断与测试结果。窗口恢复先激活所属插件模块,激活中的命令面板项禁用;参数任务遵守 workspace/project/target 作用范围与目标标签,模型或工作区变化后清除旧选择。隔离回归覆盖这些边界、窗口布局恢复及包内图标读取前后文件清单与字节不变;多实例的根目录选择器保留每个实例的模型候选和生效值,编辑多选时保留兄弟实例独有的已选值;显式清空按实例根持久化为空覆盖,检测、同步指纹、任务计划和语言服务器导入使用同一覆盖,兄弟编辑或重开不会恢复非空默认值,非空编辑清当前实例标记而共享编辑/重置清该选项全部标记;真实 Core、生产存储与服务回归核对最终 argv 和导入值;列表单选与多选支持 allowCustom 原生输入和移除已选自定义值,文本/文件/目录清空提交显式空字符串,只有重置删除覆盖。插件选项在项目打开、选项修改和模型加载完成后通过 Core build.languageImport 归一化为 mavenContext/javaGradle,与构建计划使用同一生效值,并在 Java 启动前等待同一工作区代次的最新配置;运行时准备后再等一次,覆盖等待期间失效。唯一发布回调优先 Maven 原地热更新,被拒绝时串行恢复重启;停用最后一个 Maven 插件时,仅清除曾带 Maven 输入的同一会话,纯 Gradle 首次启动保持 nil。Gradle 在下次启动生效,取消/重置拒绝旧检测与恢复任务,被动工具路径发现不执行 Wrapper/版本探测;没有对应插件导入输入时兼容原 Maven 设置。模型 run 入口与 lithe/build/execute 尚未接入,Provider 无操作系统级沙盒;Windows 宿主尚未调用 build.* 命令。自动化:cargo test -p lithe-core --lib build_systems、cargo test -p lithe-core --lib lsp、scripts/verify-shared-contracts.sh、./scripts/test-macos.sh --filter 'BuildSystemToolWindowTests|RustBuildSystemOperationsTests|BuildSystemServiceTests|PluginMarketplaceServiceTests'。手动验证:安装 fixtures 中 cargo-build、go-build 形态的插件包,确认每个构建系统各出现一个工具窗口,列出工程、分级任务、选项和依赖,停用插件后窗口消失;执行任务与测试的 argv 与 build-plans.json 一致,停止与输出上限生效;JUnit 报告与 lineMatcher 诊断可跳转到源码;命令模型和项目内 Wrapper 只在用户点击加载或运行后启动;禁用插件后实例消失;Windows 接入后另需验证未信任工作区不启动任何模型命令或 Wrapper;gradle-provider 形态的自有 Provider 只在用户操作或工作区信任后启动、停用插件时停止,mix-provider 形态复用语言服务器会话而不启动第二个进程;运行前后 app bundle 文件清单不变(scripts/verify-runtime-bundle-immutability.sh)。" + "verification": "macOS 已接入 static、command、hostIntegration、provider 四种模型来源:宿主向 Core 声明 buildSystems 与 buildProviders 能力,插件市场因此列出兼容的 API 3 声明式和 Provider 版本;Provider 进程按插件、构建系统和工作区各自独立,经各自 stdio 用 JSON-RPC(LSP 基础协议)与宿主通信,initialize 协商 capabilities.experimental.litheBuild 后宿主才经 lsp.buildRequest 发送 lithe/build/model、lithe/build/dependencies,回复交给 Core 解码;共享写法只复用同一插件的语言服务器会话;进程只在用户加载模型或依赖时启动,切换工作区、关闭项目窗口、停止执行模块、停用或更新插件、退出应用时停止;ExecutionFeatureGraph.stop 经 BuildSystemService.stop 同时回收已就绪和初始化中的 Provider,停止后的初始化完成也不得重新登记会话;状态写入插件状态目录;每个已启用的构建系统插件在打开工作区后各有一个右侧工具窗口(标题为 displayName、图标为 icon),不依赖识别结果,工作区没有对应工程时窗口内显示未检测到该构建系统,工具栏放运行、参数任务、刷新和 presentation=toolbar 的开关,树顶部是 presentation=tree 的勾选选项,工程下按 category(缺省按 group)分级列出任务,再列测试、目标和依赖;内置 Maven 窗口与共享 Build 窗口已删除,Build Output 显示输出、诊断与测试结果。窗口恢复先激活所属插件模块,激活中的命令面板项禁用;参数任务遵守 workspace/project/target 作用范围与目标标签,模型或工作区变化后清除旧选择。隔离回归覆盖这些边界、窗口布局恢复及包内图标读取前后文件清单与字节不变;多实例的根目录选择器保留每个实例的模型候选和生效值,编辑多选时保留兄弟实例独有的已选值;显式清空按实例根持久化为空覆盖,检测、同步指纹、任务计划和语言服务器导入使用同一覆盖,兄弟编辑或重开不会恢复非空默认值,非空编辑清当前实例标记而共享编辑/重置清该选项全部标记;真实 Core、生产存储与服务回归核对最终 argv 和导入值;列表单选与多选支持 allowCustom 原生输入和移除已选自定义值,文本/文件/目录清空提交显式空字符串,只有重置删除覆盖。插件选项在项目打开、选项修改和模型加载完成后通过 Core build.languageImport 归一化为 mavenContext/javaGradle,与构建计划使用同一生效值,并在 Java 启动前等待同一工作区代次的最新配置;运行时准备后再等一次,覆盖等待期间失效。唯一发布回调优先 Maven 原地热更新,被拒绝时串行恢复重启;停用最后一个 Maven 插件时,仅清除曾带 Maven 输入的同一会话,纯 Gradle 首次启动保持 nil。Gradle 在下次启动生效,取消/重置拒绝旧检测与恢复任务,被动工具路径发现不执行 Wrapper/版本探测;没有对应插件导入输入时兼容原 Maven 设置。模型 run 入口与 lithe/build/execute 尚未接入,Provider 无操作系统级沙盒;Windows 宿主尚未调用 build.* 命令。自动化:cargo test -p lithe-core --lib build_systems、cargo test -p lithe-core --lib lsp、scripts/verify-shared-contracts.sh、./scripts/test-macos.sh --filter 'BuildSystemToolWindowTests|RustBuildSystemOperationsTests|BuildSystemServiceTests|PluginMarketplaceServiceTests'。手动验证:安装 fixtures 中 cargo-build、go-build 形态的插件包,确认每个构建系统各出现一个工具窗口,列出工程、分级任务、选项和依赖,停用插件后窗口消失;执行任务与测试的 argv 与 build-plans.json 一致,停止与输出上限生效;JUnit 报告与 lineMatcher 诊断可跳转到源码;命令模型和项目内 Wrapper 只在用户点击加载或运行后启动;禁用插件后实例消失;Windows 接入后另需验证未信任工作区不启动任何模型命令或 Wrapper;gradle-provider 形态的自有 Provider 只在用户操作或工作区信任后启动、停用插件时停止,mix-provider 形态复用语言服务器会话而不启动第二个进程;运行前后 app bundle 文件清单不变(scripts/verify-runtime-bundle-immutability.sh)。;构建路径设置使用 buildSystems 2 + settings 2:MacBuildToolResolverTests 验证带空格绝对路径、权限与版本失败不回退,BuildSystemServiceTests 验证 Provider 失败不独立发现,RustBuildSystemOperationsTests 验证全局值接入。Cargo 独立仓库以显式本地 Core bridge 验证自选路径用于 metadata 和全部构建/测试/运行/清理;发布前需把独立仓库 sdk.lock.json 的宿主 pin 更新到包含该能力的已发布提交。" } diff --git a/shared/platform-feature-matrix/features/cargo-build-plugin.json b/shared/platform-feature-matrix/features/cargo-build-plugin.json index ef40e77227..1965ac0a00 100644 --- a/shared/platform-feature-matrix/features/cargo-build-plugin.json +++ b/shared/platform-feature-matrix/features/cargo-build-plugin.json @@ -2,14 +2,15 @@ "id": "cargo-build-plugin", "area": "扩展", "group": "插件与主题", - "capability": "Cargo 社区构建插件:由 Cargo metadata 提供 workspace/package/target/features,使用原生构建窗口执行编译、检查、测试、清理和 binary/example 运行,支持 Release、Features、Offline;用户安装 Cargo 与 Node,插件独立打包且运行时只读", + "capability": "Cargo 社区构建插件:由 Cargo metadata 提供 workspace/package/target/features,使用原生构建窗口执行编译、检查、测试、清理和 binary/example 运行,支持 Release、Features、Offline;用户安装 Cargo 与 Node,插件独立打包且运行时只读;支持全局可执行文件路径,留空自动发现,指定失效报错", "macos": { "implementationStatus": "implemented", "verificationStatus": "pending", "evidence": [ "Plugins/mac/README.md", "docs/ci-builds.md", - ".agents/notes/implemented/feature/2026-10-22-cargo-build-plugin.md" + ".agents/notes/implemented/feature/2026-10-22-cargo-build-plugin.md", + "shared/contracts/plugins/v1/fixtures/build-tool-path.plugin.json" ] }, "windows": { @@ -20,5 +21,5 @@ ] }, "owner": "Plugin Platform", - "verification": "独立源码与预发布包由 https://github.com/Lithe-IDEA/lithe-plugin-cargo 维护;插件 CI 按 sdk.lock.json 的宿主提交构建公开 JSON API 测试桥接,运行 3 项 Cargo 专属 Core 兼容性回归(清单/安装审查/能力拒绝、识别/模型解码、任务与测试选择),并以 LITHE_CARGO_INTEGRATION=1 执行真实双包 workspace:模型由 Core 规划请求并解码,编译/检查/测试/同名 binary 与 example/单测试/清理由 Core 生成参数,验证 Release/Features/Offline、编译失败及诊断解码、后端退出和包字节不变;SDK 固定源码和哈希、打包校验及逐测试 HTML/JUnit 由插件仓库 CI 持有。固定宿主基线不代表已验证未来 preview。主仓库只保留通用插件契约回归;scripts/verify-runtime-bundle-immutability.sh。原生验收待完成:macOS 从磁盘安装预发布 ZIP、确认 Cargo/Node、重启并启用;打开插件仓库 fixture workspace,检查 Cargo 原生窗口、模型与选项,执行构建/检查/测试/运行,制造错误并跳转源码;停止运行、关闭项目与停用插件后确认无后端和 Cargo 子进程。基础版不提供依赖树、调试或逐用例图形报告;Windows 尚无 API 3 构建宿主。" + "verification": "独立源码与预发布包由 https://github.com/Lithe-IDEA/lithe-plugin-cargo 维护;插件 CI 按 sdk.lock.json 的宿主提交构建公开 JSON API 测试桥接,运行 3 项 Cargo 专属 Core 兼容性回归(清单/安装审查/能力拒绝、识别/模型解码、任务与测试选择),并以 LITHE_CARGO_INTEGRATION=1 执行真实双包 workspace:模型由 Core 规划请求并解码,编译/检查/测试/同名 binary 与 example/单测试/清理由 Core 生成参数,验证 Release/Features/Offline、编译失败及诊断解码、后端退出和包字节不变;SDK 固定源码和哈希、打包校验及逐测试 HTML/JUnit 由插件仓库 CI 持有。固定宿主基线不代表已验证未来 preview。主仓库只保留通用插件契约回归;scripts/verify-runtime-bundle-immutability.sh。原生验收待完成:macOS 从磁盘安装预发布 ZIP、确认 Cargo/Node、重启并启用;打开插件仓库 fixture workspace,检查 Cargo 原生窗口、模型与选项,执行构建/检查/测试/运行,制造错误并跳转源码;停止运行、关闭项目与停用插件后确认无后端和 Cargo 子进程。基础版不提供依赖树、调试或逐用例图形报告;Windows 尚无 API 3 构建宿主。;构建路径设置使用 buildSystems 2 + settings 2:MacBuildToolResolverTests 验证带空格绝对路径、权限与版本失败不回退,BuildSystemServiceTests 验证 Provider 失败不独立发现,RustBuildSystemOperationsTests 验证全局值接入。Cargo 独立仓库以显式本地 Core bridge 验证自选路径用于 metadata 和全部构建/测试/运行/清理;发布前需把独立仓库 sdk.lock.json 的宿主 pin 更新到包含该能力的已发布提交。" } From fc653d5c063182fcde0f24fbe925fbb25eb70974 Mon Sep 17 00:00:00 2001 From: Mucheen <1528136628@qq.com> Date: Thu, 22 Oct 2026 15:59:58 +0800 Subject: [PATCH 2/5] fix(macos): keep plugin path chooser visible in narrow settings --- .../2026-10-21-plugin-settings-surfaces.md | 18 ++++ .../Views/App/PluginSettingsSection.swift | 5 +- .../Components/LitheSettingsControls.swift | 4 +- .../PluginSettingsLayoutTests.swift | 101 ++++++++++++++++++ .../plugin-registered-settings-pages.json | 8 +- 5 files changed, 130 insertions(+), 6 deletions(-) create mode 100644 macos/Tests/LitheTests/PluginSettingsLayoutTests.swift diff --git a/.agents/notes/implemented/architecture/2026-10-21-plugin-settings-surfaces.md b/.agents/notes/implemented/architecture/2026-10-21-plugin-settings-surfaces.md index bfed95934d..2e7f5e3339 100644 --- a/.agents/notes/implemented/architecture/2026-10-21-plugin-settings-surfaces.md +++ b/.agents/notes/implemented/architecture/2026-10-21-plugin-settings-surfaces.md @@ -88,6 +88,22 @@ Sparkle delta。通用夹具 `build-tool-path.plugin.json`、Core 校验、Swift macOS 的 `hostCapabilities` 声明 `settings: [1, 2]`、`languageServers: [1, 2]` 和 `buildSystems: [1, 2]`。Windows 还没有这些界面和推送,所以仍只声明 1,需要 v2 的插件在 Windows 上会被市场隐藏,而不是装上后行为不完整。 +### 7. 路径选择按钮保留完整宽度 + +插件详情页比完整设置窗口窄。路径输入框若固定占用 220 点,同时右侧作用域和 +生效标签保持完整,SwiftUI 会把“选择…”按钮压成没有文字的灰条。通用路径 +控件因此固定按钮的自然宽度,让输入框随剩余空间缩短;共享设置行的标题列 +以原来的 230 点为上限,窄面板时也允许缩短。宽面板仍保持原来的列宽。 +缩放只调整布局,不替换输入框实例,以免丢失尚未提交的路径。 + +这与 IDEA Community 的文本框加浏览按钮采用相同的空间分配:检查的版本是 +`c7f91397daa3a961b4e78bc634fe467a0a7d9ade`,源码为 +`platform/platform-api/src/com/intellij/openapi/ui/TextFieldWithBrowseButton.java` +及 `ComponentWithBrowseButton.java`。后者把文本框放在 `BorderLayout.CENTER`, +把 `FixedSizeButton` 放在 `BorderLayout.EAST`,让输入部分承担宽度变化。 +macOS 保留既有原生控件和主题,只在通用 owner 中修复压缩规则,不为 Cargo +增加专门的宽度或页面。 + ## 考虑过的备选方案 ### 宿主为常见工具内置设置页 @@ -116,6 +132,7 @@ Swift 和 Windows 各写一遍合并规则最直接,但两边一旦有细微 - `cargo test -p lithe-core --lib plugin_configuration`:会话按 section 应答、更新推送、宿主会话拒绝更新。 - `./scripts/test-macos.sh --filter PluginSettingsTests`:项目层存储、作用域规则、页面注册、配置展开。 - `./scripts/test-macos.sh --filter SettingsSidebarLayoutTests`:静态页面仍各归一个分组。 +- `./scripts/test-macos.sh --filter PluginSettingsLayoutTests`:480、640、900 点宽的深浅主题下,路径输入框和完整选择按钮都在容器内,按钮可调用选择器并写入所选路径。 - 共享夹具:`shared/contracts/plugins/v1/fixtures/settings-v2.plugin.json`。 ## 适用范围 @@ -127,5 +144,6 @@ Swift 和 Windows 各写一遍合并规则最直接,但两边一旦有细微 - `macos/Sources/Lithe/Models/AppModel/AppModel+PluginSettings.swift` - `macos/Sources/Lithe/Platform/MacOS/Plugins/MacPluginSettingsStore.swift` - `macos/Sources/Lithe/Views/App/PluginSettingsSection.swift` +- `macos/Sources/Lithe/Views/Components/LitheSettingsControls.swift` - `macos/Sources/Lithe/Views/App/ContributedSettingsPageView.swift` - `shared/contracts/plugins/v1/README.md` diff --git a/macos/Sources/Lithe/Views/App/PluginSettingsSection.swift b/macos/Sources/Lithe/Views/App/PluginSettingsSection.swift index 1dd2ce7df8..088fc75828 100644 --- a/macos/Sources/Lithe/Views/App/PluginSettingsSection.swift +++ b/macos/Sources/Lithe/Views/App/PluginSettingsSection.swift @@ -282,6 +282,7 @@ private struct PluginSettingRow: View { value: shownString, placeholder: placeholder, width: 220, + isFlexible: true, accessibilityLabel: declaration.title, savesWhileTyping: savesWhileTyping, accepts: { declaration.accepts(.string($0)) }, @@ -291,6 +292,7 @@ private struct PluginSettingRow: View { if let url = choosePath(directory) { write(.string(url.path)) } } .controlSize(.small) + .fixedSize() } } } @@ -452,6 +454,7 @@ private struct PluginTextSettingField: View { let value: String let placeholder: String? let width: CGFloat + var isFlexible = false let accessibilityLabel: String let savesWhileTyping: Bool let accepts: (String) -> Bool @@ -463,7 +466,7 @@ private struct PluginTextSettingField: View { HStack(spacing: 6) { TextField(placeholder ?? "", text: $text) .litheSettingsTextField() - .frame(width: width) + .frame(minWidth: isFlexible ? 0 : width, idealWidth: width, maxWidth: width) .focused($isFocused) .accessibilityLabel(Text(verbatim: accessibilityLabel)) .onSubmit(commit) diff --git a/macos/Sources/Lithe/Views/Components/LitheSettingsControls.swift b/macos/Sources/Lithe/Views/Components/LitheSettingsControls.swift index d944a987bc..df7a5c6cdf 100644 --- a/macos/Sources/Lithe/Views/Components/LitheSettingsControls.swift +++ b/macos/Sources/Lithe/Views/Components/LitheSettingsControls.swift @@ -127,7 +127,7 @@ private struct LitheSettingsCardLines: _VariadicView_UnaryViewRoot { } } -/// One setting: a fixed label column, the control after it, and optional +/// One setting: a bounded label column, the control after it, and optional /// status pills on the trailing edge (effective value, scope, when it takes /// effect). Matches the `.srow` row of the settings mockup. struct LitheSettingsRow: View { @@ -161,7 +161,7 @@ struct LitheSettingsRow: View { .fixedSize(horizontal: false, vertical: true) if let info { LitheInfoTip(info) } } - .frame(width: Self.labelWidth, alignment: .leading) + .frame(minWidth: 0, idealWidth: Self.labelWidth, maxWidth: Self.labelWidth, alignment: .leading) HStack(spacing: 6) { control } .frame(maxWidth: .infinity, alignment: .leading) HStack(spacing: 4) { badges } diff --git a/macos/Tests/LitheTests/PluginSettingsLayoutTests.swift b/macos/Tests/LitheTests/PluginSettingsLayoutTests.swift new file mode 100644 index 0000000000..fc73e565a6 --- /dev/null +++ b/macos/Tests/LitheTests/PluginSettingsLayoutTests.swift @@ -0,0 +1,101 @@ +import AppKit +import LitheCoreContracts +import LitheModuleAPI +import SwiftUI +import Testing +@testable import Lithe + +/// A file picker remains a usable native button when plugin details are narrow. +@Suite("Plugin settings path layout", .serialized) +@MainActor +struct PluginSettingsLayoutTests { + @Test(arguments: [480.0, 640.0, 900.0], [false, true]) + func pathPickerFitsAndStillWritesTheSelectedPath(width: Double, dark: Bool) async throws { + var pickedDirectory: Bool? + var saved: ToolingJSONValue? + let selected = URL(fileURLWithPath: "/fixture/custom tools/build-tool") + let declaration = DeclarativePluginSetting( + id: "toolPath", title: "Build executable", summary: "Select a file or leave empty for discovery.", + kind: .path(directory: false, placeholder: "Automatic"), defaultValue: .string(""), + scope: .global, effect: .reload + ) + let view = PluginSettingsSection( + settings: [.resolve(declaration, global: nil, project: nil)], hasProject: true, + handlers: PluginSettingsHandlers( + setValue: { id, value, layer in + #expect(id == "toolPath" && layer == .global) + saved = value + return nil + }, + restartLanguageServers: {}, runAction: { _ in }, + choosePath: { directory in pickedDirectory = directory; return selected } + ) + ) + .padding(14) + .frame(width: width, height: 180, alignment: .topLeading) + .environment(\.colorScheme, dark ? .dark : .light) + let host = NSHostingView(rootView: view) + let window = NSWindow( + contentRect: NSRect(x: 0, y: 0, width: width, height: 180), + styleMask: [.borderless], backing: .buffered, defer: false + ) + window.isReleasedWhenClosed = false + window.appearance = NSAppearance(named: dark ? .darkAqua : .aqua) + window.contentView = host + defer { window.close() } + let application = NSApplication.shared + let attribute = NSAccessibility.Attribute(rawValue: "AXEnhancedUserInterface") + let previous = (application.accessibilityAttributeValue(attribute) as? Bool) ?? false + application.accessibilitySetValue(true, forAttribute: attribute) + defer { application.accessibilitySetValue(previous, forAttribute: attribute) } + host.layoutSubtreeIfNeeded() + let button = try #require(await chooseButton(in: host)) + let field = try #require(descendants(host).compactMap { $0 as? NSTextField }.first { $0.isEditable }) + let screenFrame = try #require(button.accessibilityFrame?()) + let buttonFrame = host.convert(window.convertFromScreen(screenFrame), from: nil) + let fieldFrame = field.convert(field.bounds, to: host) + let titleWidth = (String(localized: "Choose…") as NSString).size(withAttributes: [.font: NSFont.systemFont(ofSize: NSFont.smallSystemFontSize)]).width + #expect(buttonFrame.width >= titleWidth) + #expect(buttonFrame.minX >= fieldFrame.maxX) + #expect(host.bounds.contains(buttonFrame)) + #expect(host.bounds.contains(fieldFrame)) + #expect(fieldFrame.width > 0) + #expect(button.accessibilityPerformPress?() == true) + #expect(pickedDirectory == false) + #expect(saved == .string(selected.path)) + + if let directory = ProcessInfo.processInfo.environment["LITHE_PLUGIN_SETTINGS_LAYOUT_CAPTURES"] { + let bitmap = try #require(host.bitmapImageRepForCachingDisplay(in: host.bounds)) + host.cacheDisplay(in: host.bounds, to: bitmap) + let data = try #require(bitmap.representation(using: .png, properties: [:])) + let output = URL(fileURLWithPath: directory, isDirectory: true) + try FileManager.default.createDirectory(at: output, withIntermediateDirectories: true) + try data.write(to: output.appendingPathComponent("path-\(Int(width))-\(dark ? "dark" : "light").png")) + } + } + + private func descendants(_ view: NSView) -> [NSView] { + view.subviews.flatMap { [$0] + descendants($0) } + } + + private func chooseButton(in host: NSView) async -> AnyObject? { + let clock = ContinuousClock() + let deadline = clock.now.advanced(by: .seconds(2)) + repeat { + host.layoutSubtreeIfNeeded() + if let button = accessibleElements(in: host).first(where: { + $0.accessibilityRole?() == .button + && ($0.accessibilityLabel?() ?? $0.accessibilityTitle?()) == String(localized: "Choose…") + }) { return button } + await Task.yield() + } while clock.now < deadline + return nil + } + + private func accessibleElements(in element: Any) -> [AnyObject] { + let accessible = element as AnyObject + let children = accessible.accessibilityChildren?() ?? [] + let descendants: [Any] = children.isEmpty ? ((element as? NSView)?.subviews ?? []) : children + return [accessible] + descendants.flatMap { accessibleElements(in: $0) } + } +} diff --git a/shared/platform-feature-matrix/features/plugin-registered-settings-pages.json b/shared/platform-feature-matrix/features/plugin-registered-settings-pages.json index 996eccf2ef..4576d8d480 100644 --- a/shared/platform-feature-matrix/features/plugin-registered-settings-pages.json +++ b/shared/platform-feature-matrix/features/plugin-registered-settings-pages.json @@ -2,7 +2,7 @@ "id": "plugin-registered-settings-pages", "area": "插件", "group": "插件管理", - "capability": "插件通过 settings 2 在 plugin.json 里把设置项和按钮注册到“语言与框架 › <语言>”或“构建、执行、部署 › <构建系统>”页,按 section 分组;设置可声明项目级覆盖(写入项目 .lithe/plugin-settings.json)和生效方式(重启、立即、重新加载、下次运行),“立即生效”的值经 workspace/configuration 推给正在运行的语言服务器;按钮调用插件自己的插件函数。宿主只提供通用页面、控件和语言服务状态卡,不内置任何语言或构建工具的页面", + "capability": "插件通过 settings 2 在 plugin.json 里把设置项和按钮注册到“语言与框架 › <语言>”或“构建、执行、部署 › <构建系统>”页,按 section 分组;设置可声明项目级覆盖(写入项目 .lithe/plugin-settings.json)和生效方式(重启、立即、重新加载、下次运行),“立即生效”的值经 workspace/configuration 推给正在运行的语言服务器;按钮调用插件自己的插件函数。宿主只提供通用页面、控件和语言服务状态卡,不内置任何语言或构建工具的页面;路径选择按钮保持完整可见,窄面板由输入框和标题列缩短以容纳状态标签", "macos": { "evidence": [ "rust/lithe-core/src/plugins/settings.rs", @@ -13,7 +13,9 @@ "macos/Sources/Lithe/Views/App/PluginSettingsSection.swift", "macos/Sources/Lithe/Views/App/SettingsView.swift", "macos/Tests/LitheTests/PluginSettingsTests.swift", - "shared/contracts/plugins/v1/fixtures/settings-v2.plugin.json" + "shared/contracts/plugins/v1/fixtures/settings-v2.plugin.json", + "macos/Sources/Lithe/Views/Components/LitheSettingsControls.swift", + "macos/Tests/LitheTests/PluginSettingsLayoutTests.swift" ], "implementationStatus": "implemented", "verificationStatus": "pending" @@ -26,5 +28,5 @@ "verificationStatus": "not-applicable" }, "owner": "Plugin Platform", - "verification": "macOS:先使用 Swift 6.3.3 构建 Release,确认插件页选择回调不触发编译器崩溃;在 Release 应用中选择插件设置页,确认其侧栏分组自动展开。macOS:安装一个声明了 settings 2 页面(page/section/scope/effect/settingActions)的插件并启用,确认设置侧栏的对应分组下出现该语言或构建系统页,页内按插件和 section 分组显示设置与按钮;搜索设置标题能定位到该页。打开项目后把 scope 为 project 的设置切到“此项目”并修改,确认项目下生成 .lithe/plugin-settings.json 且显示“已在此项目覆盖”,恢复默认后文件被删除。修改 effect 为 immediate 的设置,确认语言服务器不重启而配置生效;修改 restart 设置时出现重启提示。点击带 confirm 的按钮先弹确认,再调用插件函数并给出结果通知。停用插件后页面消失。Windows:宿主仍只声明 settings/languageServers 1,需要 v2 的插件在市场中隐藏。" + "verification": "macOS:先使用 Swift 6.3.3 构建 Release,确认插件页选择回调不触发编译器崩溃;在 Release 应用中选择插件设置页,确认其侧栏分组自动展开。macOS:安装一个声明了 settings 2 页面(page/section/scope/effect/settingActions)的插件并启用,确认设置侧栏的对应分组下出现该语言或构建系统页,页内按插件和 section 分组显示设置与按钮;搜索设置标题能定位到该页。打开项目后把 scope 为 project 的设置切到“此项目”并修改,确认项目下生成 .lithe/plugin-settings.json 且显示“已在此项目覆盖”,恢复默认后文件被删除。修改 effect 为 immediate 的设置,确认语言服务器不重启而配置生效;修改 restart 设置时出现重启提示。点击带 confirm 的按钮先弹确认,再调用插件函数并给出结果通知。停用插件后页面消失。macOS 布局回归:运行 PluginSettingsLayoutTests,检查 480/640/900 点宽、深浅主题的路径控件与选择按钮不重叠且留在容器内,点击选择按钮写入所选路径;在插件详情的窄设置页确认“选择…”文字完整。Windows:宿主仍只声明 settings/languageServers 1,需要 v2 的插件在市场中隐藏。" } From 589906520dc4cfaaf02e6117cd3dfa449e54f74a Mon Sep 17 00:00:00 2001 From: Mucheen <1528136628@qq.com> Date: Thu, 22 Oct 2026 16:23:29 +0800 Subject: [PATCH 3/5] fix(macos): keep plugin details inside resized split panes --- .../2026-10-21-plugin-settings-surfaces.md | 17 +++ .../Lithe/Views/App/PluginDetailView.swift | 32 ++++- .../LitheTests/PluginDetailLayoutTests.swift | 117 ++++++++++++++++++ .../features/plugin-detail-tabs.json | 7 +- 4 files changed, 164 insertions(+), 9 deletions(-) create mode 100644 macos/Tests/LitheTests/PluginDetailLayoutTests.swift diff --git a/.agents/notes/implemented/architecture/2026-10-21-plugin-settings-surfaces.md b/.agents/notes/implemented/architecture/2026-10-21-plugin-settings-surfaces.md index 2e7f5e3339..d80d7f7a89 100644 --- a/.agents/notes/implemented/architecture/2026-10-21-plugin-settings-surfaces.md +++ b/.agents/notes/implemented/architecture/2026-10-21-plugin-settings-surfaces.md @@ -104,6 +104,22 @@ macOS 的 `hostCapabilities` 声明 `settings: [1, 2]`、`languageServers: [1, 2 macOS 保留既有原生控件和主题,只在通用 owner 中修复压缩规则,不为 Cargo 增加专门的宽度或页面。 +### 8. 插件详情不能越过分隔线 + +分隔容器分配了确定矩形,不代表子内容一定接受这个宽度。插件详情的表单 +有自己的最小宽度;窗口缩小后,原来的根容器会按更宽的内容居中,导致名称、 +页签和卡片跨进左侧列表,分隔线看起来穿过了详情。 + +详情根视图必须接受分隔容器给出的宽度,并在自己的边界内绘制。设置页的 +原生表单在宽面板填满可用宽度;面板不足以容纳完整设置行时,使用同一个 +滚动容器横向查看,保留输入框、选择器和右侧状态标签。只裁剪超出的表单会 +让部分设置无法访问;提高整个设置窗口的最小宽度又会限制其他页面,因此 +不采用这两种单独修补方式。 + +宽度只在详情正文的小容器里读取,用于分配可见区域。已构建的正文作为值 +传入,不在几何回调里重新加载插件、重建列表或保存宽度。拖动和持久化仍由 +既有 `LitheSplitPaneView` 负责,窄宽切换不替换表单实例。 + ## 考虑过的备选方案 ### 宿主为常见工具内置设置页 @@ -133,6 +149,7 @@ Swift 和 Windows 各写一遍合并规则最直接,但两边一旦有细微 - `./scripts/test-macos.sh --filter PluginSettingsTests`:项目层存储、作用域规则、页面注册、配置展开。 - `./scripts/test-macos.sh --filter SettingsSidebarLayoutTests`:静态页面仍各归一个分组。 - `./scripts/test-macos.sh --filter PluginSettingsLayoutTests`:480、640、900 点宽的深浅主题下,路径输入框和完整选择按钮都在容器内,按钮可调用选择器并写入所选路径。 +- `./scripts/test-macos.sh --filter PluginDetailLayoutTests`:实际 Java 插件表单在深浅主题中往返缩放,详情边界始终跟随分隔条,窄面板下右侧设置可经原生横向滚动到达。 - 共享夹具:`shared/contracts/plugins/v1/fixtures/settings-v2.plugin.json`。 ## 适用范围 diff --git a/macos/Sources/Lithe/Views/App/PluginDetailView.swift b/macos/Sources/Lithe/Views/App/PluginDetailView.swift index 694b45b775..ecd88dae25 100644 --- a/macos/Sources/Lithe/Views/App/PluginDetailView.swift +++ b/macos/Sources/Lithe/Views/App/PluginDetailView.swift @@ -59,14 +59,11 @@ struct PluginDetailView: View { notices tabBar Rectangle().fill(LitheTheme.divider).frame(height: 1) - ScrollView { - tabContent - .padding(22) - .frame(maxWidth: .infinity, alignment: .leading) - } - .litheScrollViewChrome() + PluginDetailContent(scrollsHorizontally: tab == .settings, content: tabContent) } + .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .topLeading) .background(LitheTheme.settingsSurface) + .clipped() } // MARK: Header @@ -86,6 +83,7 @@ struct PluginDetailView: View { .padding(.horizontal, 22) .padding(.top, 20) .padding(.bottom, 12) + .frame(minWidth: 0, maxWidth: .infinity, alignment: .leading) } private var identity: some View { @@ -705,3 +703,25 @@ struct PluginDetailView: View { PluginMarketplacePresentation.localized(key, locale: locale) } } + +/// Keep resize measurement local: the plugin's content is built before entering +/// this reader. A native settings row retains its controls and can scroll when +/// the detail pane is narrower than the complete form. +private struct PluginDetailContent: View { + let scrollsHorizontally: Bool + let content: Content + private let inset: CGFloat = 22 + + var body: some View { + GeometryReader { geometry in + ScrollView(scrollsHorizontally ? [.horizontal, .vertical] : .vertical) { + content + .frame(minWidth: max(0, geometry.size.width - 2 * inset), + maxWidth: scrollsHorizontally ? nil : .infinity, + minHeight: max(0, geometry.size.height - 2 * inset), alignment: .topLeading) + .padding(inset) + } + .litheScrollViewChrome() + } + } +} diff --git a/macos/Tests/LitheTests/PluginDetailLayoutTests.swift b/macos/Tests/LitheTests/PluginDetailLayoutTests.swift new file mode 100644 index 0000000000..67d6c80a4f --- /dev/null +++ b/macos/Tests/LitheTests/PluginDetailLayoutTests.swift @@ -0,0 +1,117 @@ +import AppKit +import LitheCoreContracts +import LitheModuleAPI +import SwiftUI +import Testing +@testable import Lithe + +/// A real plugin form must respect the same edge as the split handle when resized. +@MainActor +@Suite(.serialized) +struct PluginDetailLayoutTests { + @Test(arguments: [false, true]) + func settingsStayBesideTheDividerWhenTheWindowShrinks(dark: Bool) throws { + let descriptor = try DeclarativePluginTestSupport.officialDescriptor("JavaSupport") + var plugin = PluginManagementSnapshot( + manifest: descriptor.pluginManifest, origin: .bundled, installationStatus: .installed, + isEnabled: true, isRequired: false, isRunning: false, isQuarantined: false, + isSuppressedBySafeMode: false, requiresRestart: false, canRollback: false, + statusMessage: "Enabled", marketplace: nil + ) + plugin.settings = descriptor.settings.map { .resolve($0, global: nil, project: nil) } + let markers = PluginDetailLayoutMarkers() + let host = NSHostingView(rootView: LitheSplitPaneView( + axis: .horizontal, placement: .leading, defaultSize: 420, + minimum: PluginManagementView.listMinimumWidth, maximum: PluginManagementView.listMaximumWidth, + flexibleMinimum: PluginManagementView.detailMinimumWidth, + sized: { + Text("Installed plugins").frame(maxWidth: .infinity, maxHeight: .infinity) + .background(PluginDetailLayoutMarker { markers.sidebar = $0 }) + }, + flexible: { + PluginDetailView( + plugin: plugin, summary: "", isEnabled: true, hasPendingChange: false, + isBusy: false, isApplyingChanges: false, updateVersion: nil, sourceName: nil, error: nil, + actions: PluginDetailActions( + toggleEnabled: {}, update: nil, reinstall: nil, uninstall: {}, restore: nil, rollback: nil, + settings: PluginSettingsHandlers(setValue: { _, _, _ in nil }, + restartLanguageServers: {}, runAction: { _ in }, choosePath: { _ in nil }), + hasProject: true, openSettings: { _ in } + ), tab: .constant(.settings) + ) { + Image(systemName: "cup.and.saucer").frame(width: 48, height: 48) + } + .background(PluginDetailLayoutMarker { markers.detail = $0 }) + } + ).environment(\.colorScheme, dark ? .dark : .light)) + let window = NSWindow(contentRect: NSRect(x: 0, y: 0, width: 1100, height: 650), + styleMask: [.borderless], backing: .buffered, defer: false) + window.isReleasedWhenClosed = false + window.appearance = NSAppearance(named: dark ? .darkAqua : .aqua) + window.contentView = host + defer { window.close() } + host.layoutSubtreeIfNeeded() + let originalField = try #require(descendants(host).compactMap { $0 as? NSTextField }.first { $0.isEditable }) + var initialTopInset: CGFloat? + for (width, height) in [(1100.0, 650.0), (900, 500), (700, 700), (1000, 650)] { + window.setContentSize(CGSize(width: width, height: height)) + host.layoutSubtreeIfNeeded() + let sidebar = try #require(markers.sidebar) + let detail = try #require(markers.detail) + let left = sidebar.convert(sidebar.bounds, to: host) + let right = detail.convert(detail.bounds, to: host) + let divider = left.maxX + SplitHandleView.thickness + #expect(abs(right.minX - divider) < 1, "\(width): detail \(right) must start after sidebar \(left)") + #expect(right.maxX <= host.bounds.maxX + 1) + for field in descendants(host).compactMap({ $0 as? NSTextField }).filter(\.isEditable) { + let frame = field.convert(field.bounds, to: host) + #expect(frame.minX >= divider) + #expect(field === originalField) + } + let scroller = try #require(descendants(host).compactMap { $0 as? NSScrollView }.last { + $0.hasHorizontalScroller && $0.hasVerticalScroller + }) + let document = try #require(scroller.documentView) + let fieldFrame = originalField.convert(originalField.bounds, to: host) + let viewport = scroller.convert(scroller.bounds, to: host) + let topInset = host.isFlipped ? fieldFrame.minY - viewport.minY : viewport.maxY - fieldFrame.maxY + if let initialTopInset { + #expect(abs(topInset - initialTopInset) < 1, "A short form stays at the top when the pane height changes") + } else { + initialTopInset = topInset + } + scroller.contentView.scroll(to: CGPoint(x: document.bounds.maxX - scroller.contentView.bounds.width, y: 0)) + scroller.reflectScrolledClipView(scroller.contentView) + #expect(abs(scroller.contentView.bounds.maxX - document.bounds.maxX) < 1, + "The trailing settings remain reachable rather than being clipped") + if let directory = ProcessInfo.processInfo.environment["LITHE_PLUGIN_DETAIL_LAYOUT_CAPTURES"] { + let bitmap = try #require(host.bitmapImageRepForCachingDisplay(in: host.bounds)) + host.cacheDisplay(in: host.bounds, to: bitmap) + let data = try #require(bitmap.representation(using: .png, properties: [:])) + let output = URL(fileURLWithPath: directory, isDirectory: true) + try FileManager.default.createDirectory(at: output, withIntermediateDirectories: true) + try data.write(to: output.appendingPathComponent("detail-\(Int(width))-\(dark ? "dark" : "light").png")) + } + } + } + + private func descendants(_ view: NSView) -> [NSView] { + view.subviews.flatMap { [$0] + descendants($0) } + } +} + +@MainActor +private final class PluginDetailLayoutMarkers { + weak var sidebar: NSView? + weak var detail: NSView? +} + +private struct PluginDetailLayoutMarker: NSViewRepresentable { + let record: (NSView) -> Void + func makeNSView(context: Context) -> NSView { + let view = NSView() + record(view) + return view + } + func updateNSView(_ view: NSView, context: Context) {} +} diff --git a/shared/platform-feature-matrix/features/plugin-detail-tabs.json b/shared/platform-feature-matrix/features/plugin-detail-tabs.json index c039b0b367..407ae0be01 100644 --- a/shared/platform-feature-matrix/features/plugin-detail-tabs.json +++ b/shared/platform-feature-matrix/features/plugin-detail-tabs.json @@ -2,7 +2,7 @@ "id": "plugin-detail-tabs", "area": "插件", "group": "插件管理", - "capability": "已安装插件详情分为概览、功能、设置、权限与程序、版本与来源五个页签,信任与迁移提示固定在头部;已安装列表可按能力、更新、来源和启用状态过滤,搜索框输入 / 列出过滤选项", + "capability": "已安装插件详情分为概览、功能、设置、权限与程序、版本与来源五个页签,信任与迁移提示固定在头部;已安装列表可按能力、更新、来源和启用状态过滤,搜索框输入 / 列出过滤选项;窗口缩放及调整列表宽度时详情保持在分隔线右侧,过窄的设置表单可横向滚动查看完整控件和状态", "macos": { "evidence": [ "macos/Sources/Lithe/Views/App/PluginDetailView.swift", @@ -10,7 +10,8 @@ "macos/Sources/Lithe/Application/Features/PluginManagement.swift", "macos/Sources/Lithe/Platform/MacOS/Plugins/MacPluginManager.swift", "macos/Tests/LitheTests/PluginManagementPresentationTests.swift", - "macos/Tests/LitheTests/PluginManagerTests.swift" + "macos/Tests/LitheTests/PluginManagerTests.swift", + "macos/Tests/LitheTests/PluginDetailLayoutTests.swift" ], "implementationStatus": "implemented", "verificationStatus": "pending" @@ -23,5 +24,5 @@ "verificationStatus": "not-applicable" }, "owner": "Plugin Platform", - "verification": "macOS:打开设置 › 插件 › 已安装,选中 Java Support。头部显示名称、官方徽标、版本和状态胶囊,右侧有启用/禁用、卸载按钮。依次切换五个页签:概览显示状态、提供的能力、来源和设置数量,“在设置中配置”可跳到 LSP 和运行配置页;功能页签列出 Java 语言、语言服务器(使用插件自带的 java 运行)以及由 Lithe 提供的运行、测试、调试;设置页签显示最大内存和日志级别,修改后出现“重启语言服务器”,“恢复默认值”可一键还原;权限与程序页签列出 languageServer.launch 与 JDT LS 启动命令,内容与安装确认弹窗一致;版本与来源显示当前版本、插件 ID 和签名。安装一个社区插件,确认社区提示固定在页签上方,任何页签都能看到。在左侧点“语言服务”“社区 / 磁盘”“已禁用”等过滤芯片,确认列表随之变化并按“已启用 / 已禁用”分组;在搜索框输入 /,确认出现过滤选项,选中后搜索框清空并切换过滤。更新过的插件在版本与来源页签显示上一版本和“回滚…”,确认后需要重启 Lithe。Windows:扩展管理尚未拆分页签。" + "verification": "macOS:打开设置 › 插件 › 已安装,选中 Java Support。头部显示名称、官方徽标、版本和状态胶囊,右侧有启用/禁用、卸载按钮。依次切换五个页签:概览显示状态、提供的能力、来源和设置数量,“在设置中配置”可跳到 LSP 和运行配置页;功能页签列出 Java 语言、语言服务器(使用插件自带的 java 运行)以及由 Lithe 提供的运行、测试、调试;设置页签显示最大内存和日志级别,修改后出现“重启语言服务器”,“恢复默认值”可一键还原;权限与程序页签列出 languageServer.launch 与 JDT LS 启动命令,内容与安装确认弹窗一致;版本与来源显示当前版本、插件 ID 和签名。安装一个社区插件,确认社区提示固定在页签上方,任何页签都能看到。在左侧点“语言服务”“社区 / 磁盘”“已禁用”等过滤芯片,确认列表随之变化并按“已启用 / 已禁用”分组;在搜索框输入 /,确认出现过滤选项,选中后搜索框清空并切换过滤。更新过的插件在版本与来源页签显示上一版本和“回滚…”,确认后需要重启 Lithe。布局:在浅色和深色下缩放设置窗口、往返拖动插件列表分隔条,切换 Java/Cargo 与各页签,确认标题、页签和正文不越过分隔线;窄设置表单可横向滚动至末尾,输入控件保持同一实例,扩大后恢复填满正文。运行 PluginDetailLayoutTests 检查这些边界。Windows:扩展管理尚未拆分页签。" } From 5bac51971ad5d1da6b460748c30bdd5c83912e00 Mon Sep 17 00:00:00 2001 From: Mucheen <145200703+Mucheen@users.noreply.github.com> Date: Thu, 22 Oct 2026 22:37:10 +0800 Subject: [PATCH 4/5] refactor(plugins): unify executable candidates and injected resolution --- ...2026-10-17-build-system-plugin-contract.md | 16 +- .../2026-10-17-plugin-capability-versions.md | 11 + .../2026-10-21-plugin-settings-surfaces.md | 50 ++-- .../Core/Rust/RustBuildSystemOperations.swift | 6 +- .../MacOS/Build/MacBuildToolResolver.swift | 199 ++++--------- .../Execution/BuildSystemContracts.swift | 19 +- .../Execution/ExecutableResolution.swift | 68 +++++ .../Services/BuildSystemService.swift | 2 +- .../LitheModuleAPI/Plugins/PluginTypes.swift | 2 +- .../BuildSystemServiceTests.swift | 4 +- .../MacBuildToolResolverTests.swift | 74 ++++- .../RustBuildSystemOperationsTests.swift | 4 +- rust/lithe-core/src/build/invocation.rs | 110 ++++---- rust/lithe-core/src/build/manifest.rs | 118 +++----- rust/lithe-core/src/build/plans.rs | 8 +- rust/lithe-core/src/plugins/capabilities.rs | 4 + rust/lithe-core/src/plugins/declarative.rs | 37 +++ rust/lithe-core/src/plugins/executables.rs | 200 +++++++++++++ rust/lithe-core/src/plugins/mod.rs | 1 + rust/lithe-core/src/plugins/settings.rs | 27 +- rust/lithe-core/src/tests/build_systems.rs | 178 ++++++++++-- shared/contracts/plugins/v1/README.md | 92 ++++-- .../v1/fixtures/build-tool-path.plugin.json | 11 +- .../plugins/v1/plugin-manifest.schema.json | 262 +++++++++++++++++- shared/contracts/rust-core-api.md | 8 + .../features/build-system-plugins.json | 8 +- .../features/cargo-build-plugin.json | 8 +- 27 files changed, 1140 insertions(+), 387 deletions(-) create mode 100644 macos/Sources/LitheCoreContracts/Execution/ExecutableResolution.swift create mode 100644 rust/lithe-core/src/plugins/executables.rs diff --git a/.agents/notes/implemented/architecture/2026-10-17-build-system-plugin-contract.md b/.agents/notes/implemented/architecture/2026-10-17-build-system-plugin-contract.md index 1a84455315..0d270dd69d 100644 --- a/.agents/notes/implemented/architecture/2026-10-17-build-system-plugin-contract.md +++ b/.agents/notes/implemented/architecture/2026-10-17-build-system-plugin-contract.md @@ -69,7 +69,7 @@ Rust Core 负责校验声明、识别工程、展开每一条命令行,并把 插件可以自由描述(不需要改 Core): - **任何构建工具**:ID、标记文件、任务、选项、运行入口、测试过滤器、诊断正则、依赖命令都是数据。 -- **可执行文件**:按偏好顺序列出候选,有四种: +- **可执行文件**:按偏好顺序列出候选,有四种基础来源: - `projectFile`:工程里的 Wrapper(例如 `gradlew`),可以要求某些文件存在。它一律被视为执行仓库代码。 - `environment`:某个环境变量下的相对路径,例如 `MAVEN_HOME` 下的 `bin/mvn`。变量必须列在 `environmentInputs` 里,宿主只传这些变量。 - `command`:在 `PATH` 上查找的裸命令名。 @@ -365,3 +365,17 @@ macOS 接入规则(2026-10-18): - `shared/contracts/plugins/v1/` - `shared/contracts/rust-core-api.md` - `scripts/verify-shared-contracts.sh` + + +### 统一的候选解析扩展 + +在原有自动发现来源之上,可选 `executableResolution: 1` 增加 setting 来源与 +确定性排序;候选仍声明在同一个 executables 数组里,不增加新的 Build 覆盖路径。 +数组顺序是默认优先级,不需要路径覆盖的插件不用声明设置。 +共享类型与拓扑排序位于 `plugins::executables`,macOS 由 +`ExecutableCandidateResolver` 注入文件系统、环境、Runtime 和工具发现能力, +区分跳过、解析成功和终止失败。Provider 的可选 tool 提示继续复用宿主解析结果; +无显式选择的自动发现失败仍可让 Provider 自行查找,显式失败则停止本次模型加载。 +设置值非法时 Core 直接拒绝计划,普通设置的容错显示规则不变。 +自定义 Runtime 候选复用同一机制;其余进程模块的分步迁移边界见 +[插件设置面](2026-10-21-plugin-settings-surfaces.md)。 diff --git a/.agents/notes/implemented/architecture/2026-10-17-plugin-capability-versions.md b/.agents/notes/implemented/architecture/2026-10-17-plugin-capability-versions.md index f86ba51a7e..874a938e90 100644 --- a/.agents/notes/implemented/architecture/2026-10-17-plugin-capability-versions.md +++ b/.agents/notes/implemented/architecture/2026-10-17-plugin-capability-versions.md @@ -136,3 +136,14 @@ macOS 宿主接受级别 1 到 3(`supportedDeclarativeAPIVersions = [1, 2, 3]` - `rust/lithe-core/src/plugins/marketplace.rs` - `shared/contracts/plugins/v1/` - `shared/contracts/rust-core-api.md` + + +### 共享可执行文件候选能力 + +`executableResolution: 1` 是候选解析机制的可选能力,不是所有构建插件都要列的新字段。 +只有使用 setting 来源或 id/priority/insertBefore/insertAfter 时才声明;自动发现数组 +保持原序和原来的 buildSystems 1。macOS 先通过 Build 与自定义 Runtime 适配接入, +Windows 暂不声明;Language Server、Execution Provider 的新候选语法需各自后续接入后 +才可开放。底层源类型、排序与终止失败规则共用,启动安全约束仍属于各适配器。 +已发布 Cargo 0.1.1 的 buildSystems 2 输入通过兼容适配转换为同一个候选列表, +不维持独立 configuredExecutable 输出;细节见[插件设置面](2026-10-21-plugin-settings-surfaces.md)。 diff --git a/.agents/notes/implemented/architecture/2026-10-21-plugin-settings-surfaces.md b/.agents/notes/implemented/architecture/2026-10-21-plugin-settings-surfaces.md index d80d7f7a89..7f19d6e5b7 100644 --- a/.agents/notes/implemented/architecture/2026-10-21-plugin-settings-surfaces.md +++ b/.agents/notes/implemented/architecture/2026-10-21-plugin-settings-surfaces.md @@ -67,22 +67,35 @@ macOS 设置窗口现在可以由插件“注册”页面:插件在 `plugin.js ### 5. 构建工具的可执行文件路径 -只声明一个 file 设置不会改变构建进程。`buildSystems` 2 增加通用的 -`invocation.executableSetting`,引用全局 file 设置,生效方式为 reload 或 -nextRun。Core 负责校验引用和解析值;macOS 每次计划时读取该插件的全局值, -由平台 adapter 检查文件权限和版本,并把同一个路径用于模型 Provider 与构建、 -测试、运行。留空恢复自动发现。已指定路径失效时必须报错,不能回退到 PATH -中的另一份工具,否则模型与执行可能使用不同安装。工具父目录也放到进程 -PATH 前,供工具启动同目录的辅助程序。 - -路径只允许全局作用域,避免共享项目配置静默选择本机可执行文件。不要在 -Cargo 或其他插件 ID 下写宿主分支。插件只需声明 file 字段和引用;版本 1 -宿主通过能力协商拒绝安装,避免出现可保存但不生效的设置。 - -该设置写入既有用户偏好存储,没有新缓存或安装目录写入,不影响包签名和 -Sparkle delta。通用夹具 `build-tool-path.plugin.json`、Core 校验、Swift -路径解析与 Provider 失败回归覆盖这条边界。Cargo 专属真实执行回归仍由独立 -插件仓库维护;独立仓库的发布宿主 pin 必须在宿主变更提交后同步更新。 +路径选择使用同一个 `invocation.executables` 数组。插件需要用户覆盖时,声明 +`kind: "setting"`、`settingID`,引用全局 file 设置(reload 或 nextRun);不需要 +覆盖的插件保持原来的自动发现列表,不额外声明设置。该通用机制按 +`executableResolution: 1` 协商,不要求所有构建插件升级。 + +Core 先校验完整候选集、排定顺序,再按平台过滤。数组从前到后是首选写法; +可选 priority 以较大值优先,同分按原序;insertBefore/insertAfter 使用同集合的稳定 +id 建立相对顺序约束。插入约束优先,不能在同一候选混用 priority 或两个插入字段; +重复 id、未知锚点、自环与循环都拒绝。契约正文定义完整的确定性算法,供后续使用方复用。 + +macOS 的 `ExecutableCandidateResolver`(候选文件解析器)由宿主注入文件系统、 +环境变量、Runtime 和工具发现服务,返回跳过、已解析或终止失败。设置值来自 Core +检查后的同一操作快照;空值跳过,非空无效值直接拒绝,不能经过普通设置解析的 +“无效则回默认值”。普通设置的显示与配置容错不变。平台检查权限与版本,显式路径 +失败时 Provider 不得独立发现另一安装。带空格路径保持完整参数,父目录进入 PATH。 + +共享源类型和排序在 `plugins::executables`;本次 Build 与自定义 Runtime Dependencies +使用共享解析器,已有 Build Provider 继续通过 ServerProcess 适配和 tool 提示复用。 +Language Server、Execution Provider 等后续可接入相同机制,各自保留包内文件边界、 +自动启动限制和工作区信任;当前不在这些清单位置开放新候选语法。 +参考 xiaoyumuxi 的 #1318、#1356、#1382 以及 Maven 插件 #3,宿主仍只负责通用机制, +Provider 继续接受宿主选中的工具,不重新实现一套覆盖路径。 + +已发布预览 Cargo 0.1.1 使用旧 `executableSetting`(buildSystems 2)。保留只读的兼容 +输入适配:转换为数组首位 setting 候选,后续只走共享解析器,不再返回 +configuredExecutable。新插件必须用第五种候选和新能力;既有发行包不覆盖,迁移以新版本发布。 + +路径偏好仍写既有用户存储,候选计划只在操作内存活,没有额外缓存或安装目录写入, +不影响签名和 Sparkle delta。Core、Swift 与独立 Cargo CI 覆盖统一的选择和失败语义。 ### 6. 宿主能力版本 @@ -130,6 +143,11 @@ macOS 保留既有原生控件和主题,只在通用 owner 中修复压缩规 插件已经可以声明网页 UI,理论上可以自己画设置页。但网页无法和宿主设置窗口的搜索、分组、项目/全局切换保持一致,用户偏好也是原生优先。网页 UI 仍可用于复杂的工具窗口,设置项本身走原生控件。 +### 顶层增加可执行文件覆盖旁路 + +单独增加 executableSetting/configuredExecutable 会让 Build 的设置路径绕过候选顺序, +其它进程模块也不能复用。只为已发布预览包保留输入适配,新 API 使用统一候选与宿主能力注入。 + ### 宿主自己合并取值 Swift 和 Windows 各写一遍合并规则最直接,但两边一旦有细微差异,界面显示的值和实际启动使用的值就会不同。所以合并只在 Core 做,宿主只负责存储和显示。 diff --git a/macos/Sources/Lithe/Core/Rust/RustBuildSystemOperations.swift b/macos/Sources/Lithe/Core/Rust/RustBuildSystemOperations.swift index 754f7dd0b8..84b2ca699f 100644 --- a/macos/Sources/Lithe/Core/Rust/RustBuildSystemOperations.swift +++ b/macos/Sources/Lithe/Core/Rust/RustBuildSystemOperations.swift @@ -473,8 +473,10 @@ struct RustBuildSystemOperations: BuildSystemPlanning { let variable: String? let command: String? let runtime: String? + let settingID: String? func executable() throws -> BuildInvocation.Executable { + if kind == "setting", let settingID { return .setting(id: settingID, path: path) } switch (kind, path, variable, command, runtime) { case ("projectFile", let path?, _, _, _): return .projectFile(path: path, requires: requires ?? []) @@ -503,7 +505,6 @@ struct RustBuildSystemOperations: BuildSystemPlanning { } private struct WireInvocation: Decodable { - let configuredExecutable: String? let executables: [WireExecutable] let environmentInputs: [String] let runtimeDependencies: [WireRuntime] @@ -525,8 +526,7 @@ struct RustBuildSystemOperations: BuildSystemPlanning { ) }, versionArguments: version?.arguments, - minimumVersion: minimumVersion, - configuredExecutable: configuredExecutable + minimumVersion: minimumVersion ) } } diff --git a/macos/Sources/Lithe/Platform/MacOS/Build/MacBuildToolResolver.swift b/macos/Sources/Lithe/Platform/MacOS/Build/MacBuildToolResolver.swift index 3b55c0f26d..7f2e75a92e 100644 --- a/macos/Sources/Lithe/Platform/MacOS/Build/MacBuildToolResolver.swift +++ b/macos/Sources/Lithe/Platform/MacOS/Build/MacBuildToolResolver.swift @@ -46,60 +46,26 @@ final class MacBuildToolResolver: BuildToolResolving { } var problems: [String] = [] - if let path = invocation.configuredExecutable { - let url = URL(fileURLWithPath: path) - guard path.hasPrefix("/"), fileStorage.isExecutable(at: url) else { - throw BuildToolResolutionError(String(localized: "The configured build tool is not executable: \(path)")) - } - environment["PATH"] = url.deletingLastPathComponent().path + ":" + (environment["PATH"] ?? "") - if let tool = try await accept( - url, invocation: invocation, environment: environment, - checkVersion: checkVersion, problems: &problems - ) { return tool } - throw BuildToolResolutionError(Self.unavailableMessage(displayName, problems: problems)) - } + let resolver = candidateResolver(runtimeExecutables) for candidate in invocation.executables { - switch candidate { - case .projectFile(let path, let requires): - let url = workspaceURL.appendingPathComponent(path).standardizedFileURL - guard requires.allSatisfy({ fileStorage.fileExists(at: workspaceURL.appendingPathComponent($0)) }), - fileStorage.isExecutable(at: url) else { continue } - return ResolvedBuildTool( - executableURL: url, - environment: environment, - executesProjectCode: true, - version: nil - ) - case .environment(let variable, let path): - guard let url = environmentExecutable( - variable: variable, path: path, invocation: invocation, environment: environment - ) else { continue } - if let tool = try await accept( - url, invocation: invocation, environment: environment, - checkVersion: checkVersion, problems: &problems - ) { - return tool - } - case .command(let command): - let candidates = commandCandidates(command) - if candidates.isEmpty { - problems.append(runtime.missingToolMessage(command)) - } - for url in candidates { - if let tool = try await accept( - url, invocation: invocation, environment: environment, - checkVersion: checkVersion, problems: &problems - ) { - return tool + switch resolver.resolve(candidate, workspaceURL: workspaceURL, environment: environment, environmentInputs: invocation.environmentInputs) { + case .skip: continue + case .terminalFailure(let message): throw BuildToolResolutionError(message, terminal: true) + case .resolved(let choices): + for choice in choices { + var selectedEnvironment = environment + if choice.terminal { + selectedEnvironment["PATH"] = choice.url.deletingLastPathComponent().path + ":" + (environment["PATH"] ?? "") } - } - case .runtime(let id): - guard let url = runtimeExecutables[id] else { continue } - if let tool = try await accept( - url, invocation: invocation, environment: environment, - checkVersion: checkVersion, problems: &problems - ) { - return tool + if choice.executesProjectCode { + return ResolvedBuildTool(executableURL: choice.url, environment: selectedEnvironment, executesProjectCode: true, version: nil) + } + do { + if let tool = try await accept(choice.url, invocation: invocation, environment: selectedEnvironment, + checkVersion: checkVersion, problems: &problems) { return tool } + } catch is CancellationError { throw CancellationError() } + catch { throw BuildToolResolutionError(error.localizedDescription, terminal: choice.terminal) } + if choice.terminal { throw BuildToolResolutionError(Self.unavailableMessage(displayName, problems: problems), terminal: true) } } } } @@ -109,32 +75,25 @@ final class MacBuildToolResolver: BuildToolResolving { /// Project import needs the installation path for global settings, but /// must not run build code or a version probe merely by opening a project. func languageImportExecutable(_ invocation: BuildInvocation, workspaceURL: URL) -> URL? { - if let path = invocation.configuredExecutable { - let url = URL(fileURLWithPath: path) - return path.hasPrefix("/") && fileStorage.isExecutable(at: url) ? url : nil - } let environment = runtime.processEnvironment() + let resolver = candidateResolver([:]) for candidate in invocation.executables { - switch candidate { - case .projectFile(let path, let requires): - let url = workspaceURL.appendingPathComponent(path).standardizedFileURL - if requires.allSatisfy({ fileStorage.fileExists(at: workspaceURL.appendingPathComponent($0)) }), - fileStorage.isExecutable(at: url) { return url } - case .environment(let variable, let path): - if let url = environmentExecutable( - variable: variable, path: path, invocation: invocation, environment: environment - ) { return url } - case .command(let command): - if let url = commandCandidates(command).first { return url } - case .runtime: - // Runtime selection can probe a JDK; it is unnecessary for an - // optional installation settings path and stays lazy. - continue + // No runtime selection or version probes during passive import. + switch resolver.resolve(candidate, workspaceURL: workspaceURL, environment: environment, environmentInputs: invocation.environmentInputs) { + case .skip: continue + case .terminalFailure: return nil + case .resolved(let choices): return choices.first?.url } } return nil } + private func candidateResolver(_ runtimes: [String: URL]) -> ExecutableCandidateResolver { + ExecutableCandidateResolver(fileExists: { [fileStorage] in fileStorage.fileExists(at: $0) }, + isExecutable: { [fileStorage] in fileStorage.metadata(for: $0)?.isDirectory == false && fileStorage.isExecutable(at: $0) }, + commands: { [self] in commandCandidates($0) }, runtimes: { runtimes[$0] }) + } + /// Keeps a candidate when the build tool declares no minimum version or /// its probe satisfies it. private func accept( @@ -167,66 +126,37 @@ final class MacBuildToolResolver: BuildToolResolving { checkVersion: @escaping @Sendable (String?, String) throws -> BuildVersionCheck ) async throws -> URL { let name = dependency.displayName ?? dependency.id - var javaHome: URL? - var candidates: [URL] = [] - /// Project-local runtimes run repository code, so they are never - /// probed; the user starts them by running a command. - var projectOwned: Set = [] - if dependency.hostManaged { - if dependency.id == "java" { - javaHome = runtime.javaHomeURL() - candidates = javaHome.map { [$0.appendingPathComponent("bin/java")] } ?? [] - } else { - candidates = commandCandidates(dependency.id) - } - } else { - for executable in dependency.executables { - switch executable { - case .command(let command): - candidates += commandCandidates(command) - case .environment(let variable, let path): - if let url = environmentExecutable( - variable: variable, path: path, invocation: invocation, environment: environment - ) { - candidates.append(url) - } - case .projectFile(let path, let requires): - let url = workspaceURL.appendingPathComponent(path).standardizedFileURL - guard requires.allSatisfy({ - fileStorage.fileExists(at: workspaceURL.appendingPathComponent($0)) - }), fileStorage.isExecutable(at: url) else { continue } - candidates.append(url) - projectOwned.insert(url) - case .runtime: - // A runtime is not another runtime. - continue - } - } - } - guard !candidates.isEmpty else { - throw BuildToolResolutionError(dependency.id == "java" - ? String(localized: "No JDK is configured for this project.") - : runtime.missingToolMessage(dependency.id)) - } - + let javaHome = dependency.hostManaged && dependency.id == "java" ? runtime.javaHomeURL() : nil + let sources: [ExecutableCandidate] = dependency.hostManaged + ? (dependency.id == "java" ? [.runtime("java")] : [.command(dependency.id)]) + : dependency.executables + let resolver = candidateResolver(javaHome.map { ["java": $0.appendingPathComponent("bin/java")] } ?? [:]) var problems: [String] = [] - for url in candidates { - if !projectOwned.contains(url), - let minimum = dependency.minimumVersion, let arguments = dependency.versionArguments { - let output = await probe(url, arguments: arguments, environment: environment) - let check = try checkVersion(dependency.id, output) - guard check.satisfied else { - problems.append(Self.tooOldMessage(url.path, found: check.version, minimum: minimum)) - continue + for source in sources { + switch resolver.resolve(source, workspaceURL: workspaceURL, environment: environment, environmentInputs: invocation.environmentInputs) { + case .skip: continue + case .terminalFailure(let message): throw BuildToolResolutionError(message, terminal: true) + case .resolved(let choices): + for choice in choices { + if !choice.executesProjectCode, + let minimum = dependency.minimumVersion, let arguments = dependency.versionArguments { + let output = await probe(choice.url, arguments: arguments, environment: environment) + let check: BuildVersionCheck + do { check = try checkVersion(dependency.id, output) } + catch { throw BuildToolResolutionError(error.localizedDescription, terminal: choice.terminal) } + guard check.satisfied else { + problems.append(Self.tooOldMessage(choice.url.path, found: check.version, minimum: minimum)) + if choice.terminal { throw BuildToolResolutionError(Self.unavailableMessage(name, problems: problems), terminal: true) } + continue + } + } + if let javaHome { environment["JAVA_HOME"] = javaHome.path } + let directory = choice.url.deletingLastPathComponent().path + let path = environment["PATH"] ?? "" + environment["PATH"] = path.isEmpty ? directory : directory + ":" + path + return choice.url } } - if let javaHome { - environment["JAVA_HOME"] = javaHome.path - } - let directory = url.deletingLastPathComponent().path - let path = environment["PATH"] ?? "" - environment["PATH"] = path.isEmpty ? directory : directory + ":" + path - return url } throw BuildToolResolutionError(Self.unavailableMessage(name, problems: problems)) } @@ -237,19 +167,6 @@ final class MacBuildToolResolver: BuildToolResolving { .map(\.executableURL) } - /// Only variables the build system lists in `environmentInputs` are read. - private func environmentExecutable( - variable: String, - path: String, - invocation: BuildInvocation, - environment: [String: String] - ) -> URL? { - guard invocation.environmentInputs.contains(variable), - let base = environment[variable], base.hasPrefix("/") else { return nil } - let url = URL(fileURLWithPath: base).appendingPathComponent(path).standardizedFileURL - return fileStorage.isExecutable(at: url) ? url : nil - } - private func probe(_ url: URL, arguments: [String], environment: [String: String]) async -> String { let modified = fileStorage.metadata(for: url)?.modificationDate?.timeIntervalSince1970 ?? 0 let key = ([url.path, String(modified)] + arguments).joined(separator: "\u{1F}") diff --git a/macos/Sources/LitheCoreContracts/Execution/BuildSystemContracts.swift b/macos/Sources/LitheCoreContracts/Execution/BuildSystemContracts.swift index 0f7acce19f..1a181e3fcb 100644 --- a/macos/Sources/LitheCoreContracts/Execution/BuildSystemContracts.swift +++ b/macos/Sources/LitheCoreContracts/Execution/BuildSystemContracts.swift @@ -427,18 +427,7 @@ package struct BuildModel: Equatable, Sendable, Decodable { /// The executables of one build system on this platform, in Core's order. package struct BuildInvocation: Equatable, Sendable { - /// Explicit global file setting; failure must not fall back to discovery. - package let configuredExecutable: String? - package enum Executable: Equatable, Sendable { - /// A wrapper script inside the project. Always runs project code. - case projectFile(path: String, requires: [String]) - /// A path below the directory one environment variable names. - case environment(variable: String, path: String) - /// A bare command name the host's tool discovery resolves. - case command(String) - /// The executable of a declared runtime dependency. - case runtime(String) - } + package typealias Executable = ExecutableCandidate package struct RuntimeDependency: Equatable, Sendable { package let id: String @@ -469,12 +458,11 @@ package struct BuildInvocation: Equatable, Sendable { package init( executables: [Executable], environmentInputs: [String] = [], runtimeDependencies: [RuntimeDependency] = [], versionArguments: [String]? = nil, - minimumVersion: String? = nil, configuredExecutable: String? = nil + minimumVersion: String? = nil ) { self.executables = executables; self.environmentInputs = environmentInputs self.runtimeDependencies = runtimeDependencies; self.versionArguments = versionArguments self.minimumVersion = minimumVersion - self.configuredExecutable = configuredExecutable } } @@ -504,7 +492,8 @@ package struct ResolvedBuildTool: Equatable, Sendable { /// No candidate of a build system, or one of its runtimes, was usable. package struct BuildToolResolutionError: LocalizedError, Equatable, Sendable { package let message: String - package init(_ message: String) { self.message = message } + package let terminal: Bool + package init(_ message: String, terminal: Bool = false) { self.message = message; self.terminal = terminal } package var errorDescription: String? { message } } diff --git a/macos/Sources/LitheCoreContracts/Execution/ExecutableResolution.swift b/macos/Sources/LitheCoreContracts/Execution/ExecutableResolution.swift new file mode 100644 index 0000000000..28786863ac --- /dev/null +++ b/macos/Sources/LitheCoreContracts/Execution/ExecutableResolution.swift @@ -0,0 +1,68 @@ +import Foundation + +/// Core orders these before native discovery. Other plugin launch adapters can +/// reuse the sources without adopting Build's protocol or trust policy. +package enum ExecutableCandidate: Equatable, Sendable { + case projectFile(path: String, requires: [String]) + case environment(variable: String, path: String) + case command(String) + case runtime(String) + /// Nil is deliberately unconfigured. Core rejects invalid stored values. + case setting(id: String, path: String?) +} + +package struct ResolvedExecutableCandidate: Equatable, Sendable { + package let url: URL + package let executesProjectCode: Bool + package let terminal: Bool +} + +package enum ExecutableResolution: Equatable, Sendable { + case skip + case resolved([ResolvedExecutableCandidate]) + case terminalFailure(String) +} + +/// Pure native candidate lookup, supplied with capabilities by the platform. +/// No process runs here; each consumer keeps its own probing/trust constraints. +@MainActor +package struct ExecutableCandidateResolver { + package let fileExists: (URL) -> Bool + package let isExecutable: (URL) -> Bool + package let commands: (String) -> [URL] + package let runtimes: (String) -> URL? + + package init(fileExists: @escaping (URL) -> Bool, isExecutable: @escaping (URL) -> Bool, + commands: @escaping (String) -> [URL], runtimes: @escaping (String) -> URL?) { + self.fileExists = fileExists; self.isExecutable = isExecutable + self.commands = commands; self.runtimes = runtimes + } + + package func resolve(_ candidate: ExecutableCandidate, workspaceURL: URL, + environment: [String: String], environmentInputs: [String]) -> ExecutableResolution { + func found(_ urls: [URL], project: Bool = false, terminal: Bool = false) -> ExecutableResolution { + let selected = urls.filter(isExecutable).map { + ResolvedExecutableCandidate(url: $0, executesProjectCode: project, terminal: terminal) + } + return selected.isEmpty ? .skip : .resolved(selected) + } + switch candidate { + case .projectFile(let path, let requires): + guard requires.allSatisfy({ fileExists(workspaceURL.appendingPathComponent($0)) }) else { return .skip } + return found([workspaceURL.appendingPathComponent(path).standardizedFileURL], project: true) + case .environment(let variable, let path): + guard environmentInputs.contains(variable), let base = environment[variable], base.hasPrefix("/") else { return .skip } + return found([URL(fileURLWithPath: base).appendingPathComponent(path).standardizedFileURL]) + case .command(let command): return found(commands(command)) + case .runtime(let id): return found(runtimes(id).map { [$0] } ?? []) + case .setting(_, let path): + guard let path, !path.isEmpty else { return .skip } + guard path.hasPrefix("/"), path == path.trimmingCharacters(in: .whitespacesAndNewlines), + !path.unicodeScalars.contains(where: { CharacterSet.controlCharacters.contains($0) }), + isExecutable(URL(fileURLWithPath: path)) else { + return .terminalFailure(String(localized: "The configured build tool is not executable: \(path)")) + } + return found([URL(fileURLWithPath: path)], terminal: true) + } + } +} diff --git a/macos/Sources/LitheExecutionModule/Services/BuildSystemService.swift b/macos/Sources/LitheExecutionModule/Services/BuildSystemService.swift index 705d4a9cd5..c6cd19c265 100644 --- a/macos/Sources/LitheExecutionModule/Services/BuildSystemService.swift +++ b/macos/Sources/LitheExecutionModule/Services/BuildSystemService.swift @@ -1288,7 +1288,7 @@ package final class BuildSystemService: ObservableObject { } catch is CancellationError { throw CancellationError() } catch { - if invocation.configuredExecutable != nil { throw error } + if (error as? BuildToolResolutionError)?.terminal == true { throw error } if canAppend(owner) { appendOutput( "\n" + String(localized: "The provider looks up the build tool itself: \(error.localizedDescription)") + "\n", diff --git a/macos/Sources/LitheModuleAPI/Plugins/PluginTypes.swift b/macos/Sources/LitheModuleAPI/Plugins/PluginTypes.swift index 7f015dc8ae..2366cb11ad 100644 --- a/macos/Sources/LitheModuleAPI/Plugins/PluginTypes.swift +++ b/macos/Sources/LitheModuleAPI/Plugins/PluginTypes.swift @@ -491,7 +491,7 @@ public struct PluginManifest: Equatable, Codable, Sendable { /// not running it, so an entry is added only with its host support. public static let hostCapabilities: [String: [Int]] = [ "buildProviders": [1], - "buildSystems": [1, 2], + "buildSystems": [1, 2], "executableResolution": [1], "executionProviders": [1], "languageServers": [1, 2], "languages": [1], diff --git a/macos/Tests/LitheExecutionModuleTests/BuildSystemServiceTests.swift b/macos/Tests/LitheExecutionModuleTests/BuildSystemServiceTests.swift index a1666af12b..1c3e076ede 100644 --- a/macos/Tests/LitheExecutionModuleTests/BuildSystemServiceTests.swift +++ b/macos/Tests/LitheExecutionModuleTests/BuildSystemServiceTests.swift @@ -1492,7 +1492,7 @@ struct BuildSystemServiceTests { #expect(pluginID == "dev.example") return ["toolPath": .string("/custom tools/build")] }) - harness.tools.failure = BuildToolResolutionError("Selected executable is unavailable.") + harness.tools.failure = BuildToolResolutionError("Selected executable is unavailable.", terminal: true) defer { harness.service.stop() } harness.service.reset(workspaceURL: Self.workspace) #expect(await harness.waitForEntries { $0.first?.modelState == .notLoaded }) @@ -2057,7 +2057,7 @@ private final class FakeBuildPlanner: BuildSystemPlanning, @unchecked Sendable { func invocationPlan(_ target: BuildSystemTarget, root: String, settings: [String: ToolingJSONValue]) throws -> BuildInvocation { let configured: String? = if case .string(let path)? = settings["toolPath"] { path } else { nil } - return BuildInvocation(executables: [.command("fake")], configuredExecutable: configured) + return BuildInvocation(executables: [.setting(id: "toolPath", path: configured), .command("fake")]) } func checkToolVersion(_ target: BuildSystemTarget, runtime: String?, output: String) throws -> BuildVersionCheck { diff --git a/macos/Tests/LitheTests/MacBuildToolResolverTests.swift b/macos/Tests/LitheTests/MacBuildToolResolverTests.swift index 605a4b199d..24d8c1f3a2 100644 --- a/macos/Tests/LitheTests/MacBuildToolResolverTests.swift +++ b/macos/Tests/LitheTests/MacBuildToolResolverTests.swift @@ -6,6 +6,48 @@ import Testing @Suite("Build tool resolver version output") @MainActor struct MacBuildToolResolverTests { + @Test + func emptySettingSkipsToWrapperAndPassiveSelectionNeverProbes() async throws { + let root = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString) + defer { try? FileManager.default.removeItem(at: root) } + try FileManager.default.createDirectory(at: root, withIntermediateDirectories: true) + let marker = root.appendingPathComponent("unexpected-probe") + let wrapper = root.appendingPathComponent("wrapper") + try Data("#!/bin/sh\ntouch '\(marker.path)'\n".utf8).write(to: wrapper) + try FileManager.default.setAttributes([.posixPermissions: 0o755], ofItemAtPath: wrapper.path) + let runtime = ProjectRuntimeService(runtimeLocator: BuildProbeRuntimeLocator(home: root), store: BuildProbeEmptyStore()) + let resolver = MacBuildToolResolver(runtime: runtime, processRunner: MacProcessRunner(), fileStorage: MacFileStorage()) + let invocation = BuildInvocation(executables: [.setting(id: "toolPath", path: nil), .projectFile(path: "wrapper", requires: [])], + versionArguments: ["--version"], minimumVersion: "2") + #expect(resolver.languageImportExecutable(invocation, workspaceURL: root) == wrapper) + let result = try await resolver.resolve(invocation, displayName: "Fixture", workspaceURL: root) { _, _ in + Issue.record("A wrapper must not be probed") + return BuildVersionCheck(satisfied: false, version: nil) + } + #expect(result.executableURL == wrapper) + #expect(result.executesProjectCode) + #expect(!FileManager.default.fileExists(atPath: marker.path)) + let invalid = BuildInvocation(executables: [.setting(id: "toolPath", path: root.appendingPathComponent("missing").path), .projectFile(path: "wrapper", requires: [])]) + #expect(resolver.languageImportExecutable(invalid, workspaceURL: root) == nil) + } + + @Test + func sharedResolverUsesInjectedEnvironmentCommandAndRuntimeDiscovery() { + let custom = URL(fileURLWithPath: "/tools/build") + let resolver = ExecutableCandidateResolver(fileExists: { _ in true }, isExecutable: { $0 == custom }, + commands: { $0 == "build" ? [custom] : [] }, runtimes: { $0 == "build" ? custom : nil }) + let workspace = URL(fileURLWithPath: "/workspace") + for candidate in [ExecutableCandidate.command("build"), .runtime("build"), .environment(variable: "BUILD_HOME", path: "build")] { + guard case .resolved(let result) = resolver.resolve(candidate, workspaceURL: workspace, + environment: ["BUILD_HOME": "/tools"], environmentInputs: ["BUILD_HOME"]) else { + Issue.record("The injected source must resolve") + continue + } + #expect(result.first?.url == custom) + } + #expect(resolver.resolve(.environment(variable: "BUILD_HOME", path: "build"), workspaceURL: workspace, + environment: ["BUILD_HOME": "/tools"], environmentInputs: []) == .skip) + } @Test func configuredPathWithSpacesWinsOverDiscoveryAndSuppliesItsDirectory() async throws { let root = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString) @@ -17,8 +59,8 @@ struct MacBuildToolResolverTests { let runtime = ProjectRuntimeService(runtimeLocator: BuildProbeRuntimeLocator(home: root), store: BuildProbeEmptyStore()) let resolver = MacBuildToolResolver(runtime: runtime, processRunner: MacProcessRunner(), fileStorage: MacFileStorage()) let invocation = BuildInvocation( - executables: [.command("unavailable")], versionArguments: ["--version"], - minimumVersion: "2", configuredExecutable: executable.path + executables: [.setting(id: "toolPath", path: executable.path), .command("unavailable")], versionArguments: ["--version"], + minimumVersion: "2" ) let resolved = try await resolver.resolve(invocation, displayName: "Fixture", workspaceURL: root) { _, output in BuildVersionCheck(satisfied: output.contains("fixture 2.0"), version: "2.0") @@ -28,13 +70,15 @@ struct MacBuildToolResolverTests { #expect(resolver.languageImportExecutable(invocation, workspaceURL: root) == executable) } - @Test(arguments: ["missing", "non-executable", "old"]) + @Test(arguments: ["missing", "non-executable", "old", "directory"]) func unusableConfiguredPathNeverFallsBackToAvailableWrapper(_ failure: String) async throws { let root = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString) defer { try? FileManager.default.removeItem(at: root) } try FileManager.default.createDirectory(at: root, withIntermediateDirectories: true) let configured = root.appendingPathComponent("configured") - if failure != "missing" { + if failure == "directory" { + try FileManager.default.createDirectory(at: configured, withIntermediateDirectories: true) + } else if failure != "missing" { try Data("#!/bin/sh\nprintf 'fixture 1.0\\n'\n".utf8).write(to: configured) try FileManager.default.setAttributes([.posixPermissions: failure == "old" ? 0o755 : 0o644], ofItemAtPath: configured.path) } @@ -44,8 +88,8 @@ struct MacBuildToolResolverTests { let runtime = ProjectRuntimeService(runtimeLocator: BuildProbeRuntimeLocator(home: root), store: BuildProbeEmptyStore()) let resolver = MacBuildToolResolver(runtime: runtime, processRunner: MacProcessRunner(), fileStorage: MacFileStorage()) let invocation = BuildInvocation( - executables: [.projectFile(path: "wrapper", requires: [])], versionArguments: ["--version"], - minimumVersion: "2", configuredExecutable: configured.path + executables: [.setting(id: "toolPath", path: configured.path), .projectFile(path: "wrapper", requires: [])], versionArguments: ["--version"], + minimumVersion: "2" ) await #expect(throws: BuildToolResolutionError.self) { try await resolver.resolve(invocation, displayName: "Fixture", workspaceURL: root) { _, _ in @@ -54,6 +98,24 @@ struct MacBuildToolResolverTests { } } + @Test + func customRuntimeUsesTheSharedSettingCandidateAndDoesNotFallBack() async throws { + let root = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString) + defer { try? FileManager.default.removeItem(at: root) } + try FileManager.default.createDirectory(at: root, withIntermediateDirectories: true) + let runtime = ProjectRuntimeService(runtimeLocator: BuildProbeRuntimeLocator(home: root), store: BuildProbeEmptyStore()) + let resolver = MacBuildToolResolver(runtime: runtime, processRunner: MacProcessRunner(), fileStorage: MacFileStorage()) + let invocation = BuildInvocation(executables: [.runtime("custom")], runtimeDependencies: [ + .init(id: "custom", hostManaged: false, executables: [.setting(id: "runtimePath", path: root.appendingPathComponent("missing").path), .command("sh")]) + ]) + do { + _ = try await resolver.resolve(invocation, displayName: "Fixture", workspaceURL: root) { _, _ in + BuildVersionCheck(satisfied: true, version: nil) + } + Issue.record("An explicit runtime failure must terminate discovery") + } catch let error as BuildToolResolutionError { #expect(error.terminal) } + } + @Test func languageImportDiscoversWrapperWithoutExecutingItOrRuntimeProbes() throws { let root = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString) diff --git a/macos/Tests/LitheTests/RustBuildSystemOperationsTests.swift b/macos/Tests/LitheTests/RustBuildSystemOperationsTests.swift index 19b04f9e48..fc629d2ee5 100644 --- a/macos/Tests/LitheTests/RustBuildSystemOperationsTests.swift +++ b/macos/Tests/LitheTests/RustBuildSystemOperationsTests.swift @@ -72,8 +72,8 @@ struct RustBuildSystemOperationsTests { func invocationUsesTheGlobalExecutableSetting() throws { let target = try Self.target("build-tool-path", "fixture") let custom = try operations.invocationPlan(target, root: ".", settings: ["toolPath": .string("/opt/custom tools/build")]) - #expect(custom.configuredExecutable == "/opt/custom tools/build") - #expect(try operations.invocationPlan(target, root: ".").configuredExecutable == nil) + #expect(custom.executables.first == .setting(id: "toolPath", path: "/opt/custom tools/build")) + #expect(try operations.invocationPlan(target, root: ".").executables.first == .setting(id: "toolPath", path: nil)) } @Test diff --git a/rust/lithe-core/src/build/invocation.rs b/rust/lithe-core/src/build/invocation.rs index 1029b57d62..4fddc96485 100644 --- a/rust/lithe-core/src/build/invocation.rs +++ b/rust/lithe-core/src/build/invocation.rs @@ -8,13 +8,14 @@ use super::decode::{self, join_relative}; use super::manifest::{ - BuildSystemDeclaration, ExecutableCandidate, Platform, RuntimeDependency, VersionProbe, + BuildSystemDeclaration, ExecutableCandidate, ExecutableSource, Platform, RuntimeDependency, + VersionProbe, }; use crate::plugins::declarative::{ reported_version, validate_minimum_version, version_components, DeclarativePluginManifest, PluginRejection, Validation, }; -use crate::plugins::settings::SettingLayers; +use crate::plugins::executables::ordered_indices; use serde::Deserialize; use serde_json::{json, Value}; use std::collections::BTreeMap; @@ -40,34 +41,29 @@ pub(crate) struct VersionCheckRequest { pub(crate) output: String, } -fn candidates(candidates: &[ExecutableCandidate], root: &str, platform: Platform) -> Vec { - candidates - .iter() - .filter(|candidate| { - candidate.platforms().is_empty() || candidate.platforms().contains(&platform) - }) - .map(|candidate| match candidate { - ExecutableCandidate::ProjectFile { path, requires, .. } => json!({ - "kind": "projectFile", - "path": join_relative(root, path), - "requires": requires.iter().map(|file| join_relative(root, file)).collect::>(), - "executesProjectCode": true, - }), - ExecutableCandidate::Environment { variable, path, .. } => json!({ - "kind": "environment", - "variable": variable, - "path": path, - }), - ExecutableCandidate::Command { command, .. } => json!({ - "kind": "command", - "command": command, - }), - ExecutableCandidate::Runtime { runtime, .. } => json!({ - "kind": "runtime", - "runtime": runtime, - }), - }) - .collect() +fn candidates( + candidates: &[ExecutableCandidate], + root: &str, + platform: Platform, + manifest: &DeclarativePluginManifest, + settings: &BTreeMap, +) -> Validation> { + ordered_indices(candidates, "executables")?.into_iter() + .filter(|&index| candidates[index].platforms.is_empty() || candidates[index].platforms.contains(&platform)) + .map(|index| { + let candidate = &candidates[index]; + Ok(match &candidate.source { + ExecutableSource::ProjectFile { path, requires } => json!({ + "kind": "projectFile", "path": join_relative(root, path), + "requires": requires.iter().map(|file| join_relative(root, file)).collect::>(), "executesProjectCode": true, + }), + ExecutableSource::Environment { variable, path } => json!({ "kind": "environment", "variable": variable, "path": path }), + ExecutableSource::Command { command } => json!({ "kind": "command", "command": command }), + ExecutableSource::Runtime { runtime } => json!({ "kind": "runtime", "runtime": runtime }), + ExecutableSource::Setting { setting_id } => json!({ "kind": "setting", "settingID": setting_id, + "path": manifest.executable_setting_value(setting_id, settings)? }), + }) + }).collect() } /// Arguments that make a host-managed runtime print its version and exit. @@ -84,7 +80,13 @@ pub(crate) fn host_runtime_version_arguments(id: &str) -> Option<&'static [&'sta } } -fn runtime(runtime: &RuntimeDependency, root: &str, platform: Platform) -> Value { +fn runtime( + runtime: &RuntimeDependency, + root: &str, + platform: Platform, + manifest: &DeclarativePluginManifest, + settings: &BTreeMap, +) -> Validation { let version = if runtime.is_host_managed() { host_runtime_version_arguments(&runtime.id) .map(|arguments| json!({ "arguments": arguments })) @@ -94,14 +96,14 @@ fn runtime(runtime: &RuntimeDependency, root: &str, platform: Platform) -> Value .as_ref() .map(|probe| json!({ "arguments": probe.arguments })) }; - json!({ + Ok(json!({ "id": runtime.id, "displayName": runtime.display_name, "hostManaged": runtime.is_host_managed(), "minimumVersion": runtime.minimum_version, - "executables": candidates(&runtime.executables, root, platform), + "executables": candidates(&runtime.executables, root, platform, manifest, settings)?, "version": version, - }) + })) } /// `build.invocationPlan`: the candidates for this platform, in order, with @@ -113,7 +115,17 @@ pub(crate) fn invocation_plan( ) -> Validation { let root = decode::request_path(&request.root, "root")?; let invocation = &build_system.invocation; - let executables = candidates(&invocation.executables, &root, request.platform); + let mut executables = candidates( + &invocation.executables, + &root, + request.platform, + manifest, + &request.settings, + )?; + // Published v2 preview manifests adapt into the same candidate path. + if let Some(id) = &invocation.executable_setting { + executables.insert(0, json!({ "kind": "setting", "settingID": id, "path": manifest.executable_setting_value(id, &request.settings)? })); + } if executables.is_empty() { return Err(PluginRejection::new( "plugin.build.unavailable", @@ -123,23 +135,7 @@ pub(crate) fn invocation_plan( ), )); } - let configured_executable = invocation.executable_setting.as_ref().and_then(|id| { - manifest - .resolve_settings(SettingLayers { - global: &request.settings, - project: &BTreeMap::new(), - }) - .into_iter() - .find(|setting| &setting.id == id) - .and_then(|setting| { - setting - .value - .as_str() - .filter(|path| !path.is_empty()) - .map(str::to_owned) - }) - }); - let mut plan = json!({ + Ok(json!({ "buildSystemID": build_system.id, "root": root, "executables": executables, @@ -147,15 +143,11 @@ pub(crate) fn invocation_plan( "runtimeDependencies": invocation .runtime_dependencies .iter() - .map(|dependency| runtime(dependency, &root, request.platform)) - .collect::>(), + .map(|dependency| runtime(dependency, &root, request.platform, manifest, &request.settings)) + .collect::>>()?, "version": invocation.version.as_ref().map(|probe| json!({ "arguments": probe.arguments })), "minimumVersion": invocation.minimum_version, - }); - if let Some(path) = configured_executable { - plan["configuredExecutable"] = json!(path); - } - Ok(plan) + })) } /// `build.checkToolVersion`: reads the probe output of the build tool or of diff --git a/rust/lithe-core/src/build/manifest.rs b/rust/lithe-core/src/build/manifest.rs index d4e2837724..5a9bd8760d 100644 --- a/rust/lithe-core/src/build/manifest.rs +++ b/rust/lithe-core/src/build/manifest.rs @@ -192,8 +192,8 @@ pub(crate) enum Nesting { #[derive(Debug, Clone, Deserialize, Serialize)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub(crate) struct Invocation { - /// Optional global file setting selecting the executable. An empty value - /// keeps discovery; a configured path must never fall back silently. + /// Compatibility adapter for published buildSystems 2 previews. New + /// plugins declare a setting candidate in executables instead. #[serde(default, skip_serializing_if = "Option::is_none")] pub(crate) executable_setting: Option, /// Candidates in preference order; the host takes the first that exists. @@ -211,74 +211,7 @@ pub(crate) struct Invocation { pub(crate) minimum_version: Option, } -/// One place an executable may come from. -#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)] -#[serde( - tag = "kind", - rename_all = "camelCase", - rename_all_fields = "camelCase", - deny_unknown_fields -)] -pub(crate) enum ExecutableCandidate { - /// A file inside the instance root, such as a wrapper script. Running it - /// always counts as running project code. - ProjectFile { - path: String, - /// Further files that must exist for the candidate to apply. - #[serde(default, skip_serializing_if = "Vec::is_empty")] - requires: Vec, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - platforms: Vec, - }, - /// A path below a directory named by a declared environment input. - Environment { - variable: String, - path: String, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - platforms: Vec, - }, - /// A bare command resolved through the host's tool discovery. - Command { - command: String, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - platforms: Vec, - }, - /// The executable of a declared runtime dependency itself. - Runtime { - runtime: String, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - platforms: Vec, - }, -} - -impl ExecutableCandidate { - pub(crate) fn platforms(&self) -> &[Platform] { - match self { - Self::ProjectFile { platforms, .. } - | Self::Environment { platforms, .. } - | Self::Command { platforms, .. } - | Self::Runtime { platforms, .. } => platforms, - } - } - - fn platforms_mut(&mut self) -> &mut Vec { - match self { - Self::ProjectFile { platforms, .. } - | Self::Environment { platforms, .. } - | Self::Command { platforms, .. } - | Self::Runtime { platforms, .. } => platforms, - } - } -} - -/// Host operating systems a candidate applies to; empty means all. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Deserialize, Serialize)] -#[serde(rename_all = "lowercase")] -pub(crate) enum Platform { - Macos, - Linux, - Windows, -} +pub(crate) use crate::plugins::executables::{ExecutableCandidate, ExecutableSource, Platform}; /// A runtime the tool needs. Runtimes the host already manages (`java`, /// `node`, `go`) take only an ID and an optional minimum version and follow @@ -1425,6 +1358,13 @@ impl BuildSystemDeclaration { let invocation = &mut self.invocation; let field = format!("{field}.invocation"); if let Some(id) = &invocation.executable_setting { + if invocation + .executables + .iter() + .any(ExecutableCandidate::uses_resolution) + { + return Err(invalid(&field, "Do not combine the legacy executableSetting adapter with new candidate metadata or setting sources.")); + } if context.build_systems_version < 2 || !context.declared_settings.is_executable(id) { return Err(invalid( format!("{field}.executableSetting"), @@ -1489,7 +1429,7 @@ impl BuildSystemDeclaration { } for (candidate_index, candidate) in runtime.executables.iter_mut().enumerate() { let candidate_field = format!("{field}.executables[{candidate_index}]"); - if matches!(candidate, ExecutableCandidate::Runtime { .. }) { + if matches!(candidate.source, ExecutableSource::Runtime { .. }) { return Err(invalid( candidate_field, "A runtime cannot be provided by another runtime.", @@ -1528,6 +1468,25 @@ impl BuildSystemDeclaration { &runtimes, )?; } + for (list, location) in + std::iter::once((&invocation.executables, format!("{field}.executables"))).chain( + invocation.runtime_dependencies.iter().map(|runtime| { + ( + &runtime.executables, + format!("{field}.runtimeDependencies.{}.executables", runtime.id), + ) + }), + ) + { + crate::plugins::executables::ordered_indices(list, &location)?; + for candidate in list { + if let ExecutableSource::Setting { setting_id } = &candidate.source { + if !context.declared_settings.is_executable(setting_id) { + return Err(invalid(&location, "A setting candidate needs a global file setting with effect reload or nextRun.")); + } + } + } + } if let Some(probe) = &invocation.version { probe.validate(&format!("{field}.version"))?; } @@ -2038,8 +1997,8 @@ fn check_candidate( environment_inputs: &[String], runtimes: &BTreeSet, ) -> Validation<()> { - match candidate { - ExecutableCandidate::ProjectFile { path, requires, .. } => { + match &mut candidate.source { + ExecutableSource::ProjectFile { path, requires, .. } => { *requires = sorted_unique(std::mem::take(requires)); if !is_safe_relative_path(path) || !requires.iter().all(|value| is_safe_relative_path(value)) @@ -2047,7 +2006,7 @@ fn check_candidate( return Err(executable_path(field)); } } - ExecutableCandidate::Environment { variable, path, .. } => { + ExecutableSource::Environment { variable, path, .. } => { if !environment_inputs.contains(variable) { return Err(invalid( format!("{field}.variable"), @@ -2058,7 +2017,7 @@ fn check_candidate( return Err(executable_path(field)); } } - ExecutableCandidate::Command { command, .. } => { + ExecutableSource::Command { command, .. } => { if !is_bare_command(command) { return Err(invalid( format!("{field}.command"), @@ -2066,7 +2025,12 @@ fn check_candidate( )); } } - ExecutableCandidate::Runtime { runtime, .. } => { + ExecutableSource::Setting { setting_id } => { + if !is_setting_identifier(setting_id) { + return Err(invalid(format!("{field}.settingID"), "Invalid setting ID.")); + } + } + ExecutableSource::Runtime { runtime, .. } => { if !runtimes.contains(runtime) { return Err(invalid( format!("{field}.runtime"), @@ -2075,7 +2039,7 @@ fn check_candidate( } } } - let platforms = candidate.platforms_mut(); + let platforms = &mut candidate.platforms; platforms.sort(); platforms.dedup(); Ok(()) diff --git a/rust/lithe-core/src/build/plans.rs b/rust/lithe-core/src/build/plans.rs index 6c5f0179a1..15e4244980 100644 --- a/rust/lithe-core/src/build/plans.rs +++ b/rust/lithe-core/src/build/plans.rs @@ -816,9 +816,11 @@ pub(crate) fn dependency_plan( /// entries then need no executable resolution of their own. fn sole_command(build_system: &BuildSystemDeclaration) -> Option<&str> { match build_system.invocation.executables.as_slice() { - [ExecutableCandidate::Command { command, platforms }] if platforms.is_empty() => { - Some(command) - } + [ExecutableCandidate { + source: super::manifest::ExecutableSource::Command { command }, + platforms, + .. + }] if platforms.is_empty() => Some(command), _ => None, } } diff --git a/rust/lithe-core/src/plugins/capabilities.rs b/rust/lithe-core/src/plugins/capabilities.rs index d4b8a2d5f8..69eaaf0d6b 100644 --- a/rust/lithe-core/src/plugins/capabilities.rs +++ b/rust/lithe-core/src/plugins/capabilities.rs @@ -42,12 +42,16 @@ pub(crate) const BUILD_SYSTEMS: &str = "buildSystems"; /// `buildSystems[].provider`, whether it owns or shares a language server process. pub(crate) const BUILD_PROVIDERS: &str = "buildProviders"; +/// Shared executable candidate order and strict explicit selection. +pub(crate) const EXECUTABLE_RESOLUTION: &str = "executableResolution"; + /// Capability versions this Core build validates and plans. Version 1 of a /// capability keeps the meaning its section had at API level 2. pub const SUPPORTED_CAPABILITIES: &[(&str, &[u32])] = &[ (BUILD_PROVIDERS, &[1]), (BUILD_SYSTEMS, &[1, 2]), (EXECUTION_PROVIDERS, &[1]), + (EXECUTABLE_RESOLUTION, &[1]), (LANGUAGE_SERVERS, &[1, 2]), (LANGUAGES, &[1]), (SERVER_PROCESS, &[1]), diff --git a/rust/lithe-core/src/plugins/declarative.rs b/rust/lithe-core/src/plugins/declarative.rs index a7a88f4da5..f302d6ac9a 100644 --- a/rust/lithe-core/src/plugins/declarative.rs +++ b/rust/lithe-core/src/plugins/declarative.rs @@ -910,6 +910,23 @@ impl DeclarativePluginManifest { /// server and every own build provider is a `serverProcess`. fn used_capabilities(&self) -> BTreeSet<&'static str> { let sections = [ + ( + capabilities::EXECUTABLE_RESOLUTION, + self.build_systems.iter().any(|system| { + system + .invocation + .executables + .iter() + .chain( + system + .invocation + .runtime_dependencies + .iter() + .flat_map(|runtime| &runtime.executables), + ) + .any(|candidate| candidate.uses_resolution()) + }), + ), (capabilities::LANGUAGES, !self.languages.is_empty()), ( capabilities::LANGUAGE_SERVERS, @@ -1249,6 +1266,26 @@ impl DeclarativePluginManifest { Ok(()) } + /// Strict executable selection preserves invalid stored values instead of + /// applying the UI settings resolver's tolerant fallback-to-default rule. + pub(crate) fn executable_setting_value( + &self, + id: &str, + values: &BTreeMap, + ) -> Validation> { + let setting = self + .settings + .iter() + .find(|setting| setting.id == id) + .ok_or_else(|| { + invalid( + "executables.settingID", + "The executable setting is not declared.", + ) + })?; + setting.executable_value(values.get(id)) + } + /// Effective value of every declared setting and the layer it came from. pub(crate) fn resolve_settings(&self, layers: SettingLayers<'_>) -> Vec { super::settings::resolve(&self.settings, layers) diff --git a/rust/lithe-core/src/plugins/executables.rs b/rust/lithe-core/src/plugins/executables.rs new file mode 100644 index 0000000000..57fddb5a7d --- /dev/null +++ b/rust/lithe-core/src/plugins/executables.rs @@ -0,0 +1,200 @@ +//! Shared executable candidate declarations and deterministic ordering. +//! Native discovery, trust and probing remain injected host responsibilities. + +use super::declarative::{invalid, is_identifier, Validation}; +use serde::{Deserialize, Deserializer, Serialize}; +use serde_json::Value; +use std::collections::{BTreeMap, BTreeSet}; + +/// A source plus optional ordering constraints within one plugin-owned set. +#[derive(Debug, Clone, PartialEq, Eq, Serialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct ExecutableCandidate { + #[serde(flatten)] + pub(crate) source: ExecutableSource, + #[serde(skip_serializing_if = "Option::is_none")] + pub(crate) id: Option, + /// Higher priorities run first; absent means 0. Ties use array order. + #[serde(skip_serializing_if = "Option::is_none")] + pub(crate) priority: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub(crate) insert_before: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub(crate) insert_after: Option, + #[serde(skip_serializing_if = "Vec::is_empty")] + pub(crate) platforms: Vec, +} + +impl<'de> Deserialize<'de> for ExecutableCandidate { + fn deserialize>(deserializer: D) -> Result { + let mut value = Value::deserialize(deserializer)?; + let map = value + .as_object_mut() + .ok_or_else(|| serde::de::Error::custom("An executable is an object."))?; + // Decode metadata separately so source-specific unknown fields still + // fail closed instead of disappearing through serde flatten. + let id = map + .remove("id") + .map(serde_json::from_value) + .transpose() + .map_err(serde::de::Error::custom)?; + let priority = map + .remove("priority") + .map(serde_json::from_value) + .transpose() + .map_err(serde::de::Error::custom)?; + let insert_before = map + .remove("insertBefore") + .map(serde_json::from_value) + .transpose() + .map_err(serde::de::Error::custom)?; + let insert_after = map + .remove("insertAfter") + .map(serde_json::from_value) + .transpose() + .map_err(serde::de::Error::custom)?; + let platforms = map + .remove("platforms") + .map(serde_json::from_value) + .transpose() + .map_err(serde::de::Error::custom)? + .unwrap_or_default(); + let source = serde_json::from_value(value).map_err(serde::de::Error::custom)?; + Ok(Self { + source, + id, + priority, + insert_before, + insert_after, + platforms, + }) + } +} + +/// Platform-neutral source. Adapters supply each native discovery capability. +#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)] +#[serde( + tag = "kind", + rename_all = "camelCase", + rename_all_fields = "camelCase", + deny_unknown_fields +)] +pub(crate) enum ExecutableSource { + ProjectFile { + path: String, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + requires: Vec, + }, + Environment { + variable: String, + path: String, + }, + Command { + command: String, + }, + Runtime { + runtime: String, + }, + /// Global file preference; empty skips, any invalid nonempty value fails. + Setting { + #[serde(rename = "settingID")] + setting_id: String, + }, +} + +/// Operating system filter, applied after validating the complete candidate set. +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Deserialize, Serialize)] +#[serde(rename_all = "lowercase")] +pub(crate) enum Platform { + Macos, + Linux, + Windows, +} + +impl ExecutableCandidate { + pub(crate) fn uses_resolution(&self) -> bool { + matches!(self.source, ExecutableSource::Setting { .. }) + || self.id.is_some() + || self.priority.is_some() + || self.insert_before.is_some() + || self.insert_after.is_some() + } +} + +/// Stable topological sort: explicit edges win, otherwise higher priority then +/// original array index wins. No cross-set anchors or arbitrary host code. +pub(crate) fn ordered_indices( + candidates: &[ExecutableCandidate], + field: &str, +) -> Validation> { + let mut ids = BTreeMap::new(); + for (index, candidate) in candidates.iter().enumerate() { + if let Some(id) = &candidate.id { + if !is_identifier(id) || ids.insert(id.as_str(), index).is_some() { + return Err(invalid( + field, + "Candidate IDs must be valid and unique within their set.", + )); + } + } + if (candidate.priority.is_some() + && (candidate.insert_before.is_some() || candidate.insert_after.is_some())) + || (candidate.insert_before.is_some() && candidate.insert_after.is_some()) + { + return Err(invalid( + field, + "Use priority or one relative insertion constraint, not both.", + )); + } + } + let mut edges = vec![BTreeSet::new(); candidates.len()]; + let mut incoming = vec![0usize; candidates.len()]; + for (index, candidate) in candidates.iter().enumerate() { + for (anchor, before) in [ + (candidate.insert_before.as_deref(), true), + (candidate.insert_after.as_deref(), false), + ] { + let Some(anchor) = anchor else { continue }; + let other = *ids.get(anchor).ok_or_else(|| { + invalid( + field, + "An insertion anchor must name a candidate in this set.", + ) + })?; + let (from, to) = if before { + (index, other) + } else { + (other, index) + }; + if edges[from].insert(to) { + incoming[to] += 1; + } + } + } + let mut result = Vec::with_capacity(candidates.len()); + let mut remaining: BTreeSet<_> = (0..candidates.len()).collect(); + while !remaining.is_empty() { + let next = remaining + .iter() + .copied() + .filter(|&index| incoming[index] == 0) + .min_by_key(|&index| { + ( + std::cmp::Reverse(candidates[index].priority.unwrap_or(0)), + index, + ) + }) + .ok_or_else(|| { + invalid( + field, + "Candidate insertion constraints contain a cycle or contradiction.", + ) + })?; + remaining.remove(&next); + result.push(next); + for &to in &edges[next] { + incoming[to] -= 1; + } + } + Ok(result) +} diff --git a/rust/lithe-core/src/plugins/mod.rs b/rust/lithe-core/src/plugins/mod.rs index 7431ebc539..2a228ddd41 100644 --- a/rust/lithe-core/src/plugins/mod.rs +++ b/rust/lithe-core/src/plugins/mod.rs @@ -2,6 +2,7 @@ pub mod capabilities; pub mod declarative; +pub(crate) mod executables; pub mod marketplace; pub(crate) mod settings; diff --git a/rust/lithe-core/src/plugins/settings.rs b/rust/lithe-core/src/plugins/settings.rs index 25c9506200..da196f9069 100644 --- a/rust/lithe-core/src/plugins/settings.rs +++ b/rust/lithe-core/src/plugins/settings.rs @@ -15,7 +15,7 @@ //! //! Note: the decision is recorded in .agents/notes/implemented/architecture/2026-10-21-plugin-settings-surfaces.md -use super::declarative::{invalid, Validation}; +use super::declarative::{invalid, PluginRejection, Validation}; use regex::Regex; use serde::{Deserialize, Serialize}; use serde_json::Value; @@ -324,6 +324,31 @@ pub(crate) struct SettingLayers<'a> { } impl SettingDeclaration { + /// Unlike display/configuration settings, an explicit invalid executable + /// value must terminate resolution rather than silently choose a default. + pub(crate) fn executable_value(&self, stored: Option<&Value>) -> Validation> { + let value = stored.unwrap_or(&self.default); + let valid = self.accepts(value) + && value.as_str().is_some_and(|path| { + path.is_empty() + || (path.trim() == path + && !path.chars().any(char::is_control) + && (path.starts_with('/') + || (path.len() >= 3 + && path.as_bytes()[0].is_ascii_alphabetic() + && path.as_bytes()[1] == b':' + && matches!(path.as_bytes()[2], b'/' | b'\\')) + || path.starts_with("\\\\"))) + }); + if !valid { + return Err(PluginRejection::at("plugin.build.invalidSelection", format!("settings.{}", self.id), "The configured executable must be an absolute file path satisfying the setting constraints.")); + } + Ok(value + .as_str() + .filter(|path| !path.is_empty()) + .map(str::to_owned)) + } + fn is_version_2_kind(&self) -> bool { matches!( self.kind.as_str(), diff --git a/rust/lithe-core/src/tests/build_systems.rs b/rust/lithe-core/src/tests/build_systems.rs index 1ff564c743..943e5c81f1 100644 --- a/rust/lithe-core/src/tests/build_systems.rs +++ b/rust/lithe-core/src/tests/build_systems.rs @@ -1611,37 +1611,37 @@ fn explicit_build_tool_path_requires_supported_global_file_setting() { ) }; assert_eq!( - invoke(json!({}))["invocation"].get("configuredExecutable"), - None + invoke(json!({}))["invocation"]["executables"][0]["path"], + Value::Null ); assert_eq!( - invoke(json!({"toolPath": ""}))["invocation"].get("configuredExecutable"), - None + invoke(json!({"toolPath": ""}))["invocation"]["executables"][0]["path"], + Value::Null ); - let path = "/opt/custom tools/build-tool"; assert_eq!( - invoke(json!({"toolPath": path}))["invocation"]["configuredExecutable"], - path - ); - assert_eq!( - invoke(json!({"toolPath": "relative"}))["invocation"].get("configuredExecutable"), - None - ); - for platform in ["macos", "linux", "windows"] { - let result = call( - "invocationPlan", - manifest.clone(), - "fixture", - json!({ - "root": ".", "platform": platform, "settings": {"toolPath": "C:\\Tools\\build.exe"} - }), - ); - assert_eq!(result["status"], "ok"); + invoke(json!({"toolPath": "/opt/custom tools/build-tool"}))["invocation"]["executables"][0] + ["path"], + "/opt/custom tools/build-tool" + ); + for value in [ + json!("relative"), + json!(42), + json!(null), + json!([]), + json!(" /bad"), + json!("/bad\npath"), + json!("/".repeat(1025)), + ] { assert_eq!( - result["invocation"]["configuredExecutable"], - "C:\\Tools\\build.exe" + invoke(json!({"toolPath": value}))["status"], + "rejected", + "{value}" ); } + assert_eq!( + invoke(json!({"toolPath": "C:\\Tools\\build.exe"}))["status"], + "ok" + ); for (field, value) in [ ("scope", json!("project")), ("type", json!("directory")), @@ -1652,9 +1652,135 @@ fn explicit_build_tool_path_requires_supported_global_file_setting() { assert_eq!(validate(invalid)["status"], "rejected", "{field}"); } let mut old = manifest.clone(); - old["requires"]["buildSystems"] = json!(1); + old["requires"] + .as_object_mut() + .unwrap() + .remove("executableResolution"); assert_eq!(validate(old)["status"], "rejected"); let mut missing = manifest; - missing["buildSystems"][0]["invocation"]["executableSetting"] = json!("missing"); + missing["buildSystems"][0]["invocation"]["executables"][0]["settingID"] = json!("missing"); assert_eq!(validate(missing)["status"], "rejected"); } + +#[test] +fn executable_candidates_order_and_constraints_are_shared_and_deterministic() { + let base: Value = + serde_json::from_str(contract_file!("fixtures/build-tool-path.plugin.json")).unwrap(); + let invoke = |candidates: Value| { + let mut manifest = base.clone(); + manifest["buildSystems"][0]["invocation"]["executables"] = candidates; + call( + "invocationPlan", + manifest, + "fixture", + json!({"root":".","platform":"macos"}), + ) + }; + let result = invoke(json!([ + {"id":"a","kind":"command","command":"a"}, + {"id":"b","kind":"command","command":"b","priority":10}, + {"kind":"command","command":"c","insertBefore":"b"}, + {"kind":"command","command":"d","insertAfter":"a"} + ])); + assert_eq!(result["status"], "ok", "{result}"); + let commands: Vec<_> = result["invocation"]["executables"] + .as_array() + .unwrap() + .iter() + .map(|item| item["command"].as_str().unwrap()) + .collect(); + // Relative constraints are edges, not adjacency: ready-node ties retain + // array order, so a precedes c; c unlocks the higher-priority b. + assert_eq!(commands, ["a", "c", "b", "d"]); + for candidates in [ + json!([{"id":"a","kind":"command","command":"a"},{"id":"a","kind":"command","command":"b"}]), + json!([{"kind":"command","command":"a","insertBefore":"missing"}]), + json!([{"id":"a","kind":"command","command":"a","insertBefore":"a"}]), + json!([{"id":"a","kind":"command","command":"a","insertBefore":"b"},{"id":"b","kind":"command","command":"b","insertBefore":"a"}]), + json!([{"id":"a","kind":"command","command":"a","priority":2,"insertAfter":"a"}]), + json!([{"id":"a","kind":"command","command":"a","insertBefore":"a","insertAfter":"a"}]), + ] { + assert_eq!( + invoke(candidates.clone())["status"], + "rejected", + "{candidates}" + ); + } + let result = invoke(json!([ + {"kind":"command","command":"a","priority":1}, + {"kind":"command","command":"b","priority":9}, + {"kind":"command","command":"c","priority":9} + ])); + assert_eq!(result["invocation"]["executables"][0]["command"], "b"); + assert_eq!(result["invocation"]["executables"][1]["command"], "c"); +} + +#[test] +fn published_build_v2_paths_adapt_to_candidates_and_preserve_invalid_values() { + let mut manifest: Value = + serde_json::from_str(contract_file!("fixtures/build-tool-path.plugin.json")).unwrap(); + manifest["requires"] + .as_object_mut() + .unwrap() + .remove("executableResolution"); + manifest["buildSystems"][0]["invocation"]["executables"] + .as_array_mut() + .unwrap() + .remove(0); + manifest["requires"]["buildSystems"] = json!(2); + manifest["buildSystems"][0]["invocation"]["executableSetting"] = json!("toolPath"); + let run = |value| { + call( + "invocationPlan", + manifest.clone(), + "fixture", + json!({"root":".","platform":"macos","settings":{"toolPath":value}}), + ) + }; + let result = run(json!("/tools/custom build")); + assert_eq!(result["status"], "ok", "{result}"); + assert_eq!(result["invocation"]["executables"][0]["kind"], "setting"); + assert!(result["invocation"].get("configuredExecutable").is_none()); + assert_eq!(run(json!(false))["status"], "rejected"); + // The existing settings UI keeps its tolerant display behavior. + let displayed = crate::plugins::declarative::resolve_settings_command( + json!({"manifest":manifest,"settings":{"toolPath":false}}), + ) + .unwrap(); + assert_eq!(displayed["status"], "ok", "{displayed}"); + assert_eq!(displayed["settings"][0]["value"], "", "{displayed}"); +} + +#[test] +fn executable_resolution_is_opt_in_and_custom_runtimes_share_the_same_plan() { + let mut manifest: Value = + serde_json::from_str(contract_file!("fixtures/build-tool-path.plugin.json")).unwrap(); + let old_host = validate_command( + json!({"manifest":manifest,"hostCapabilities":{"buildSystems":[1,2],"settings":[1,2]}}), + ) + .unwrap(); + assert_eq!(old_host["error"]["code"], "plugin.api.unsupported"); + manifest["buildSystems"][0]["invocation"]["runtimeDependencies"] = json!([{ + "id":"custom", "executables":[ + {"id":"selected","kind":"setting","settingID":"toolPath"}, + {"kind":"command","command":"custom"} + ] + }]); + let result = call( + "invocationPlan", + manifest.clone(), + "fixture", + json!({"root":".","platform":"macos","settings":{"toolPath":"/custom runtime/tool"}}), + ); + assert_eq!(result["status"], "ok", "{result}"); + assert_eq!( + result["invocation"]["runtimeDependencies"][0]["executables"][0]["path"], + "/custom runtime/tool" + ); + // Anchors never escape into a different candidate collection. + manifest["buildSystems"][0]["invocation"]["executables"][1]["insertBefore"] = + json!("runtime-only"); + manifest["buildSystems"][0]["invocation"]["runtimeDependencies"][0]["executables"][0]["id"] = + json!("runtime-only"); + assert_eq!(validate(manifest)["status"], "rejected"); +} diff --git a/shared/contracts/plugins/v1/README.md b/shared/contracts/plugins/v1/README.md index a7a0c93cde..686b3fdd92 100644 --- a/shared/contracts/plugins/v1/README.md +++ b/shared/contracts/plugins/v1/README.md @@ -1472,21 +1472,77 @@ macOS 动作的可见、可用、勾选和激活中状态由宿主计算,不 仍可取消显示。多个窗口同时请求同一插件模块时只构造一次;禁用或关闭会取消 并清理在途激活,旧的菜单或命令引用不能重新调用已禁用的贡献。 -#### Configured build executable (`buildSystems` 2) - -`invocation.executableSetting` names a declared **global** `file` setting with -`effect: "reload"` or `"nextRun"` (also requires `settings: 2`). The field is part -of install review. Project settings cannot choose an executable. See -[`build-tool-path.plugin.json`](fixtures/build-tool-path.plugin.json). - -`build.invocationPlan` accepts optional `request.settings`, the plugin's stored -global values. Core applies the declared setting validation/default and emits -`invocation.configuredExecutable` only for a nonempty value. Empty/absent values -retain the existing ordered executable candidates. A host advertising -`buildSystems: 2` must use a configured path directly, verify executability and -version, and report a failure instead of falling back to another installation. -The executable's parent directory precedes PATH for its process. All command -sources, tasks/tests and provider `tool.executable` hints must use that same -selection; a provider must not do independent discovery when an explicit path -fails. Passive language import may inspect existence but never execute a probe. -Older hosts advertise only version 1 and reject version 2 plugins. +#### Shared executable candidates (`executableResolution` 1) + +Declare executable sources in `invocation.executables`, in preference order. +Array order is the recommended form; no custom path setting is required for a +plugin that only needs automatic discovery. Existing `projectFile`, `environment`, +`command` and `runtime` sources retain their v1 behavior. The shared +`executableResolution: 1` capability adds `setting` and ordering metadata: + +```json +"executables": [ + { "id": "selected", "kind": "setting", "settingID": "toolPath" }, + { "id": "wrapper", "kind": "projectFile", "path": "mvnw" }, + { "id": "system", "kind": "command", "command": "mvn" } +] +``` + +A `setting` references a declared **global file** setting with `effect: "reload"` +or `"nextRun"` (`settings: 2`). Core receives raw `request.settings`. An absent +value uses the declared default; an explicit empty string emits a setting candidate +with `path: null`, which skips. A nonempty value must satisfy the setting rules, +be absolute, and have no surrounding whitespace or controls. Invalid stored +values reject the invocation instead of invoking the normal settings display +resolver's fallback-to-default behavior. Project overrides never select tools. +The host checks file permissions and versions: a configured failure is terminal, +including a failure to probe, and must not fall back to subsequent candidates or +a Provider's own lookup. Paths with spaces remain single paths. The selected +setting's directory precedes PATH. Provider hints and task/test execution use +this same plan/selection mechanism. + +Optional metadata applies within **one candidate set owned by one plugin**: + +- `id` is a unique stable identifier; anonymous candidates cannot be anchors. +- `priority` is a signed 32-bit integer; higher wins, absent means 0. Ties retain + original array order. +- `insertBefore` or `insertAfter` names an ID in this set. One candidate cannot + combine either with `priority`, or declare both insertion fields. Constraints + mean relative order, not immediate adjacency. +- Normalize the complete set into a directed graph before platform filtering. + Repeatedly select a zero-indegree node by descending priority, then original + index; emit it and remove its edges. Explicit edges take precedence over + priority. Duplicate/invalid IDs, unknown anchors, cycles/self-edges and + conflicting metadata are manifest errors. Filter platforms only after sorting, + so anchors remain valid even if they do not apply to the current platform. + +`plugins::executables` owns the reusable source types and deterministic order; +`ExecutableCandidateResolver` receives file-system, Setting (already validated by +Core), Environment, Runtime and command-discovery capabilities from the host. +Results distinguish `skip`, `resolved` and `terminalFailure`; plugins declare data +and cannot inject host native code. Each operation uses a value snapshot for its +settings/environment and ordered plan. Passive import does not resolve/probe +runtimes or execute project wrappers. A project candidate remains project code +and is only executed through the consumer's existing trust/user-action workflow. + +This PR connects Build Systems and their custom Runtime Dependencies. Own Build +Providers already adapt command/runtime launches through BuildToolResolver and +receive the selected build tool as `tool.executable`; their ServerProcess protocol +is unchanged. Language Servers, Execution Providers, and other ServerProcess +launch forms can later adapt into this same resolver without changing their +manifest structure all at once: preserve package-realpath/executable checks, +workspace trust, auto-start restrictions, runtime ownership and cancellation. +They do **not** advertise support for new candidate declarations until their +adapter is implemented; this capability currently authorizes the Build candidate +positions only. Windows does not advertise it yet. + +Compatibility: Cargo 0.1.1 already shipped as a preview with `buildSystems: 2` +and `invocation.executableSetting`. That field is deprecated and supported only +as a v2 input adapter: prepend an equivalent setting candidate to the normal +list; never emit `configuredExecutable` or use a separate resolution branch. +New plugins use the fifth candidate and `executableResolution: 1` (Build v1 +remains sufficient). Legacy manifests do not need the new capability; hosts +without it reject new-style plugins before decoding unknown fields. Published +0.1.0/0.1.1 archives remain immutable; migration is a new plugin version. + +See [`build-tool-path.plugin.json`](fixtures/build-tool-path.plugin.json). diff --git a/shared/contracts/plugins/v1/fixtures/build-tool-path.plugin.json b/shared/contracts/plugins/v1/fixtures/build-tool-path.plugin.json index 60677df97f..3115aac8a5 100644 --- a/shared/contracts/plugins/v1/fixtures/build-tool-path.plugin.json +++ b/shared/contracts/plugins/v1/fixtures/build-tool-path.plugin.json @@ -5,8 +5,9 @@ "version": "0.1.0", "pluginAPIVersion": 3, "requires": { - "buildSystems": 2, - "settings": 2 + "buildSystems": 1, + "settings": 2, + "executableResolution": 1 }, "vendor": { "id": "org.example", @@ -43,8 +44,12 @@ ] }, "invocation": { - "executableSetting": "toolPath", "executables": [ + { + "id": "selected", + "kind": "setting", + "settingID": "toolPath" + }, { "kind": "command", "command": "fixture-build" diff --git a/shared/contracts/plugins/v1/plugin-manifest.schema.json b/shared/contracts/plugins/v1/plugin-manifest.schema.json index 4b331e1e26..04634debf2 100644 --- a/shared/contracts/plugins/v1/plugin-manifest.schema.json +++ b/shared/contracts/plugins/v1/plugin-manifest.schema.json @@ -23,7 +23,8 @@ "properties": { "buildProviders": { "description": "Required exactly when any buildSystems[].provider is present, including own-process and shared language-server providers. Declares host support for Provider orchestration, independent of declarative buildSystems and serverProcess launch support.", "enum": [1] }, "buildSystems": { "description": "Declarative build detection, models, and command plans; does not imply buildProviders support.", "enum": [1, 2] }, - "executionProviders": { "enum": [1] }, + "executableResolution": { "enum": [1], "description": "Shared executable candidate ordering and strict selection." }, + "executionProviders": { "enum": [1] }, "languageServers": { "enum": [1] }, "languages": { "enum": [1] }, "serverProcess": { "description": "The launch fields of language servers and of build providers that start their own process.", "enum": [1] }, @@ -583,7 +584,7 @@ }, "maxItems": 64 }, - "buildExecutable": { + "executableCandidate": { "oneOf": [ { "type": "object", @@ -618,8 +619,52 @@ "windows" ] } + }, + "id": { + "type": "string", + "minLength": 1, + "maxLength": 64 + }, + "priority": { + "type": "integer", + "minimum": -2147483648, + "maximum": 2147483647 + }, + "insertBefore": { + "type": "string", + "minLength": 1 + }, + "insertAfter": { + "type": "string", + "minLength": 1 } - } + }, + "allOf": [ + { + "not": { + "required": [ + "priority", + "insertBefore" + ] + } + }, + { + "not": { + "required": [ + "priority", + "insertAfter" + ] + } + }, + { + "not": { + "required": [ + "insertBefore", + "insertAfter" + ] + } + } + ] }, { "type": "object", @@ -652,8 +697,52 @@ "windows" ] } + }, + "id": { + "type": "string", + "minLength": 1, + "maxLength": 64 + }, + "priority": { + "type": "integer", + "minimum": -2147483648, + "maximum": 2147483647 + }, + "insertBefore": { + "type": "string", + "minLength": 1 + }, + "insertAfter": { + "type": "string", + "minLength": 1 } - } + }, + "allOf": [ + { + "not": { + "required": [ + "priority", + "insertBefore" + ] + } + }, + { + "not": { + "required": [ + "priority", + "insertAfter" + ] + } + }, + { + "not": { + "required": [ + "insertBefore", + "insertAfter" + ] + } + } + ] }, { "type": "object", @@ -679,8 +768,52 @@ "windows" ] } + }, + "id": { + "type": "string", + "minLength": 1, + "maxLength": 64 + }, + "priority": { + "type": "integer", + "minimum": -2147483648, + "maximum": 2147483647 + }, + "insertBefore": { + "type": "string", + "minLength": 1 + }, + "insertAfter": { + "type": "string", + "minLength": 1 } - } + }, + "allOf": [ + { + "not": { + "required": [ + "priority", + "insertBefore" + ] + } + }, + { + "not": { + "required": [ + "priority", + "insertAfter" + ] + } + }, + { + "not": { + "required": [ + "insertBefore", + "insertAfter" + ] + } + } + ] }, { "type": "object", @@ -707,11 +840,127 @@ "windows" ] } + }, + "id": { + "type": "string", + "minLength": 1, + "maxLength": 64 + }, + "priority": { + "type": "integer", + "minimum": -2147483648, + "maximum": 2147483647 + }, + "insertBefore": { + "type": "string", + "minLength": 1 + }, + "insertAfter": { + "type": "string", + "minLength": 1 } - } + }, + "allOf": [ + { + "not": { + "required": [ + "priority", + "insertBefore" + ] + } + }, + { + "not": { + "required": [ + "priority", + "insertAfter" + ] + } + }, + { + "not": { + "required": [ + "insertBefore", + "insertAfter" + ] + } + } + ] + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "kind", + "settingID" + ], + "properties": { + "kind": { + "const": "setting" + }, + "settingID": { + "type": "string", + "minLength": 1 + }, + "platforms": { + "type": "array", + "items": { + "enum": [ + "macos", + "linux", + "windows" + ] + } + }, + "id": { + "type": "string", + "minLength": 1, + "maxLength": 64 + }, + "priority": { + "type": "integer", + "minimum": -2147483648, + "maximum": 2147483647 + }, + "insertBefore": { + "type": "string", + "minLength": 1 + }, + "insertAfter": { + "type": "string", + "minLength": 1 + } + }, + "allOf": [ + { + "not": { + "required": [ + "priority", + "insertBefore" + ] + } + }, + { + "not": { + "required": [ + "priority", + "insertAfter" + ] + } + }, + { + "not": { + "required": [ + "insertBefore", + "insertAfter" + ] + } + } + ] } ] }, + "buildExecutable": {"$ref": "#/$defs/executableCandidate"}, "buildVersionProbe": { "type": "object", "additionalProperties": false, @@ -1096,6 +1345,7 @@ ], "properties": { "executableSetting": { + "deprecated": true, "type": "string", "description": "buildSystems 2: global file setting with effect reload or nextRun; empty uses discovery, nonempty must be used without fallback.", "pattern": "^[a-z][a-zA-Z0-9]*$", diff --git a/shared/contracts/rust-core-api.md b/shared/contracts/rust-core-api.md index 4384ecf25a..6cea083e63 100644 --- a/shared/contracts/rust-core-api.md +++ b/shared/contracts/rust-core-api.md @@ -3089,6 +3089,14 @@ selections the declaration does not allow are `plugin.build.invalidSelection`, output that does not fit its decoder is `plugin.build.invalidOutput`, and a malformed payload is an `invalid_request` failure. +Executable candidates are normalized by the shared plugin executable-resolution +mechanism before platform filtering. A `setting` candidate emits +`{kind: "setting", settingID, path: absolutePath | null}` in the same `executables` +list; null skips, invalid stored values reject the plan, and native validation +failure is terminal. There is no separate `configuredExecutable` result. +See the plugin contract's **Shared executable candidates** section for ordering, +capability negotiation and the compatibility adapter for published v2 previews. + Host-managed runtime probes use `java -version` (including Java 8), `node --version`, and `go version`. Hosts execute the returned arguments and pass combined stdout and stderr as `build.checkToolVersion.request.output`: diff --git a/shared/platform-feature-matrix/features/build-system-plugins.json b/shared/platform-feature-matrix/features/build-system-plugins.json index 2145df1621..310b844704 100644 --- a/shared/platform-feature-matrix/features/build-system-plugins.json +++ b/shared/platform-feature-matrix/features/build-system-plugins.json @@ -2,7 +2,7 @@ "id": "build-system-plugins", "area": "扩展", "group": "插件与主题", - "capability": "构建系统插件(API 3 buildSystems):插件用 JSON 声明构建工具的识别、可执行文件、选项、任务、运行入口、测试和输出格式,或由插件自带、与语言服务器同类的 Provider 进程回答模型和依赖,Rust Core 统一校验、生成命令行或 Provider 请求并解码结果,宿主为每个构建系统打开一个按声明(icon、presentation、category)布局的工具窗口;支持全局可执行文件路径,留空自动发现,指定失效报错", + "capability": "构建系统插件(API 3 buildSystems):插件用 JSON 声明构建工具的识别、可执行文件、选项、任务、运行入口、测试和输出格式,或由插件自带、与语言服务器同类的 Provider 进程回答模型和依赖,Rust Core 统一校验、生成命令行或 Provider 请求并解码结果,宿主为每个构建系统打开一个按声明(icon、presentation、category)布局的工具窗口;通过共享 executableResolution 候选解析支持可选设置路径、优先级与相对排序,空值自动发现、显式失败不回退", "macos": { "evidence": [ "rust/lithe-core/src/build", @@ -24,7 +24,9 @@ "macos/Sources/Lithe/Platform/MacOS/Build/MacBuildProviderSessions.swift", "macos/Sources/Lithe/Platform/MacOS/Plugins/MacPluginLanguageServerLaunchResolver.swift", "macos/Tests/LitheTests/PluginMarketplaceServiceTests.swift", - "shared/contracts/plugins/v1/fixtures/build-tool-path.plugin.json" + "shared/contracts/plugins/v1/fixtures/build-tool-path.plugin.json", + "rust/lithe-core/src/plugins/executables.rs", + "macos/Sources/LitheCoreContracts/Execution/ExecutableResolution.swift" ], "implementationStatus": "partial", "verificationStatus": "pending" @@ -39,5 +41,5 @@ "verificationStatus": "not-applicable" }, "owner": "Extensions", - "verification": "macOS 已接入 static、command、hostIntegration、provider 四种模型来源:宿主向 Core 声明 buildSystems 与 buildProviders 能力,插件市场因此列出兼容的 API 3 声明式和 Provider 版本;Provider 进程按插件、构建系统和工作区各自独立,经各自 stdio 用 JSON-RPC(LSP 基础协议)与宿主通信,initialize 协商 capabilities.experimental.litheBuild 后宿主才经 lsp.buildRequest 发送 lithe/build/model、lithe/build/dependencies,回复交给 Core 解码;共享写法只复用同一插件的语言服务器会话;进程只在用户加载模型或依赖时启动,切换工作区、关闭项目窗口、停止执行模块、停用或更新插件、退出应用时停止;ExecutionFeatureGraph.stop 经 BuildSystemService.stop 同时回收已就绪和初始化中的 Provider,停止后的初始化完成也不得重新登记会话;状态写入插件状态目录;每个已启用的构建系统插件在打开工作区后各有一个右侧工具窗口(标题为 displayName、图标为 icon),不依赖识别结果,工作区没有对应工程时窗口内显示未检测到该构建系统,工具栏放运行、参数任务、刷新和 presentation=toolbar 的开关,树顶部是 presentation=tree 的勾选选项,工程下按 category(缺省按 group)分级列出任务,再列测试、目标和依赖;内置 Maven 窗口与共享 Build 窗口已删除,Build Output 显示输出、诊断与测试结果。窗口恢复先激活所属插件模块,激活中的命令面板项禁用;参数任务遵守 workspace/project/target 作用范围与目标标签,模型或工作区变化后清除旧选择。隔离回归覆盖这些边界、窗口布局恢复及包内图标读取前后文件清单与字节不变;多实例的根目录选择器保留每个实例的模型候选和生效值,编辑多选时保留兄弟实例独有的已选值;显式清空按实例根持久化为空覆盖,检测、同步指纹、任务计划和语言服务器导入使用同一覆盖,兄弟编辑或重开不会恢复非空默认值,非空编辑清当前实例标记而共享编辑/重置清该选项全部标记;真实 Core、生产存储与服务回归核对最终 argv 和导入值;列表单选与多选支持 allowCustom 原生输入和移除已选自定义值,文本/文件/目录清空提交显式空字符串,只有重置删除覆盖。插件选项在项目打开、选项修改和模型加载完成后通过 Core build.languageImport 归一化为 mavenContext/javaGradle,与构建计划使用同一生效值,并在 Java 启动前等待同一工作区代次的最新配置;运行时准备后再等一次,覆盖等待期间失效。唯一发布回调优先 Maven 原地热更新,被拒绝时串行恢复重启;停用最后一个 Maven 插件时,仅清除曾带 Maven 输入的同一会话,纯 Gradle 首次启动保持 nil。Gradle 在下次启动生效,取消/重置拒绝旧检测与恢复任务,被动工具路径发现不执行 Wrapper/版本探测;没有对应插件导入输入时兼容原 Maven 设置。模型 run 入口与 lithe/build/execute 尚未接入,Provider 无操作系统级沙盒;Windows 宿主尚未调用 build.* 命令。自动化:cargo test -p lithe-core --lib build_systems、cargo test -p lithe-core --lib lsp、scripts/verify-shared-contracts.sh、./scripts/test-macos.sh --filter 'BuildSystemToolWindowTests|RustBuildSystemOperationsTests|BuildSystemServiceTests|PluginMarketplaceServiceTests'。手动验证:安装 fixtures 中 cargo-build、go-build 形态的插件包,确认每个构建系统各出现一个工具窗口,列出工程、分级任务、选项和依赖,停用插件后窗口消失;执行任务与测试的 argv 与 build-plans.json 一致,停止与输出上限生效;JUnit 报告与 lineMatcher 诊断可跳转到源码;命令模型和项目内 Wrapper 只在用户点击加载或运行后启动;禁用插件后实例消失;Windows 接入后另需验证未信任工作区不启动任何模型命令或 Wrapper;gradle-provider 形态的自有 Provider 只在用户操作或工作区信任后启动、停用插件时停止,mix-provider 形态复用语言服务器会话而不启动第二个进程;运行前后 app bundle 文件清单不变(scripts/verify-runtime-bundle-immutability.sh)。;构建路径设置使用 buildSystems 2 + settings 2:MacBuildToolResolverTests 验证带空格绝对路径、权限与版本失败不回退,BuildSystemServiceTests 验证 Provider 失败不独立发现,RustBuildSystemOperationsTests 验证全局值接入。Cargo 独立仓库以显式本地 Core bridge 验证自选路径用于 metadata 和全部构建/测试/运行/清理;发布前需把独立仓库 sdk.lock.json 的宿主 pin 更新到包含该能力的已发布提交。" + "verification": "macOS 已接入 static、command、hostIntegration、provider 四种模型来源:宿主向 Core 声明 buildSystems 与 buildProviders 能力,插件市场因此列出兼容的 API 3 声明式和 Provider 版本;Provider 进程按插件、构建系统和工作区各自独立,经各自 stdio 用 JSON-RPC(LSP 基础协议)与宿主通信,initialize 协商 capabilities.experimental.litheBuild 后宿主才经 lsp.buildRequest 发送 lithe/build/model、lithe/build/dependencies,回复交给 Core 解码;共享写法只复用同一插件的语言服务器会话;进程只在用户加载模型或依赖时启动,切换工作区、关闭项目窗口、停止执行模块、停用或更新插件、退出应用时停止;ExecutionFeatureGraph.stop 经 BuildSystemService.stop 同时回收已就绪和初始化中的 Provider,停止后的初始化完成也不得重新登记会话;状态写入插件状态目录;每个已启用的构建系统插件在打开工作区后各有一个右侧工具窗口(标题为 displayName、图标为 icon),不依赖识别结果,工作区没有对应工程时窗口内显示未检测到该构建系统,工具栏放运行、参数任务、刷新和 presentation=toolbar 的开关,树顶部是 presentation=tree 的勾选选项,工程下按 category(缺省按 group)分级列出任务,再列测试、目标和依赖;内置 Maven 窗口与共享 Build 窗口已删除,Build Output 显示输出、诊断与测试结果。窗口恢复先激活所属插件模块,激活中的命令面板项禁用;参数任务遵守 workspace/project/target 作用范围与目标标签,模型或工作区变化后清除旧选择。隔离回归覆盖这些边界、窗口布局恢复及包内图标读取前后文件清单与字节不变;多实例的根目录选择器保留每个实例的模型候选和生效值,编辑多选时保留兄弟实例独有的已选值;显式清空按实例根持久化为空覆盖,检测、同步指纹、任务计划和语言服务器导入使用同一覆盖,兄弟编辑或重开不会恢复非空默认值,非空编辑清当前实例标记而共享编辑/重置清该选项全部标记;真实 Core、生产存储与服务回归核对最终 argv 和导入值;列表单选与多选支持 allowCustom 原生输入和移除已选自定义值,文本/文件/目录清空提交显式空字符串,只有重置删除覆盖。插件选项在项目打开、选项修改和模型加载完成后通过 Core build.languageImport 归一化为 mavenContext/javaGradle,与构建计划使用同一生效值,并在 Java 启动前等待同一工作区代次的最新配置;运行时准备后再等一次,覆盖等待期间失效。唯一发布回调优先 Maven 原地热更新,被拒绝时串行恢复重启;停用最后一个 Maven 插件时,仅清除曾带 Maven 输入的同一会话,纯 Gradle 首次启动保持 nil。Gradle 在下次启动生效,取消/重置拒绝旧检测与恢复任务,被动工具路径发现不执行 Wrapper/版本探测;没有对应插件导入输入时兼容原 Maven 设置。模型 run 入口与 lithe/build/execute 尚未接入,Provider 无操作系统级沙盒;Windows 宿主尚未调用 build.* 命令。自动化:cargo test -p lithe-core --lib build_systems、cargo test -p lithe-core --lib lsp、scripts/verify-shared-contracts.sh、./scripts/test-macos.sh --filter 'BuildSystemToolWindowTests|RustBuildSystemOperationsTests|BuildSystemServiceTests|PluginMarketplaceServiceTests'。手动验证:安装 fixtures 中 cargo-build、go-build 形态的插件包,确认每个构建系统各出现一个工具窗口,列出工程、分级任务、选项和依赖,停用插件后窗口消失;执行任务与测试的 argv 与 build-plans.json 一致,停止与输出上限生效;JUnit 报告与 lineMatcher 诊断可跳转到源码;命令模型和项目内 Wrapper 只在用户点击加载或运行后启动;禁用插件后实例消失;Windows 接入后另需验证未信任工作区不启动任何模型命令或 Wrapper;gradle-provider 形态的自有 Provider 只在用户操作或工作区信任后启动、停用插件时停止,mix-provider 形态复用语言服务器会话而不启动第二个进程;运行前后 app bundle 文件清单不变(scripts/verify-runtime-bundle-immutability.sh)。;新路径选择使用 executableResolution 1 + settings 2,已发布 buildSystems 2 旧字段只作统一候选输入适配:MacBuildToolResolverTests 验证带空格绝对路径、权限与版本失败不回退,BuildSystemServiceTests 验证 Provider 失败不独立发现,RustBuildSystemOperationsTests 验证全局值接入。Cargo 独立仓库以显式本地 Core bridge 验证自选路径用于 metadata 和全部构建/测试/运行/清理;发布前需把独立仓库 sdk.lock.json 的宿主 pin 更新到包含该能力的已发布提交。;回归增加非法存储值不回默认、数组/priority/插入顺序与拒绝循环、宿主注入发现、空设置跳过和被动选择不探测;Language Server/Execution Provider 新清单语法尚未开放,Windows 不声明 executableResolution。" } diff --git a/shared/platform-feature-matrix/features/cargo-build-plugin.json b/shared/platform-feature-matrix/features/cargo-build-plugin.json index 1965ac0a00..02edfaaae3 100644 --- a/shared/platform-feature-matrix/features/cargo-build-plugin.json +++ b/shared/platform-feature-matrix/features/cargo-build-plugin.json @@ -2,7 +2,7 @@ "id": "cargo-build-plugin", "area": "扩展", "group": "插件与主题", - "capability": "Cargo 社区构建插件:由 Cargo metadata 提供 workspace/package/target/features,使用原生构建窗口执行编译、检查、测试、清理和 binary/example 运行,支持 Release、Features、Offline;用户安装 Cargo 与 Node,插件独立打包且运行时只读;支持全局可执行文件路径,留空自动发现,指定失效报错", + "capability": "Cargo 社区构建插件:由 Cargo metadata 提供 workspace/package/target/features,使用原生构建窗口执行编译、检查、测试、清理和 binary/example 运行,支持 Release、Features、Offline;用户安装 Cargo 与 Node,插件独立打包且运行时只读;通过共享 executableResolution 候选解析支持可选设置路径、优先级与相对排序,空值自动发现、显式失败不回退", "macos": { "implementationStatus": "implemented", "verificationStatus": "pending", @@ -10,7 +10,9 @@ "Plugins/mac/README.md", "docs/ci-builds.md", ".agents/notes/implemented/feature/2026-10-22-cargo-build-plugin.md", - "shared/contracts/plugins/v1/fixtures/build-tool-path.plugin.json" + "shared/contracts/plugins/v1/fixtures/build-tool-path.plugin.json", + "rust/lithe-core/src/plugins/executables.rs", + "macos/Sources/LitheCoreContracts/Execution/ExecutableResolution.swift" ] }, "windows": { @@ -21,5 +23,5 @@ ] }, "owner": "Plugin Platform", - "verification": "独立源码与预发布包由 https://github.com/Lithe-IDEA/lithe-plugin-cargo 维护;插件 CI 按 sdk.lock.json 的宿主提交构建公开 JSON API 测试桥接,运行 3 项 Cargo 专属 Core 兼容性回归(清单/安装审查/能力拒绝、识别/模型解码、任务与测试选择),并以 LITHE_CARGO_INTEGRATION=1 执行真实双包 workspace:模型由 Core 规划请求并解码,编译/检查/测试/同名 binary 与 example/单测试/清理由 Core 生成参数,验证 Release/Features/Offline、编译失败及诊断解码、后端退出和包字节不变;SDK 固定源码和哈希、打包校验及逐测试 HTML/JUnit 由插件仓库 CI 持有。固定宿主基线不代表已验证未来 preview。主仓库只保留通用插件契约回归;scripts/verify-runtime-bundle-immutability.sh。原生验收待完成:macOS 从磁盘安装预发布 ZIP、确认 Cargo/Node、重启并启用;打开插件仓库 fixture workspace,检查 Cargo 原生窗口、模型与选项,执行构建/检查/测试/运行,制造错误并跳转源码;停止运行、关闭项目与停用插件后确认无后端和 Cargo 子进程。基础版不提供依赖树、调试或逐用例图形报告;Windows 尚无 API 3 构建宿主。;构建路径设置使用 buildSystems 2 + settings 2:MacBuildToolResolverTests 验证带空格绝对路径、权限与版本失败不回退,BuildSystemServiceTests 验证 Provider 失败不独立发现,RustBuildSystemOperationsTests 验证全局值接入。Cargo 独立仓库以显式本地 Core bridge 验证自选路径用于 metadata 和全部构建/测试/运行/清理;发布前需把独立仓库 sdk.lock.json 的宿主 pin 更新到包含该能力的已发布提交。" + "verification": "独立源码与预发布包由 https://github.com/Lithe-IDEA/lithe-plugin-cargo 维护;插件 CI 按 sdk.lock.json 的宿主提交构建公开 JSON API 测试桥接,运行 3 项 Cargo 专属 Core 兼容性回归(清单/安装审查/能力拒绝、识别/模型解码、任务与测试选择),并以 LITHE_CARGO_INTEGRATION=1 执行真实双包 workspace:模型由 Core 规划请求并解码,编译/检查/测试/同名 binary 与 example/单测试/清理由 Core 生成参数,验证 Release/Features/Offline、编译失败及诊断解码、后端退出和包字节不变;SDK 固定源码和哈希、打包校验及逐测试 HTML/JUnit 由插件仓库 CI 持有。固定宿主基线不代表已验证未来 preview。主仓库只保留通用插件契约回归;scripts/verify-runtime-bundle-immutability.sh。原生验收待完成:macOS 从磁盘安装预发布 ZIP、确认 Cargo/Node、重启并启用;打开插件仓库 fixture workspace,检查 Cargo 原生窗口、模型与选项,执行构建/检查/测试/运行,制造错误并跳转源码;停止运行、关闭项目与停用插件后确认无后端和 Cargo 子进程。基础版不提供依赖树、调试或逐用例图形报告;Windows 尚无 API 3 构建宿主。;新路径选择使用 executableResolution 1 + settings 2,已发布 buildSystems 2 旧字段只作统一候选输入适配:MacBuildToolResolverTests 验证带空格绝对路径、权限与版本失败不回退,BuildSystemServiceTests 验证 Provider 失败不独立发现,RustBuildSystemOperationsTests 验证全局值接入。Cargo 独立仓库以显式本地 Core bridge 验证自选路径用于 metadata 和全部构建/测试/运行/清理;发布前需把独立仓库 sdk.lock.json 的宿主 pin 更新到包含该能力的已发布提交。;回归增加非法存储值不回默认、数组/priority/插入顺序与拒绝循环、宿主注入发现、空设置跳过和被动选择不探测;Language Server/Execution Provider 新清单语法尚未开放,Windows 不声明 executableResolution。" } From 160defa0fcb5be651fe1677db98b5808f43a843e Mon Sep 17 00:00:00 2001 From: Mucheen <145200703+Mucheen@users.noreply.github.com> Date: Thu, 22 Oct 2026 23:49:56 +0800 Subject: [PATCH 5/5] fix(macos): preserve executable selections across runtime failures Block Provider discovery after prerequisite runtime failure when tool or runtime settings are explicit. Probe each runtime with the same candidate environment used for execution. Add real Core/resolver/service regressions and native layout comparisons. --- ...2026-10-17-build-system-plugin-contract.md | 16 +- .../after-detail-700-dark.png | Bin 0 -> 92859 bytes .../after-detail-700-light.png | Bin 0 -> 90853 bytes .../after-path-480-dark.png | Bin 0 -> 37123 bytes .../after-path-480-light.png | Bin 0 -> 37533 bytes .../before-detail-700-dark.png | Bin 0 -> 99547 bytes .../before-detail-700-light.png | Bin 0 -> 96324 bytes .../before-path-480-dark.png | Bin 0 -> 27390 bytes .../before-path-480-light.png | Bin 0 -> 27334 bytes docs/plugin-executable-layout-visual-check.md | 48 +++++ .../MacOS/Build/MacBuildToolResolver.swift | 15 +- .../Execution/BuildSystemContracts.swift | 10 + .../Services/BuildSystemService.swift | 4 +- .../BuildToolProviderResolutionTests.swift | 174 ++++++++++++++++++ .../MacBuildToolResolverTests.swift | 33 ++++ shared/contracts/plugins/v1/README.md | 11 +- .../features/build-system-plugins.json | 6 +- 17 files changed, 306 insertions(+), 11 deletions(-) create mode 100644 docs/assets/plugin-executable-layout/after-detail-700-dark.png create mode 100644 docs/assets/plugin-executable-layout/after-detail-700-light.png create mode 100644 docs/assets/plugin-executable-layout/after-path-480-dark.png create mode 100644 docs/assets/plugin-executable-layout/after-path-480-light.png create mode 100644 docs/assets/plugin-executable-layout/before-detail-700-dark.png create mode 100644 docs/assets/plugin-executable-layout/before-detail-700-light.png create mode 100644 docs/assets/plugin-executable-layout/before-path-480-dark.png create mode 100644 docs/assets/plugin-executable-layout/before-path-480-light.png create mode 100644 docs/plugin-executable-layout-visual-check.md create mode 100644 macos/Tests/LitheTests/BuildToolProviderResolutionTests.swift diff --git a/.agents/notes/implemented/architecture/2026-10-17-build-system-plugin-contract.md b/.agents/notes/implemented/architecture/2026-10-17-build-system-plugin-contract.md index 0d270dd69d..d46bac82bb 100644 --- a/.agents/notes/implemented/architecture/2026-10-17-build-system-plugin-contract.md +++ b/.agents/notes/implemented/architecture/2026-10-17-build-system-plugin-contract.md @@ -375,7 +375,21 @@ macOS 接入规则(2026-10-18): 共享类型与拓扑排序位于 `plugins::executables`,macOS 由 `ExecutableCandidateResolver` 注入文件系统、环境、Runtime 和工具发现能力, 区分跳过、解析成功和终止失败。Provider 的可选 tool 提示继续复用宿主解析结果; -无显式选择的自动发现失败仍可让 Provider 自行查找,显式失败则停止本次模型加载。 +无显式选择的自动发现失败仍可让 Provider 自行查找,显式失败则停止本次模型或依赖加载。 +这个限制也覆盖前置 Runtime 先失败的情况:Provider 回退前检查整个调用计划里的 +工具和 Runtime 是否有非空 setting,不能仅依赖失败候选的 terminal 标志。 +例如用户选了工具 A,先解析的 Runtime 不可用时,应报告 Runtime 错误;不能丢掉 +A,发出不带 tool 的请求。空 setting 仍允许自动发现失败后交给 Provider。 +只在解析失败时检查这项约束,前面候选成功后不会被后面未使用的 setting 阻止。 +Runtime 每个候选先构造自己的环境,把所选目录加入 PATH,再以同一环境探测和 +执行;失败候选的 PATH 不传给下一个候选。否则同目录 helper 会在探测时缺失, +合法的 Runtime 就会被误判为版本不足。 设置值非法时 Core 直接拒绝计划,普通设置的容错显示规则不变。 自定义 Runtime 候选复用同一机制;其余进程模块的分步迁移边界见 [插件设置面](2026-10-21-plugin-settings-surfaces.md)。 + +`BuildToolProviderResolutionTests` 使用真实 Core 计划、MacBuildToolResolver 和 +BuildSystemService 验证上述组合:前置 Runtime 缺失或版本不足时,工具或后置 +Runtime 的显式选择均阻止模型和依赖 Provider 请求;全部设置为空时仍发送无 tool 的请求。 +`MacBuildToolResolverTests.customRuntimeProbeAndExecutionUseTheSameSiblingHelper` +用临时可执行脚本验证带空格目录里的 Runtime 在探测和执行时都能找到同目录 helper。 diff --git a/docs/assets/plugin-executable-layout/after-detail-700-dark.png b/docs/assets/plugin-executable-layout/after-detail-700-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..5b335a64a060f4ed9492f3abb98c2c15b39810b8 GIT binary patch literal 92859 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 bWpGmQymNTM!k6XE)u)WkpGg1HDd>Ly8tl#1 literal 0 HcmV?d00001 diff --git a/docs/assets/plugin-executable-layout/after-detail-700-light.png b/docs/assets/plugin-executable-layout/after-detail-700-light.png new file mode 100644 index 0000000000000000000000000000000000000000..edd2b8caabba90470acf945dd00ff8405cbe87df GIT binary patch literal 90853 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

U+o0y^Wl1VN)i+p^NtKqY9I@jfamU}&9| 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

e_ks9H+S5%##z+v>uYMOySn?;< zW=V7?=7Aot}-1CUB*DkKr{Rjt@Bwea~DYI;zz!yq#;Yw^f0_chs=U@29MR1PYliG>UGtdVKe33ZYy6 zfKGh#WKIFW*HNz|?rS@NMFvUFmJ|6Sf#SC#>)3^6SUmtk-x6~}YElr{evS&^&$2={ zW~zhV2V)+kg8=r{Re+^-R2QIC(|1`2OgkmXEBIr`XK~CKc1_f%Z0ukdvA!VXy5j&} z@$HdN)vw3Z3Hvdc`S(5s?-ltUD%D=|*?0*Q1t4_8Xb}4SC4EFy?`fTWtJfsz^Gq>> zq$|zBI0I-+xKMTOwr~2_XRNNAonVl0qfKLvdCd>S1mua+Hy-v*bnrB3e0_R9Ejj8w zL(lzV>J|Xxf1jmq{?#J^Ir zap8ktEa+8F8dTk;C*78}G|e0@F6)YXROjU&;n%wMqlz03s6NhJ)yF8G_dmsb!RsP! z?Z4L10MG*daw~nTb|#G;(3+sE{viGq)6q^kPm{3^aa5#yRy5{MY`lJY?q^n2mD`dD zz{5UaA!A(a9wPq%{;MGuP!ZiHfq3KU(qaDpLHU8yjYp3d3!;@T0ct+(&6{hxFO5#w zop7uA$?va^JP7mAN2!&uzC6kQLbZ7}&Y3%<`oEzDz6pkj-0Q8LaK+?h#v8k!?lS+e zS=;jk|0B4+A`?2nK;YtuTkP43d(OoF9+BhPKxL=O>EV9>`G2FT`Mc4ZD>e67b}L-} zc87kuS_W!T5gAADzy0aA+xSd(Bg_|`nn?iD@I&qPwf}qQ->wea<`WeSA%yO8mApRB z_<#5&^;^N3oKmCZX-Wa&hv8fey6;=K6*c_-N7jFQJot%VjDUvK3lg9M@|~vNw+b|; zTyfh=uJpL1qA-MJ4iXI3wwAnKdEZvwL`+;_Oy_nSek6#gC${IB4Hy#z9EVotP0sJAd| zPdB%;dW>1Er7MH=`qC9dfLO^6t8fJn4*et>`uyK_4xqa23`2pmbU|u3qar_WDl>OH z|35vd$8M?Wl0x(LKitQ^muKH@8p;2Q13Zn1sr-uz;O|#M_5TKWSUp(U?-sQ8oe%Cm za!$@|B$dz7PWu+|KdTud3gk2h9#s(9o00w3+WlddA9S5$o!?C!{jX|J|H-huI`f{g z-Kx8Omh-RR>j6Qa!1$TVxj!o0|Es0`zPbb)b{H!t6U*Nl{J$gqamB0&=&S!f1{kN0 z*0akgeD!A^KXigQZQl`{oQTVJRaJ8|^yQhayivYensqtz%}XYx<9CnWz5AB=GV?38 zm#1^G)-eU^T==`2gp-)bkRjdK?=L3ECd4VEGb+d{E~7|z$VLnh6BvU_*63? z3=9}r?e>}f{Qd$6m;dpPKQ3%)Uc3N>vIido?%eyI|C>MC+{uYyVEwllzi5^`epc2c z(0?ZxH!xBvk+U)-lzq5FOZ}u!lZ>X3te@0@hS-#m+yDElFH~C(T>Jr^{@F1QtF2_5 zpMKO=MB0Q4=wtr7ymqDXqWRg;J2e6DM)q8ewL)~V%>()Pn=_f;@v3~1(^h;`^!9GEaogiTo8Pw3A0pZP z)WN&Yz8AzYVBYhqv2<^T?p$KPd^!VC`nOv{Bb$GOmz;J^7EUkIYq>aHG@faH?SH-) z7&JtLZ~VN8w(Y+?<%@m6`OHZz3a9yaPyUOzRG-xxVfGEfciM6M+sFrUFY=A29f^rP z{BK)d(uCZk_4cCgr}>K`;7G4I(QH^Y4haP z!Qg|;l$DA>V~F-r9Xb6uYU*o6xoq$u`{5R~kWC z-UH<75xHJvlvATLn)Z>ILgh`&J;WRMWhiA3t|&sNhGXofJNte*xk7OMDD1Xq5p48d z*XaR6HO9wQesyk2=T(DL?{!@x_t!H63VPrGBcFMJ!8t$N{gdVaVoGa0p7WauOAin< zQoC1&DJk0%4!vaR(#tBZU+E4MlxT^*M4S2`1;t9YKF8LIO40-ElXI}CRU=MWUgR`T zp03vU*rg^MZN2d}{P3 zQAjo4#$FA;q85x>E78Mx;GO5&Q(UyP6}PSMD(}e1;qa3}xeCO(`mLpkKwN1DFA+Zx z;xVSW!-DqfPrzKWEMx>rywL;DR%KM%x~YQgBLCUYl1MXfUO}H{toV6q=H2kl_Z`4pM9cwXzQE zKNKWn>Pdj;C@x>_{v09t!Dl2WWqqbm**qu*g^!fQq_QbbfAd0bAULpwcAuCAcko3i zKFH@NueILl+^e|Mlr!c|rCvWK!p>kL_DL0UURd=(Ii)pK5i#gK4p;G-xykk3v8c-( z=RLiQR*FPUp=Nlg^R|Jq3|SeJb=>^ent11a0=P{+s-UFG0r`x&G0>+#h}j%j^PI1w zK+LxXI0oynm3n@)lN&h=f~zEU>f;@lIUQqk(xdMNPTjGv$p|^asE{irgRMZV=mwl@ zd3xY%*!iG4{>z`jjKeyRAAVwa&rt|nJElDAM3}gC7x4X^kQO;EhzM;Wmyyvy$;?o8vH}eKNvTw5~G{{YDqFhW1ZzJc| z!+18QypZ#@XLzZLLSZ?T!-2N=Z}yF@M&{?HBW=^c;#5jv2M7J2Q~l7aJ*r41W$_3C z?dB=Jn%Hp~cKzHpEQe=}EC`=;oc~@nTBSjEg;oNggXAZ_SPqcb#t!Sf_N1S*N6kNb#MB2}hR+`j z0Ow5I$Ov4>zqr*n*4Z$+{;YU`=Dr~Cm`~WtnouyA3JbQG$yP()5O@g6Oq`0B(3obPvsBV7tev5C9 zzl+4x6hAmT=qlO|XG*A#P*oTXc~^(vP&WSMa!7OHp#gpC4Zo1WMdYcLX&;5f4^f@_ z(Lfr)7$Ip(E3g{Z({5+^3u5MPD8HFxo}H6mQnt~EGxz;8vpvNhln`}e^VP6zX=(Qr zksKAuigsJmQO_FM1pCq$Va?YQ!^Dw$7Im3uVp%yUO`D7E{e>Kq_fwI%sECok##%3< zgWiVm`duPalA7jUQb02tDk`6uD`4J7Sr((vfkwT`B0U5>5QxGpyNU zm|&@m{W)1;!&>fBeZ!m$cgRx8aN;4qsft1PeTmty`^9AgZ|ze^AX-ajygt2p3pBqX zl->ioHWoW<;5^f1REifzag>8BYePNzpmKx?G+9WYJ<8$8m_Le8#QVf0fzAqafW9#} zd}BKDg={zHHgWsefrbRTFSFE7L%$!3Uvg9rd>{uAUVL_4>y?#1zcR&}D?;0-_F8$3 z%jV@-ZCtN9jWr6~#NvzL+F$AVY9TOjXc;p|-<)v%1|P+Gr}chEo|5uP>2RqUeWw~7 z)JqLM#G^?LqNd!f;V#!wiLq_w@%s_|wvOhHKQ*CA9)ueUaW%ICn!KDB<_3CQEt+BL z5tN^F{@l$`6VKk!BcK2oiJ&xUc?MlaWDM;Q(K~P-N_LjVzf;L2p7T<5ta9vOq4l~( z6Sp^_i2RquTG0Xt1`U!CD?4NXj%>zFYzgzYWr9(UMU?fy?h{hc(OaXB?{;!b1ulcw zHF0TR|EnoJDMdoBjY$}gIdX-uKG$G1Q&+eZT{&#R4_@c5pXE$<%syX@t?~vAT=QQ@ z7pxpPbuFS=3a;ph6o>OgUOOw3hSW`M;DsnsmigPTA{sm%# zUmlmA31evo53U(e!Mrzjplgf+7J(MM==2NTewYnRxgO0qq;^n8L;OAFBX7fS{tr!z zoLZa)&BLB;Ljk*%*5rs?J|njQm|3i2&+G47o+CjhG7sWv5L02%jAFpK^FQx@{{b2q ziy!oaE9s}YLcyC_D5s4k3k940_L8NN(jA3?P;OVl#RzXd%X?4q%E)TUsZAS^C8sAe z0(qbq>YenP9OdqoKI4$pl1`V3iJdlmOZ#At#u4WGq^&Kr2J z=fJnN6pEVY(_^1n*?70y{5MB|==Y85lpl10SzI(BR9)^d&Kv zL~NAYBC0XSEa;fys(5ve&U{q;(tU&(=(az}$T5!Bujq>^h1i{J*(YoS9e?SnN%SKj z+k6h}7`xOO?x4ekIEYh8@SvSo#)TZt2FA%X>peF8Sb7lCG<_Bxmq$4e zBAWAblT}pmgEAUP4zKHHt~!=%>~N)*YB|QqsTGEB3*744bd%j|D{L^pdsU6vL{x|9 z?V#WWco~L;%UAJLEFf5@Soyk+eKk8#r-`uXzqlfFhS-WL7|pW{-`B{}!~d>vX@}dN z=h`S)U#N-ZRs|>+i?XmvDppP9LzMDD-rY!5`ECKowxc5f3y1i?^=eQ-tMJ8b{}K0g zpvea07ZS70sNi)JG!=5T!~h}vphvuMZc^hdVKv%wwP(WP{u}ni8gQ)wYv{wg%?fcz zR&ICg_5r5H38p^DE)y<(A7@r+y|O9mt&s+TlR%n|h%#3v^>KQDkr^3Z)i#?_k)U5Y z{yoCj@&qC(N2w3$Hn51FNi?q73g9Fk!Z(F`vfiuRPC!Kr7FI1hXiOJhsw}lM?}o`W z#6jL%|Ad(8X4f;`AhgZ)R%`Cu)U3riN;A8tk>o@e!G}(M=nBGcANAMXb z-$PgC$iFLSK1n+Ukw&VsutOZP8c*QdCq?eHPm>!oGOxN&hR4E_lGEj?mT9f&0^i|f zarlqz+puN{28@;f&#%)N@vw_t@-{}Kjp_^%8U(@Xh?I=gHgdas3kupAaW9&(;Q!ti zu+}>A`A12o+6z>^Xq;_wyufgjiS-PowLs3LS6WYkUE8uxS(d60)^HWSqeS%6Um0aM z+Jik331hVE9WLup@W*(qiB%`K);G5Ipthv9j9oKMWqXq)p`%_?k^W0pFdd8i2DA&^ z+kVNRzH=sqeM?8y)NuGFP!{W3bcpq!aX_~tX#yN~G+q z{r4cm=yco?j2v9kd$r@-_Vb{W>_JaoUi{$>_LF+1)-#i3S49-tmAbW@FHoMLW!u6J zO++8!_0N`rt-{36_|YKn;{9#nkD)ePdCxTs`Sp5pZGu#HK#=?POoFgaJZ@>bmNazY zjdwPzjOr5`wEUzgI?SkP{^8Nn_?nJJaBHM&C9S$d(ZDqdL{tcTxNpD9dR_*}hpAz$ zM+pRU2TJdK)1PS@F8vB-ec7d9Wwv5QuLN#J@N?Rx)#B16WCOsa9$m6|LAI~@g90(Xmtm+Ufw|eswM{=kNlGr7%>T$9$ z{xnwJUTI;Af(Z~}q64Rwe|>x0Ci^e3ms`xfSwH-{tecHPmsd#MC}#}T;X5GqqLXZH zQ?)oDD(ZTjV|biao-sa+czKvTYP5+Suo%8>#a5hmY8ePgYrB8M)%T(2Q#YU9=A(h> zyUu{aVw3`;rqa}}Y;XBQKW1dUJe`~#K-)OxIllu38gUMtexXIEVP7iKH4=gID6No$@*?P~ z)u*J2vflC1AMB7-#Kji!^U~gHDX)xJx$hMpN(qfE4imNC3tMd$ORSG&Ms^?@~bt`7$baZ%;IPm z-bOR4BfKoX#D)XSd?#dc)Oh@^r-52t&*RD99D{2D!zNK>69@4*vP~1LMQ2!s!GrP> zFJ#R``eO8%<|_*UyHR*S0ByYHF%%rP;!L{l?>lwwJqSNBUoY*~K zU_y!Q4EDtc-O>EvN+z5ZM*|nA=&zpNv%&c!PX{wLZ4mToxS{DysA67CqJek(Fl4>m zsVASQLAUl!bu@>u*FfF3QYoIfA>-PO;Xc@bb)UdmdY4d!sBC@XW_3oy>?S4v3!cwc zR4Ah-zH3cvM+64nT(J?*0tAK(&8-6EI&*1eetuJZO3ILvy7RYe_YHqv^@lap;etW zPE5tf6dm1g&!VOWu0!bf4P$mCMf>mzot}u%|tSX;G%^`XVWkr$`U|ikcekZP6CX;WM0*@Vspl&om;Dxard)wH^4lySb@) zYLS=5kVl>G(c@0jagPj6|9U{h8%JtBS&Tg&Z&gMtFYf-5wY% zRCCw3=z-pX+;(rQZX^`Vzu~2S^R?3pU@XS(G=Q-W>scv@ZNk>6N~V+0VqvL_+60Pp}^8~7q~|&tL)}jyoK0UQYAO+ z{Ex*6%!3|(CEVE2x6xBKK@r-|0eQ@gOhFP6U~s0KcvSQWc3qTknCD}7FS|5(k)z3E zQ36%zg)-{=nV_}bwdWb-XEY?i4Dc>R%QY3{mO|QY?ChwCJ}>POB#PM(?%ADiY)EjV zR+Zqna4BXoU}s18R6^hyKA7}W-#o>K+ApreE{suoVV2NVzcdBx^clb08E?rki}@%( ztK2z8Z)RjagDQR35+J+CnSp)&L*Rs(Zio+v;o*8#%z`nj_1u?Sh6!#_SKeACiS7hvc@GVd^NFjHzPcl+`d3e zI(2K;ZJp<(Q}oGdZ9eN8c&wb{dC>Rp?dLv_9>>>xvZGg(Kqdf=6EOvGn~T;VdvMIS zm(pCeMLMKFMZpb5`U;atmQhMgiWMlw1FdR28?ec-Xk{c>blAmwVMP!Set6Es&7D={ zHlGS>lwwG&Z8DFHQpryQsnqG_ugeq1q&^2EbnrkFP2F1Vwk&ep!Kb=C z|8sC2vjaL{qpOUyOMeA{|~ARgd`_zZHrBl8c)RIwX0bHXs3k@@d%94tHDAArl)Lo@7+Nfvh(cEZ8d< z$>-LQ26_mgl2r!iG?Iat#W->PsQHdV=`U4RoVj04H3x5-{AV(++oP2`>myNB5PKq6 zA;_7wjl+XfKp6Wly)TsdliFHX+7fBd6oidk>ik4l5uzv)wnrs=j7g=9`^`}xVgrVd z?QIO*nkhMR!IkrY+MAsfCFNKb=v3dNh{CkA6M5Bf(y_SI-#t*Vnczr<6c~4MUzomG z3od1Ii31gv8m-iIcZ=j01o3xQ(rd*D@oC*|aAg8$KL+f8E8hrt1*zZ-Sr3|}d@X}z0 z)9X0^wcJ5AZB89*6$8$inbHm(ZHdNpozlj^DAef^0)%A$3@%;JuB& zXDs>JQTnaMYTS!>O&V9bUtL$Go6bL3f{cIiS}Ou&8?Lfn(1Ub5NMkE4VPIHsok+G# zGp)Ejd==}l)|)%BU|{QCB#kvZcaqe-&7rl^(t8T}YvQ)XbuZP@y#a!Q+I-(DGw750 zx=IsjKGa7$BWfU#m*aABHhnznX(59Jelo6{lppV)%#8dj^4oE`5qWWR!sOZ@plg+f z)<{08iZS??N9m~+?an<3l#ve7qL1CHcPpv|T2cj=>Y3U3LeD-CpoBWkw(*{`M1*LA zTgS}#g9GpoXuzYLA9>2Ug-8DTIZvOrT;+O}&J*r8eo4Tp*(vvoEW#0qKQEI=Gt%D| zovVV(cY0mTGX&0AqVqM`Q?wBC_$KEyWJO+@a&FRo+IR?ij#xEPIg&@owF$0cc4mBZ z*j~oK6@3bJF3x)R+~o}t?K1qTSV_o4)l)Vy)N}cQ@XON6SC7_$1w8@+LMNN-p_sTT zj-GNl!oWHH;<(bry5~T8#)xxSD|9=pbs&Vjv8e%eL1o9!y{E&6tZD>7gDRtc90|4a9y-FY=`vXyhDganiPc#j>yRx}1)psSK zS{P{WP{7#$j`ukCn`%A4yl$9D@unz4F7V2&y-6O-Q`rb#hX62?;k(BdpG3NWetmf? ze5>SY9{mD%!ZSl$IYPxE*ZDy6<8E`$^Y7t<`Elj?sOU&S&G1#I{1vdup*#XU1Hg*U z+4q8q-v>b`SM4{31bc@gBr6)7J|g_6E75GpqR*mo_9^eYHyxY^qh@;h2Gj#P0aVmz zQ#VH`AF$a*0(}Uvlv#m+4j-%-b$a=>5hArfEr7K1-F8qSDCo{d5XLXU(k#&3Nn|Vy zu&+Is>z(DdNgX*iW|OkKqlBIBWNzWJqBUnUXPJF0&$tED)B`T^siv%Zy-4|?TSvu` z#N}Nzkw7mfW3t7pC+E_=&U22EkY^nP{m+B=N+0i!jmAMESh66^IeY*Uy_(AChxY3z(xIHMp>#VAwn3;kt2`uM zSPj0>w#Y?#6Y#`8pre$)J=<-I=vv%IDd*~;S+w$6t`P$+Js_x{W#w2)Q(UhsI@{aT zET}DBc-YGos&DH;t}d>o#?m;-CGu_h=< z4T4ns<nz~0$}7{c^J$JH`l7AJv~R0Cqf-Hh#fn(c3FD#&(-(r`&?>7FyWp<; zXeGPcvV!n1E|RksVdiH~8>0P;J#VR|#5Be$Wn%(|&Xvrw=cPS02_#7CYbZF=X%(up zoA9`9{%B=AQJ5Q=Rh9#yuhK*opI0J&tT=;@Yr>V!^FP{nf#7Nw#5K9;?Qto-yix6W zM?pX(M2zYIOgI}$vuvD6aY?d;!ZUXL{WcF)gh>FnRGH{N z^bIII*9v&OriB?4O*55kAa1G!#7#p@Tt#`BWNgjYX37JW()CO}eUwtOeOFVkc}g;* zI`0kXcQ=3T1n@V`>hJb>8Ocp$a7093`v3zGg;{Yr#2Uvbkc(jpDJC27;cv))U! zz5GCwsq|+q5eCy8Gq2!J$TP47BBuI6n(FjMTBsM=TXtGH+`PB^5KcQU)hp1*Wz^cn zF2FR<4iNZlJbKLmcwVdYt^l8v@yhg!jX++NBmlJCEH|&k&7h1fm+f9dfd?mrYr06^{ z5t2DoX~{aStEK4j)e-AMDNBpzaD()0T?hnFx`EUBRH2fTKsEol_w<>tyG@S@g_TGq zo->t=9O5?kVrn1g6nj$2O3~2EW5<^3*nh)C_#Wx*-|zbHP*tLfQVj2^_YSA!Y7d$` zFm)r-@c(P?yQ7-Ozqb`pVg+1lq{<=|Iz~_gLf;i+u>vv>cUeIR0S!WEL9!N5z_L=M zDk`o@5UBwIhzd#w!BrWh1Q0^N7(qgaq2)Kg27_|m_wVmH^Iy&+GxI6;KKHrzJ~Q!# zY8rzH_?!_3gWeW*e&^h^)F z`(c$7leA~VRPu%h`?VzJTQ~2EUhQ&2r^ZcTL&4%01--{XhQC)oz=b}@Ke5O!pk|Mq zy0kkdpVbV;ZNRezSD>*}A?zB|U0gg_K@20pfV}I^_cv zA>6{w(d`4B+wL8k`q9y^lb3H#Ixa7{?RQhqyM1uaqU29}dYAW_i*)!;u(d1=((&~^ zbepnl@qnIM9EA#PTN6%1C6_OmzKSCb@_@qH-#D{uSBC^iH8l1n>8hFtTKyBSy@{DR z(+1F~3hA$ux-wVK8aSQ=$quq1d#50RF+~1b)yj&c|0&iMOvdKc#`WScOrGcHLUJbm z4mGfJESS!Tgb&Xy#&e@DO!*pV(~=mUKeGABvliTaZInzdU7x1ecPG((55siS=aPU` z0bY4*Jq-@aY@sdv!Gz_O)^C4pf8z4ap3R=T%Nq>Ih|n%oA2pkp<8PfCRJ|2kn~r<> zY@41)RScxyYFI~bnsglT0#`j+74;|(YUXVFh|Q%Y{DETzt#j3EbF8SDc$|r?QO?1&<~V1^!<%xBvEm zve2V!}I{A2b0Aam>&Fp>48mC)`k%C z$;EoD^2ow8kPl#Jd|67x4XlglRYT90{2Cy48)3y0j<*o$M-KqV*~_2sKdd}}Uw3Ph zePHs}Cmdgjc06Y>g_-uiLR=7=u6>29mKzw})3spI76;z9vaS888XyKN5pjAdxNUDM z4S1Y)MHS&{evBI&KYzu#2m&pP>gG>W1#d11%I?0JqGwsRNO&K^DIL@oqN?4`e=Foo zRu+f0Lj98X8X0NCcE_WyTiM0kBN>3#>8jDYtruk3NLDJ~x2_*keYycUx@-f<8gDn;>rGb_9;z}{xFh&1eiwkx1<%qQ-TlH(GVIbn$r?TP z#nrj#S|4c(RGi6v(PcSxZQa{aKk?rF!FBt7sJ}wD(%2*e)qXRx(7O>>E3$w!vZq#U zQ@ij&`L+a1i6Q9h7x-w;?o@0Z;Ke{S$th)UhPIx{>9rhUy#$o${I|g9eovZ=weeFf z6X?3>eb%j~P6N;f2Z)=&ipzUVPdC~P5ncfvZe8mV6a5wI^}S5r|4Xqk%lO!Ju}d}N zOIjkHsN!U2{-^Y;u^oc;=x{)HLCQSR%~eJ!m``UZrq?)|C`xhI-I-VtkY!aOWCNAg zvC`=#cIU{WJ*B^smlhJ&-2}#v6Q?K%sx5)RqoEX=s3QrMyc*e3=Ch}-8g$HFp!lX? zg_S0HuKZhoEUnP&*u>Z!yRwRP9(Xr0h7mv~6Tb}pL4H+~(T&t5ZuwmpNnT)uwjkS=j+PdBiG0yKH)?s^0AA0<(t4{{PM)0 zcW!a%MB?`T(J->yt?JhPO(e*BG}97mCWLIHsr#Xc0XBBG0rQApAnsdp+C>$Yh17W&D}A zLIas5;3i|wU2Xp~5L}=m)l?V~wq|@;F~TmF`^5#rEONCzzCOW!=<6T#C&z=x{_N&| za3(8sm_-?eMaJ>N9wC>(dt>J@-KF>|IyFgt&4p$bZ@;>)FX*A)dR8%bgM|%i45z;3 zjT$k0zL>jS4CM|0S&Zx=?iD&BPCzU4!3N7VqzkCVpaFi|o}9>@?EzCu(fHuMr7*Bp z`Kum5U@-Vy6yK{H4LsEV+#Jm=b!_C^;=C${c^8!wo+_50t3kVniwbx=4QQ7 zeX@MM8*Qb*P7lnR=(51eb-9?AsOr~7qb|o&_<1XQ%oZ(-5{nq6vxh&*(^!nmc{pDLgEj-unVg)soQ;c6;dr$tuZ}q6U zME}^1B29VeTB4jNMdV0UrlXpR_mSJ7Au=CD4{w=O*>}_>4l z;le~jZ2!mm8f@^mlgmac;udhcH1J_MM(r1_U$EuG2U9mpg-NAN#E1nr+6$WDP1M0- z_*j)M1WH1FQsRr2vK}Ps8lWb3W*4)2Wjl21bTh z9xFHIZ{h?!P>LB4HbEt;bksf`3b(=Bpw%=Gi># z`J!=_r}Q9;`g5z+p>oOBMr3Z3`l9?{s%JH{SH7~2M$TJW*& zeG_&swZq33OH}^j+0Y5O))WP3aBMm^8X-ud=D~5Im`j?1r(UWuu3R>HC zoxHI(qH39Z6naNB#oc5C=4gA zvQx9V$dU~y)A+zc93I^;V7gwT*D<7wX&`*ZV2|VjYTa%*4|)<;u`fLm{6?u+xA{Ad zg4%1(7uowSmb;gVmM+eC!FQwhreGhUjCX;~8@+PKBTvSV*!!l5SPX5YunLM7<=mz6 zO(yXi9>pdJidbj&ZCs^Ei)GnFf=QGO8KT^$UI$uGjV`wrj8D9220=zYLxy|}EB(21 zje(bO{JP4UnrCQhTQ-9@e49RqV0yfdU5IZp0o(9xI$%Ej(5yaRrUld*T(Ugj?#juA zY*Nl>E*W{V`7xzJ2Xw>7J|e^eW{I39l;Ofpak3CV{WLhdk5Xe#e{59}WGVEF$dzxd zdAuyQXQUJ8QpFIpin|v;PWl93(+i7T%4uxIqWyP=#s{?R3cQZ&2`y=xpi)}e3viLb zVM>kQ*4{Lz3$1R@oJf7)7kPVkdhTEf8Og;MgR(57Sy+^^k;2~`Gk@YPr&&>7dh13x zk$LuHOsi^K{LKEfvwnvL#rGP=j$-2i*>SCz@%b3mt`a>D!6TsMX`9i@k6&t4;_*$s z(%1EP{zvNQI2qfkZU0yexN74Xp+EHc&h?p6gC8UtU`i-^eYp|%uJSk; zQy*{*qF6@F?n>UF`7X@Ma-Zvfej2K}!_Gf8@^AWe4gqhn6GZ5Ak&Y`f0&)PE2fJ_l zHuL~6OU44cB;dD~{EqUzDQJmrQI8G!!wqjxzc$|ZxXs2+RDC9)W z(YQ9=uQsd^HjqWn8$wIB`S&2z|LR`+yeUo;rH=BYp*$yQc2=ZghYYJ3tMTJ|$bNN& z2ZB-kV;1C7VdrR^({IQA-I`}_J#;3kDZQ`kl&$HwD8TK*i?NX|K$L=Qy~61kVF6jY z<2i?(Cz#E45q-!-reD9~Xih>bk!A3&0v;E<>vdz1svS`PZRHd0dsYe=)b|PX3RhPB z67DwIHG1k(2EJ_*XxLq9?L^nfSxGweN%`T*n;q2@-+0beH&o^6ZCyO*pB0dm6YcIR z8vHiayBUCp(#k|^=tbQfQnmCJfCP_BLLcjpD#DN zPb9SaG*&>knGh7EyBi93^9rfYoNYzLxb~fC#S9u-HgR2XyuZl~u*A@-p-{7Hutwk? z8+u?ioGw{hAgXmce(w>-6eCDvPAkh9C*0>w_gh_Lgftbh< zvR)ZKn-abqbdXh!PQInlJpwU;i~ZIVV=&F1x)F53Lu4_)mW?Exe9wH0W9f1GTZ+4Q z%!;4D*yM+mb%j(DA?{1s(n0JHuRSjddL2qWWJva86R*Y^pB5;A(gZiN_!?BsXoex% z(kzvOGN~BcAFgc9H8&ZqZ5gg8_N(;**&`IdufC8<*Xb5S_Kc(ewEdTV6`Hy$*P}d9 z5Jii`kN-mE1X7s^7%v)X4}()w>DTT{IMHs_r+Izi6E~?uF*rM;Gt@b5uPJCP3mL0>*TJIemhiVKkmqM6j*U6XCAb5pz`cV?hF<&|?v2NHfpsnbz4LQc`dm z$a^j#D?xb_^$Htl;31kcQnX=p+va0vlfJgbvGq?r=UDo0ahh#eeOeF(GOHV)cSFvX z+PgApJw3Yzsp?y=YpMZq@YF5fJ_8g=8RRj1IccsfePsw-g-LHzKbXIb_!!U`C z>n>H;l&z@eKLpz2IgcsYsn~}Z3fvf(>hW!01^G#;?Ci)Gf%YQ#$}Z^*i=uwJFx0@j z8xi>s<=@J`F-1uZ{;HDROP)P)v2qB#5Yl(8R@lCGlO%tc`4)i)YJ>9sInKRz4^rLS zT9EyI&Tk=ksmxqwsW|R~sD`zSL%yVpYv$G}9Rad)+zU$TZ$bEWX+^5%TsDz=j!CV225ByD;{dhIhS4-o$h+PDSZE+VlP@W%bP zEbzwtV41MT{Rl*`$Nc~`FjPtgj%fggW1K{|`7a*9G46-pj)uv}555DF6PTQc8LXTN zoDTd5q;NX$1CYXb+&7mIBkKPn0Vj$4YA>IdH*cQY1tGyi(e7i!Ds6@G*B_qEog|+H z7yW33&=K9$CkGs&f0{ejUE#jr$1y=ist#5?G1hXJJ7qNr!p)smADA!GUtp9sXUU+W zqwoiVm`Y~s7s8X8UKx0aZ-weHgeM$^aFi?n57X}I#D1M0bFi^li@qKj|1_~G` zV4#3g53v_Sz)7Om9pKDY94_H>Ud*dupn!owj1MyjI1CgpP<+p;VW5D40tO1WK`_Y3JY3^oFa2O(;O5X@Kd+>JO=JWEgRQU- z5|Wn?68bLhXlH6+Z2|@+9+8p;rJS^m;(z(^aT1b>6q!7i^*sknQ4mpwa}8R;UtaJV z1UfEN6m>g>axtZp2D-exN@O*;TJr6?B3%!4Q% z;<#`#?Qi8Yg-SVwy*CE8o^RxXdJUl^h zOq!TjMT~~Y=ICnMo84GF$0|3xF0dLuSVPdmY88_KZwosE6u)B`Z~SP1-L#;)*( zBnsKof!I_%{sfnbqt>dJE5b>J-+EU(iB?t$-fwa)s0-^40J0aWnQ3%2TW|lQ7wZp2 z4EmXy_+^x`kcoXri(V!_Q`dHD8w^hlv(?av8HNxLA?Hv(qWTxDy)WwhbW-((H?e@( zZ`YC$43r#EE2C?YWwHg6>ZRr&`rFIU%@U^ghw!2<^7 zSU*Pa4x+Dzgbm%(P10M^Y15ge1f=0gQJvs^hGP$V4=Fa_sQ;`+O$~|}_+gM{blWhz z_O@nv26={m#_+&{5N5O&ZI8gtr%gi#*#_GN*@n3q%oPP1fd4&m<=&06^X)Paalq+X z4Z}A60E}X+IEo! z-Rs8vpJd&M1&M7adX#b%q9@%8Nbm(G^V}BP8={)D=K!1Z*dp9{jyp6@qBn+~EZ)lM zV(Tirl5W8c?dRkhurCH!OzhFjBdj9|qVxw%k)^O&BKeIPB?`dO38-a`%8N?CGGO_~ zGFN5Za=PV?WrZczlIAi&rO}eiGG;lw+HRSzz#96HdW|_P0Suv^rSesJVA_Zz*31^krRM9H$k$R1Oa4Ka=nwB<7W#Gyv z;>6+f`6t--hp$=|sF2_oV3&?$PnY_bhtZcoBH1y2rh{#6^Nv|2qEF z>s#kHUMw7JQCwRlYZhQPEvR4C)ina)wl z0p;XPvt`n!>v8#wiL8cz6oE{86V5SiZ}TqwGNUmd)$@lno!Okr-rYCK&ET9t-e0~z zgA<}_^M|Lslf#aY+iJ{xAV_6z`Ml;3|3v5LZA@&He7tPHY-x4IE#*>!uUgN47om?g z_D9%g#X|q4cQRrQfPElFAsH?HldRw^rJiS84h1(z_6338~B;YIDC`1*W7V-*viC~H# z{+f!?Ky_kKhmpcJ}u9i)jnpmdTacFHtUz1@yRixYE7ae(riA0bmLw>{%2_87k~Ik){>rNRW)% zjt`I1hvW`2{RW}+B~K(HRuEM{DUvS~E@m#koLrxf3riL%E0~3g@vl`fpa`w1*fI^*ooDgftYvgo3Kwl@}MR0d)qIcGE z%QDik*zR&J-Qb@cpA-M~%FJX@^^JPd|Lyf^nm$^X-i3XFRD-33i-PO3{%zB76SRy- z#wTqpv$fGP?Yr4~-hN(q-ov%!ibtbJGeL>7f!*9>g6X6-Q0vx}cG0VCt)<-&)-2X( zmQPw=T%+9Q>~)gXc-Y7VBml~wm?gdu!8H8(Yu6|B{C zwFAq>tK1bamFF)J_e$Ho_irJueFRAOSnOD?^-VJcwY9oMzFJ?lzT04NH2;~48PW~g z#F@se%EXch5$i`jNjT;k{n+wi-ZLL%Txl3N_&Q3RX)z5+D?d4rI=^zb641KVnv42Q z&bg7ZndR5;1nif{NdlH7%h_PG&Jou(a)0Q;GU{)T<>{LJ#Xf~ady!| zXtz7hAMZcYxvpkN(WS}ix^{Z+!-6D1Dz8UTy^b#RLT_{B^U(N~eKjAaUe?Ev^Ad1pF?k7n ziF_H~nLZGQ`KWZU`#9grUh`H(jYPxrq;%!F*KbtM&jZ|AFF8j9M+ti5{P^Ar_KG$} zgYwk#I(fzXd^vmn!o5q4t0mQ)?*e-7<%;E`!#hwemMHx5Vab00uD<4=mN$US*@E$F zvhyg(!7#t^=|}ea?VogbNzRRz9MOOwcYr|@wxYF!mQQqjL5j2t=JL0(Hs<{KAv=AV zgc3Zn{SqkQspvzD`B$j)_^I#iO%BdjW%< zL3pxj8tABDvU%#vnX+sNZ)>KG3lk6a-$t_npiqiKB+YT+3a?Rz@)CWbP*V7j3T2ym zb>9)lu9NyE+2PtzUF)J6W+bDks%l}?k30{16^@*ww2!LOwo%nLmkZ>>E$ zK4A))hVELkg@o>+CXCKWxUzqkO!gY(ILaGW)Ub<|iHVB0iAhOiWhE>=daE#il>fhv zIdg!5f&vvMr>3p~8C@FiSx^lql-1Peh^r$I4l9}s;Ql>D$tF>Dq^zu5JQlUGiL?!E z9r`~slmc5Z=-Q4|%Y8b1w|-s_sbg-N(a$AhguSXa7&^n}a`Bi~P;t?bkbpto)z>vy z5&7?0@B@fQ!9>`3d3DDXS5~E9<+eLLZjU07STEZsvvx^{xaa!(J`i#gyL_o^XE24H zSypaC>*1^;|6LF9@8S^oiw2Zd(LA2U-roDn9)9#}Y;D})%TU@fYqb6Ke@ly9pBuZo z_h~5l(EbMx2xt`oOWmW$vQZH5z3}+m3K7P`hqRSDIWbZ3w>9TAi{yWB2Sjiz&MLfE z%4>;ndUw}Q3zBNOIcRsFGdlqdtqnS5(V%n08qI&h&nKLkZ2@Das77sZXDRb$y9Gh7 zY{6E{22KH@l|=|Ee{@7dL@1{gacd`MT_yev3*VU`kg%v385!&PHP-pGDH8{e05RNs z;x58KHfA8~%j)0DiKB@$cuv%i)_3wZ{(gfI2 z+Y3r41XLZD%1GS^ZgwgfG=PngciPreR~O#ko>omi{2M^UzehvpgN4vR=P=-HLq`Fu zn>OeKWGP_({lVk;Ux~qVkT?z4Me!Xm|3sjYk95!|l)=Kmo&UyS*dzrl@jEz)f&63d|bqD-1gn3?7>)(rqCfHBJmJ1sypsJ!Wd6UYhtS;}@^@;ZTzxw3! zAd5>%R@S#yCN?!T3TC2EP%Xvhd^$eRUhx^8#l2MwP!kS@HnO$`k+M`^RHf+rM#P%z z5=C*P>LE}O7bho=Wo97IOGQm>i+XU!=6gZ@emZOx@WpsGB!uRcEdEIU&K>HUI0v?*5v$}C0wNNNRK!hF;n4=hmNO+^nYd-fK z9Us3&7MQ0PhOlz>h<4SKkdaZ*=>iIcwzNFoXz`VFV1sFv1<1oDB_^t5t0Lu`D(lu# z(M+kK1A&G-H4BnPAiRuCOPeMUN-yc?=!T-x^z1@TXX%yQFCigi93MKkME+t_e<0=r{f{C9!mYB2$w}g#$(RemRlofBiN; zz$O;VS@2J20fD-5Ij*w?jm}`k>*HF(f#ptjN3Ma;V{nwSr)MV)pKmwBX2krcsjhp0 zW@?LcjaJ)?5^H?S%?+%IynKGp<00_qt0LqqQGlxun3Yk3E{5%_&G?PhF61xvTRC9G zVX|@$YkOm1cke#8=>K!~z<=IddJJ73+l0IwJXGr8VzX$+?}I0A`Vq7%$MZK#OgRhz z|L)r1V1!Kzd}el5ZB^GRX7-^y2|_%d6Ts9 zyaqMW7RwSqq~=dMk%D$Az}nig-Q`-9Ql(nyG|Qoux6mOq9W3nV*eEF@v;6vawtnyv zNp4n`MDp+Nd)oD6L4&wYbUd@q(4(II?##~o3n=&#)a9IRCzXzJ+45O! z))-Y-HA3(X2iGf7U=^|7q1~5re__=zzCSR#{vUnB^YKyZ+fjsgUgD|y4PRs6${^bX z`hS3&6$}E(p77naDt^f2R`Y$_sP!plvD)6@4Sn5W{kY!ZyYIDzDR$YkX*)SzTADd6 zNz6d)#q~+o`>jQ&vuX8IQYEHIw7(QdM57tfXpj9EL@wMmDA-ox_0nK1&ZV zpSziab-*&RyVY>;3T=_Pzi+4_9epUDYJSTa;h^850pu#_Xu17+g&JRB{9NNGc_$s# z9;c#8?5~+YMN6BMA3n@WZa%bY_VBMTY>8^G<*(v>-b4FA`RV=NC=H#!%#808?7dix zA1}5?Old`y_DSSp5{^;H)8jU+S>&?BLzd!&#Wt6P`aXJaJT@#`A_W<9osTkH9-N?H zn$ZCm3Jc$nc_dZ<^)c5t2X?Zk5fKuwy5#fozn?tqWM@5W4`ABwghOd3DoLA~+h@co zf`i$8JWWheCdN4mA|r7wZI+%~H4^{%`U7RZA9fnB=f)Stg!SYfSP6&lcs(qosuY#4 z2`fJm@F?d^NwYZq688wVmlMRBoKem5ox}~JyRyoQZLbTYb{tM#+q+mJn z(cu^Ob_3Pz0iA-iV3Xf*S%X;TPLA*{GIo@<;xDc0BlX^2)G7-L8wVT*Xu#kufoj?p z6*onQe2O10ZJRYXTxoPVg}(P7y(*Xka`y@QAczeV@FsE*EgUtY(S_`5rDq!&;Df?U zI&=Zb7H=(^n8ZIktR|g*%w;J47#u@}@6hI}qtM^$2EIxnp)d$X%l_kU_?*%%7;p&1 z>Hv$L_mQfWQ^E49G+j@Hke@NiH3-*VVB-0Ok^DEC3a*5O!`33gzx#Uu9>0eC)3n4X z{Ory{_Uisam0*{fZE8JFgHbIP0l~k7mz&HwPdD50GT9vpc~@$**zRv%{c0~dL3A)Q zikem4Qa<8Rpx+gq%csjIQ^mGjVTkyuVzC4Y^~Os7IJm%6jjEqZ;{E9X?QD@zQG>0u zJ5-<-n?y)(@SXbPQOgtx?3)XO5mi)@B90xz-jQjaX%cy_icF~s!e6HL6A;|3WKWqx z1wrVco`O4-cvKsTCDs^WjhfjvD321rr34L9=4`XMZx6=;12JGQ>4y6gIl$g7?MCZ` zlSD3AYY&7p8I{h$!wa~MYo>l=kqe8PH$um4hC^8U_G>dK&%zea%FFpk28!`1W}iF1 zZ*k3y{JKg^9)o~SkA1=J%?Nn1U9Iz_ZV^}>XUcI~XHp_c1Z=$?H#a}vJQA#s=jWbE zSLdM&4$TGp7KwbI5T&aGjCtE8uq_!etl*HKy46xnTz>(;V#HMB3MX48lp3WnR@MCw zknihQp>EX?*`OM}5Bg>~T^$Ya7nwn>a7ntB9qFVsm0cK{&TT^_0~K4d8)1cN95F#S zf19!&en79&xniTiC=7?&y`FBPOYJgLc78OWsjb5>4SFtAe`G7~DqxTh`+__m6h=Co zL01vbk+&a<&sXbuzOj5Ifvio;%gY+*HCihI052YbO#$GMb#xmU9o&&Rl1AtFm}>ys z2?p**g2gm6Dn4no?HO8EiQw?2WJ^h#iP+$V#CHZjdU8Zt%85iKidc4~{WA9?lq$(A zEF}1crYePI+#GAX(mWCgRr59W<&g%Fk>6^qPRz9bZX7<}5eHi@Cr*o5m_^V<><=u1 zwde%yDW9J|RXW?J-6SOv2tU-%b=6f>OJ#GpD-iH`s~;}5%bc7-3%slw2>?T(2r7NA z+d;V~9ED)J?u)d!vo#Jwwq<}VoH{Lv*J$mz0wf`1OIa-m3H(Dg)iYX@+rs)>Wm$Yq z=VVju%KZHP#q2tt+#uv;WK2wQU0g#(Dry*y`svg`FnV@(oPLyVBJI!niZF#wgQuJ7 z5ee*#K3zkw$9j%Yc&F;R_BT^yC8AZa*Qzds{RNIUK}uyGxoqB~yd#BQA7jy1ozphz z%c_5)YDz?`nMX~W*YluDa);LT9v^POxgbVW zBN2<0$7QpvZ0Te136Dkac<^5d4)Z|=6ts)&@9#zKc6%{$aA@doyjuE9*RS01+4cNr zV30i39-6t~dCj@hE_m#F-?k9T%sp0nmdS% zdTvWPsM$&ckYPKYUvC357QBCafs4-hdQ&2gTw{S@Pt~D62sAW1`T}*s-X%+Tz?`;VWn%3J+#5hHl=V$K%u@8@3)swi6EqNb&nwX;) zRXL7eTcuPz%**+*Ry2;F=IbZ1;C(y$nUds0?3`mF#S5d)v%mIprrgQ;XbQVV6TB6Y z=$#**Vr#w>y7`U=FlpzMq6bFEU>_gG6=-sQ$tVBLw(9kOjoV8=>2v;bqV4hVlZsbW zES6R|di1)VFJo%qL0v$mQPb&5G0^nMsQ6|vmH$%D%48x|C~=Eb^?R9hP*KHhN7+ht z)o8s(dU|u&Ru;^b>FGO6e$m&6Ns}-V^M7R%NQoqCf1V`4-TX1h62sr6sKp6DY;UACoZRk&*fa+;x{k|xj)gVcDdQ$RCc^}IG(i3!`G!&$VjM~-jK`vOoM+m zr1ZT%M#-aW>4W!gUgs%Q8hFMP&5VyUH_b$Rvr-a6<*m) zE~_%Aga2A5HKjy0n_Z)MLMv$Mz2qRdN7H!ki8p{?sdk^c<>Oe#qQ&s^VnYO z4|KNA12fRdVqop(2-V?UZKY*q3z0KVT_0Ih%`^DZshvQDy2I=2*q_W!GWZ z$hHdJ?ZRdF>7Y__`nGv@I7)ppwxl(ffQN>nFNy@)eSJT13K0A^Sjy)pX{kt5&MKXl8kR zd1TV|>;A^!$*kpb)rV-}cqrYm8(MKY%O}VC5tpj}MILKsmhZz`uBwV`dM%yN=
z&@eEQ$s|&DE~yW^{{{Ek$#Pel zu25tr0^VAg=i^AQRAny2%%qLSqv94w{YX)Ji+yz)>w2kCT=}r^rqhZRm8^x>7jp`f zG#&kLzHRjW#|igM0RJeRloxJ7)*Gtd>RVvM8owgyZvufCbBgK#$+vK?qVn<|rI8o< zJ$~Apdn!F5I37r<+Y6DIyT;k7nhGVcd6kMG`+~1kR$Ef*UrR=xl>Hknn90UVLF{Cp z&@Tz>T_X2q)@lkUPS<1Ok}13XAX~{onG)CNM6ZbgguLoRv&a`Mk)E95IFFE6(GIRM z$@SWCg-Y!;JYEf=%llQm-T4`O8&8zqbJvlg8gpDf#5b8*g~+Kab<#!{I4KWaomC8c zwiRSLbk(aitDxCHn7WV)+$G7+3i19)HZJeDJqY@?dS z@xF+)7>}bA!M-6(UT1U2ot}4hbGv+okyXx}Oun_@nCn);t=gBU*JAnsw~al4AmHmM z@BKm)edQM@#3!l|A7p`i6M_qUU{E5)H*EI)^Y`pLKS>i>tx|OTrKmS*Rb$8^7&&~O z7vsvs(d>d7xg5pKHaiuP(7YeITs+A#?|Ij+Jx-&pEuPDgal|lkb+=~P<=F^jnIG%q zmK*DfCWh5roSt{#nQV_FI`mt<E~k>t9gZQz z4KWMR<$57srCKv*RYc!&2D{v#$uV*}qN1i(C3|>S4yor;FzJ@8Z)ij=tvu##peqB#u)(oh4yC^22$jBqb za=z5?e*R{pW6%{temuAB}nykE{bT4|X1@peVw5L-1K z*U-r8bK4jf+P;iG#z}c-H0?r&4lx-n#nGM9e8fp^e_WDO7Iz;JSe)K>IvYZ{jQ@(A zpaXfqgM&I8ZTNH*@=Yh!YBMuwk}xg~(&S`UfO+qFv6_8dM;hDgZ3S*yv+Z@0*#$7d zYw~{X-J$$l^8RTw8r7!Lj?}~~LUu10H2rRGSF#xivI^=-sN_vq>+52`utEH5%yW0R ztxWo!JCw`q8zI$Ny1u`SoUaW<#l^}zH&;V1P#$A@L=(h(#2y|UmR-eWfy4+N@6X5g zTp!JN0TGFGP{?@(%R%?6X?JP)#`1xj;ji2)9~bLQZL$qyQmK`6hR8uI4tFO-OE>7$ zpyc1NsbmaRDZzx-@;4~a8=%y zkumJDjW&zTs%@J2Iy#*NWC$rzXf$fJ5-D4u+`;+1f^T@>6jWrqkrOT$kK%`HwBxlA&Eb*^Hsdg*P|no*u;QsFex-4&^Tp zeSMl?oa{KBmG>#;GZn~jzyFg^n_@@tD?T__*yWmRw?YYOgh@OXm(%sE{7B-1OWa;m zh-lOUOU%MWzoEU|-6i2}Q~W@kaz(F7`e_h_SN)Wqkniu6Pc}yV9)U$R;0!hrByY130YLQJWxlw~z3>}06guZu?iok$m(5McbKP9}CrOJT1rlz>HYM>+k)kz+j zy=(Pa5<%f6`g|iOZkwcY%) zORP$7>Y{SB3@0ZX!vtaChwe_G%gkd0lVzOaBUGyFH^j)FfuTIkLTvYoet4+$X~9TTIV8MLSxaE2CZkBn&Fr+3*_8Ydi`pe(&Bc(=5Bos&VCi zC|Ha}AWyg5c7H~;fF5O0y!3B0Sf+M7Z{hFHkL-A)AI{c`a(y1KU4kHhT<6V;hXK4I z@R*a!r82lYCR4cTtilZVO7UByF3uKD6ZusU181*CKO0xlgxhgfe zl<$$y)rQcPtMQYRG$s`~oK|*3#XMGZ01$y=|5u@xdt3_1axcnp+Xh`h*UOy}bp7HL z3Aszk-MX;AdF32VhFFnZnkCeAd5GEgZ{K`g_$_2GfnNR_w6^c20XJ}y^wrhmPTQ+~ zQ`iU1iIJBtWKn$yFsvLr}!D_0)kiG+A2EBYtB{t{7p zU^bIUhPv5IvO7VJFQaOf%jk?f?xstcrlsqbWe&x}c{no3GFU^V+hszj=fi2q`)eNC z;jKQ4!$O9mo!ZIRM(8nCV64H^AGXu!8Qww=0k?a(dTNyXZG%c0n z#*C`HOrs~5pCGPIkoQH7d8u1g6)kqc`T1S9dMw9?TQ4n(AuCdF`B~9mO4U(hgpjpbR!JwZs0$PIJ9r5R}jcjR1E*XD2Db=m&Hw5BN zT>eH)@gzQIFRtYjN`AB|byS3zp@3~uRU9UpQ)a6E%wUwZ z%SG;scsLAi6{+VMxB&i={a=tH?t*rs4v=y)R`DqnuO( z%%%bNmJces%b=rzCoDxpMH-*A>K%{QzK!9wx%M?3ALhIH{(E8Rj0v5BlnuGKO6v^Y|4o}ze z(=}?#&75DqKZcV3YK;!b?&zk=YrV2B?EpP}7q<#^_GhZ4t_X~f&sUmeh;V$U%WFxZ z(G~-i+&G7#MpWmi+wIa8((1POCpoBDOnf;w0>dsKko_gP!Sgdq%tdx(l3E6xY~fBU zlg+F_4IE~F*=N4<&BV+T3UB~3kR3MGG0_WyW0kw|G-J|Dq{ zCeeHQBr}<06SNSh@N$0f2OSqttQZw^3y+u5r{$gDTCR=lRz}keLRrr?jRcz-lP#NS zdN@spk8MK|knN1sf+|1U`}7M=88?XnkdXdR^1UOGz_!=@_ z4hL&Ld*@8m|NgzD|6K!9=di+M)3sqEz1md@gZ`eP-{)20h05WRGKhGk1r*w2C8o4Y ztySOVQV&GD-=y(HRGBsJ{w++?cC^U3a`bWWImbTV)RG3J(mrsZI-U}{y#=-D9 z5`*leWz|xS9nx_I(Y9~M$VP}Jlu9fm64Q!7TL)PW++%kd)KidL)SgugsHQzPXgksB!k`^PsGgv;e5xWv`L;qn z`85jgjch6Jj=4jX9*w%N&3Z$vQm3MU(8HANLgkcFq17N~ga^_DO%iKm6d`#}8+yq& zwYRjD4;^xo#@-+lh?1(`^!;h&aFr*|!&V$cWO+-~kco=|O>&@p>!nnuMh_$UHQ;_V{f^;u$Qbem z)c0pHS|`H&_u33kCe0%+b{KhZ1ahBN{00cc;d3~}JSJwJmvzgz{(w$Ag3KLn5Uqxg zW;NgIi_ua@n5m>WwEo*VcIj3h`Df`Y>4)qUv+u;6e|XrW2IjQl$I*-DtmcTL0>U)v zR|5M|c=ZKP5|zh|&s)qY8u5wQC&QiLIo8(DWe_JD?|h!}eOqeFVm(C*@I{o0 zEOFcQQqy|dd-nvQt64^&B^yCdYirvSz#rmOpEIv$*lx5dJi^<~hIjiN>+qq8kg6tc z!w^7XA=kqL-FDx7J{ieQLNwUu{m1(~+g5pv(`v+iuh}Jmin_c!VI->yjrzsxm#+v9 z_Sih8)i}KS%(G_IMj_w(l|)TV@vW-M^!;%Wo_9tLL)x+v{aumVVfi_jC&3%aGl&0> ztc;Uj6}IV5(`m;QnPfm3iaeoI7qJYJxdsfsZ*8F-4SC|G-Wj<( ztZX;Ppt-ht7@+_XHfK@Pte{8wKKgm_zfGyPRU<+?l`%d>%HRnHQI74tocH3S3>msq zC_6lcpm+?Vlb&lZcu7X8|BP}*JGh{WPrCfK_>=${D??@q|epHv=M>rrvCxx4y({k`WOzUZVx9zpX1j;h`R*w%?H4j$M z&ei)5qHJRYOx`fU1OsWqDc}b?1cmmr$3<{4^_u8Tt0~RKg?2Q2ar3x66qC^O+v!?GBq|YRoVcMq zBoj8hizqVVbx`)8I~x5yy29?hnA0n8!b7_2yCAG3E}-1+OVNw(@wK5e>Lt%$>iG(6 zdtJV5NWy`d3&5ZpWsm7{c+$SX)-)Vprq*%D@e)~)cU1){UGNK0up5sd=@8g%()V6< zlgn?IM(n(<`0XgO?K($AqL9HL|L&`C6}e}g3uUV}ZR-e>D0?sT#|Av=c6-A(LU`4U z-mBD7z9L<(TTiph3A&i-1cUaS4s>chDEwzvOF=Zg6gGI?A8b zeI4ziId~KhC1X;wi|9^8G0y4mcMYh}bysyD0zUVW{B=FyE`2Ik_YBt~UJV%A7SSVS z-L=S;y+^7!UBK-OSDS>2bBg%3`r?MV$VmM=b47xxyn3T1NSAol!pS78-8mCdb)j%j z&<0#|=QA52(N8eu3PWQ?(Ko^fLGa60-5)u4BA$PS!w^Xv$0&PoXV+`Ig_#(sPP;=e=gtt3cPK1w$-;LJ#y{Vr zgh>E}W}uj?aEOG}Ujrp+Yd!;x6vstqAPW|#8>){NN?p}aJCoDpNze;dMZ%sHXS8|7 zQExm>3^UfU+9h5y`#>~wXGW1)u^;Fo$gMRM$kJcWdMp`F2XR&@x2M`GqMdggShypj zJ@b?4W$f21!{=$kdV2R2R9^Qk&iz%*n4&*E)(}0Uzc7+nxGWO?bjJ^W`E|flfzn|R+BZv1WCr&+s)S&!zj6iw!2zm==p zEM~#F^$H;|UwbEYlg_Z`A=Mp*l`K@_KBRhEgiZ%y4Tt79mngC>A@h%SLpYl#cr0>B zM^U?l*YVHLO;(7r?$NXDyi%qc-rc9IWKc-Xd=J$X!Y|~P>rQ@e{X;{ja@-Y&2csWid@l)o zg+%Ld84lH4(U>3uAJy$r=dV`Zh|04TZXn`aE%)*RazlAP{yIt2?8k1Lu50vM<9Dc` zqHL#@WuU-sq!AzF;Cv~=u^R3HS)J!0FXQRLZ+E)cJji#WODczF|FI8XB~?&t!OHus zdnOhAMv+De8%cU=e!~&MR0~k(Kc4-NzHytKiyRk+c?!XVK($l9&2I6|c#mdgiCD&v zQ1>u6zbEGrb}*L%fQ*tkrfk82#Lx`IJv=hp0oGR))`NkO+->RX!ji>yZ^Af;`5rpt zz2vb36*Z&}Y2`~uhcLF{H&rQ`he)4{TB(kZHE*%SifvZxG6Mg=-=oIXZk*(-2COJH z%2cN^%8%3{LRO`2dl*63i zqQ>|N5?FjVcrO*k0M|_z>m(oo!PDpv`aUJRJRNkLvh}^$jBVH`3oX}D#ZYYuhByxI zL!9i?c+F|@OJa)Kwpf|XQJISH!f11Yh~-ER1_K4}?-pmvSM~h1kF7p?)^a&VVsMW+ zX6u9Z^*uc^%c2_?Ef$20nq+#8RqA45V_T)DGDC|hSlzA=7Ks`CY=QE@-zq9mR+qqL z7-zx&f0q`WNO{&5G*^yt6HzQ4RMaHCS5LYq2nVyk5#Muo1;NQV@staZkiC&jnC)#=IxoM$nUvwi={D~$n-i+6Ky@giucmI|% zV&zOOUXnsikwU;!?jrx|L$!gY=B~Pfi>qFl&VFW(RG@qgRjtCWgu$_Nxl`JcOkZm7 zs_3nzk=K`PvW@MDjjdiDL@lCAV>L0_iBxaJ~NQEDs}3as8)uXhtw!hQxxeWEGwG~d{xV(IM88Bjjuzbh0d~m43 zN9yk+I|yLv<$N*b!g4JNbAP%*w%Gw0gh;X_{!G|X~JdY_MQ@sZIjlE2&c`GEL7mNzeE%c?$mmE3vTN@DOg z+a#z8e|w5AmddDIb}Rj~y=70>2j+TREUpxuJI>(Rb=&f8{jq6pIm(?vA1+FYeF1@l zNm9@Q9kFfe1G0^leE0(`enSfAcfz2YSvDSO#2}04FZ_zIyx58(EmvqzWkw=3-|l2V z33y>SxO4s3QNJYc%YQ-mQ(#a6s4R*gC=EpjbvV=o7N50WqN2zd$6M5h@5Lz*&-g z>b)6?`L+6w+DxxzoXzh+`ejp%rrgxj+9Lbe)VJ_Xc(y;aI$mQR%~~FtohDK}Z?;nd zBU{uebXk=SNVd{70cn(sHA?sy*k!!xk^UMcmctJyJwII4^VsjtbWRfAM~GIGvRd;C zTYN^TmN2cX#PnDn0RwgMnSUOlIIYPuuz&yfDrHHkurPwClL|1OIx zcDco&f_CbBj?z0yZ4=_A;cLqqpiq`m+9}SDDa8AHh-$QW{Cc`JD15$@L)-MNo_5zNvrtjd-cp_kK^mZ0Gw%Z4&gMhMOFN%QhaAzM06VkUY?^ z%putm<~d)jq3IEf5|BMHjXb0olCN~+(p&yhXiG5cn=4cir~4oOvJC#26Iv_ZhKI*3 zr`aTC(~B@~isjoQ-|7_=FF^nHx_E$5Go$;JJfxdO)2|7LeiK7lQL5tJWvh^w19h%gZC zHN716P#6U1t$c*TUo6Rb+PA||eGl0?^4s!rpGUs1_N!D&W8^pvNj_Tj5Mk7&qtN_< z!o|=>PnqmQrw&Dfy;o=%MzS75;GpN2^QF;ik_RDZZ1HJZ;vB+cv(nFq)o!O4V-g~l zsGggUV?Wn@*e;b(_Rj16RK?Q~X)>M(NHFqZK+#vYWfxb$ z%t59+(JAK_Sl%bfK&}4tA~iuY=0un$Pe?!7X_uxNt-l`p%D`KP0>qMxAHNptEm& zgW+j*)uTl_(*@G^o!>*Jw?&=0PyQ4h=n&N&!bkq>AH(Xse+BoiTfnol@Ewjx* z?je_4Ir;tvCXhuyR+3=yv%Iw`q32IXK!QS5_-JZowu-HmS=}RWH!@KvnZt${pgFa$ z);e{pkE;;KxXHtBI`&&ON_@uFQl*ji>PF6Ny_U#Uy}r`=>)!|C+;rr42ZpY%BB;I!Xk%u21%atmgTyuQ5q>6VIMWPXqRFd1?leC5M zQ>!)tC)q@)u4iG^TYIuu!RP!l148e2C&zovZ(3k(=GF8gFAD|B$e$cJlUkC|cxVLP zGlrpho9}4=|FmhA7Zr19sL_;LLFcm(1O>7;jm|6=tX-ETvS>7Veqt=U?5Lb14ADYr zyUy<(x5k;oWT9#HuSyJgjeJu2Q&Ji)t(Bd`};h&x_lzDY^G#|2kR}#a7DcBf_={;Rh~I?g{%h} z;68Qb_SEX49Nj`1qI2{V{bXb;6?rRBW<#vceIri}coS3rF9V&1I?pK=R#V)^aK1;^ z+h<2|%CPFBW)>10=ITJUza^%DQ`&ux5081Ae|n^ddXQ+^^QtG(?h6fBQo36q_e;M` zUP>rg5+3~G>!DTkBy4o_s?h9vtv|euQ9VhVY^&ZXKnMq-gH)#_iDkDP+6DhtdvE<0 zRoBIT1EPSm2q=vpAp#=ODM(9qmk5G%*H9wTN(&4v-Q5Gy-3&c6QZs}wz!2Z#bzRftO^u07FQFEeRa+RI`{xa3yHUqVKeR0|5slyO`6 zGIVbC*J5|N&Ks;9${tuGW~hZIYvfBZzvf1p%DXT(pIo>v-7T<$P;4>6{&-USn!i(_ z6M@&zijDozL~nK#!>(SK(zbZsFc)+&(otBna4Tu~S)lvFo|K~~6a|v+aV2(rI?JOX zW%g;x^;<1lY2Leo{c8gcZO~}_E*)_^*4^ySXGh?w42%>{G4Bo-nw_)*43`!!q?)qW ziFWjDbV8{SQB;JZ&K8aBd;PT7H|FKS{vrqA#*=!t-cXGszM#6ffQr@FFrBu`9}OBW z+S=XI&NUW2z|GFzx;h%*)Ydlkjl90>jEyb|#w9EC6Go2c5$?BedktLlLaenRly>z? z&Kyq}>w1Io%Vg_JYF%d4P9{?YK%|WW98IqmJ=PRmi>c3##1DR^=1ul%vI*PrRFB2k zKvfJQMbhGH3?3k3LO-EDM|XN1P@!Aonam?Zba!n6OmVsg^uyk$?YXKh6ux;>E>H=&(sT5K=MIx= ztG({`MK)DEX7T}?sCS)srYjpTI-~8quy8t(`dP6KkX;{A(k=4()NQ> z?Vz(Z;PDGtp*O|tUG*5GuVO{%Ju40im5H9=n(36a3`m5YXnk)PND?y#+nG=AkdZ@K zS~rge7_n!suTXm-;7|IjiqI#Le_)|eYCG3hE z7GXpWynI=cbb6XS#ri3?CdG*L=>i~H2rG|BJ4xRz$7=lB6%FG$(p*ftY#5rJK$5R5 z*Kj~q=aAdz|hSy?WSGk+5oMaJN4DWxLmEAM>On z1l1z=sH#xq#g?#uj93mG#pWoo4(TX9()K^R#TbZEPx)#hmW`@ zwaA?X-UrR`o#BQ$5aG(*k+ydu@#^fP2X)rnuE6 z3%Xi^HH^z0_7^JDTiADlT1pJ~?;Iiz^mV~a)#C$dC$pC6J2zj5J7k``9$fLh6Kjig zN~;13)8G0YjJuOzyCabF>0-e6I;XUGRh~z7p%B=04Z}9-iKZpd{?Tw(05o*e$9(L9 zmbKC$^C>*P$@uK%qeO+rp;?VdyLL_7*QdJa0-E*l3i>cRH|5m*7#9@*W+#nGpJ;Ql zE(b2-8tZSR>Q7W`pi?Z!&C?Xf;&Vdda-z9?E>|Xj6d0^l_m-N)NgN6b-cQ8vS#zGM zL@3%xy|~w6_yMU6JE8n&W^I49NF?sNtY4Ku?X6}f<+$=xij_Jt7;HKTj>hVbqJI?v znU=Jye54eZ)V&3F~-qHtjj_$Qs1qzkD%<;rK8RbDV5A=+XJrJZM=JRAr$!*@S3i+l{TYVH>n{ zDz<@g=+U>pFLtMb2(QWVcytdwyTh)Kq2Dso8?R1kMCiP0CPBTjahEjzTR3}Tc|CU-#niYvs%vVld!Vc-K>wHPiS z3{J=)=|7rh^~gRWsSZgrY$aLik`LdwM|$ETlaZF27IZDy5MpvwB02a}C(D%O+l4U?33 zI8c@E5eb6@)i+a&7VeAuOv#Y#KppcG_Sk(}T?hLYicbqWiSzDd2bveW*PDMz{SK2T zbiP+JqP4{4Rou2LG3Ho;NHT5!6C(x;SoDtxa{4_!7p~0f~ z{CA3HEcHYzv4l4(reM8W=}7re#y#&JnPSV?m;MAN5i$s?RoeR9uZEe+r50|mAd6dJ zl$ib79ey6YRninT8(MO&42$XEY`ZrmnQ{sW6TUy;cOI!+s}%Qkd%^bSYu^QfqUyyY z8{pF=MYWGO4@{@HcJ9XIIf9-oLCatn&{v9LsQ3G&Guj3e?gN-OrMPkaG53(sK7qo; z9r8(Ezp|n`UVKt})c$n6(UkX!ryTx)tTd66z?QGW4)$l{^hVG{prm1SL2lWLvD{7jJdqt6z^q#QVH8^vl| zT6N@d^BH4}G6B_!#_}pGn1s0B;^gVLFt47(x)*mCH8*Tmm`ltWBWjl~B2ZuNeZ`z> z#)zn~$(Cul1vMeNY=DSuse&RED&+#p-p4Z@$fD4L?E;IPQD@oFt_=df_VM+_AopDV z*Uv;{G~Rn$YcIf$HiF5G4t(sC^s^by!s(AUhmL`_1EMUmy>dxuOX?R^1yxbAEaVaH z4qmAJ8*4T!Q2Cea(Wl@}UpA$ubTo(NAg_&hZDGI!Wb$jzb%lg2`ZZdL@`@`?n1@!j z%Z9~~9rq&SzJ!|Lz@dEV`1i>jn=f&STjyV`7`K{PP=l_AS3vi$KcGGR!h2^18`H2! z01GLraQCTi(m@cjy3Oac=Z>M;`4)BSU%HD*aG8cv?5;{O)t+i`hqe^&O*gj3TgyAL zX<*jMOQD1h%NswHaCf zrjnmKj)z&VsT}pexB_RP5Zs{&ml9PW3I{~6`4%`xB`C&d%KDyO*s7Go{!LDElc-$sn@4;aXaSjZOU zs2?&19R1WbE;YE-#78d7jVACy=PG64iH*7q>s@mi&Lz{n` z*`yosLT1x~)I?&O&XzIN$Cm5ho zX8wLxcz*Rv!ZX@r(NdMT`5vQkJ|-US3uOoWW&&Hs*S!w@Jco**rwjK9RG6L=X1Tgp z7310|r7h=H4^%Ra>R|K&yT@fhbKE7ZksEL0f?7w%9iK(i4kB!g(1&?9;36K&8LvEB zJA|+A)R}^>W?PUyc-l6<`#!(O-+fGRtiai_KD(G&`*{u8TbB|OQyk{|>LCrETeEz8 zbCr&H*W@|f z>37pL**cHF$IPR6;b2nY+bT-e6~}qoqd$%{ZS~|^fE9tVG5|^o;8j9{DPWH#BxrG0 zOm>G1uJ8n)!6WDTUy~>iNT>=g@PkR8%aMHO*O6*sMzhE^xK9{cIuHL!1ZZsCFs2$! zWkZOcOHDqAA3TykC-`d8lKZ9c);3mYY${}FTsctC(5dfR%vNOx2%PWs5)P$r?NH;4c>s@_5l27oLLc3yoIN+0 z;nVfeU^7^gwtaRz2!evA_s_L`G|aG(a!KIcALEg0n()e*DkQ1;DRy>^6!9%^9o_A~ z=Ud2W9uYI&)8R2&mo>ZxUmHkZM+z2gnmc<;Pkv{=XNAHnkE7#6YRuEJ$jmTe)HCns zza7u%*Gc+EMXTp8p6@D&N5AfdN^5xzVsB8DwDufMaKW0$RhmdFHogHBY9p2kHPlc! zjCuKhfUD3O-T)WLr3c%+mh4DvRC6r9sP?)K5Aq^1_XHT0>_8qM^P5WV=p z&}Uk&+eFiD4NgujL`J7SGeV*wxQA8B4WcReln{K^Z!9bdT4LmJ0{hTdrifAr6RY!C zQrw*3(6TZ>WBN&SS~5$l!^_{bX{|d_6V`OX%kysh>qXKb);1%-CvSm;Zj%~0Giwwik=Wx+k zAOc2*Pv-_^1eE?FoCHiuisOaGV-fE8F~*4y6g<)sDVJAWHz-9D)esBTcB^CEL$^;*No7^CSa3qOK(jca4a%ZYY zlg>6XCMHJhgz(+kk~e}>>V-W0!L%~Ssjd`uX<5b6ifBQWT0*m=VEO1%=T<^MLA+h# z_S=z)3*IBA3 zV|MG_QTm+~F=2zeKD))n!lKd(JMfjm;q^$0{nRX?g+V24>EwVLry2`G#Y6rvwRR#0 zc;kkf${4X9;PfV%*aoz6`g*|rjWP3S)L*VBJ`E3dRCf9PnKK5b0k_&d&+#7ZzPDh2XHwr^}l9I84GyVZaJvW z9i=i-hLdxS@A^d3mQe>&SY$YWey+&q^}Uc$KrIImP8OB5?l=bX?sQ;w@R=Flk#?hQyp^#k5ANqLwav|oT^)`*;p7}aeXiHtEU--Xm0on*qP|OV=c5iI3mPUN z>~r=#_KS@~<8k?#CDV&4yG23Q5np8fLUXc}DNy89F`3&L6a;Yzvb=7O$V0w7UKUXR-k}b#NTzN&y1Kp{K{UTnX)2w6d8afa%ol^bthbuH zI=4!(hN6H{LDTx}84X!a|JJ}~pkuhkSKU#vf}7S&k1yyYJ6w16sS}WqlAXL@b5!JS znU(sIjAi59G%%;tRKK|T(scfG|E^tgd%|Y*lxCnF{tuWjJtG_738N zh89AK)4MxR0asYotku%g9wEVA%WW@r>g&JQ!)i;kC^wz(ZTUhhC0&m_-Vn(ukqvw+ zc7?S#7p;@vpMNl!p`#wwhV|IDCPl zfPFH`y(UxJe7O|3_3d~Mlf;ule4d9q*c595Z;3C9Yo;?kjl1VsAfT^s!YwaR~yf9x?F z(7P{AqV8piFy;Eb;_l|>GK!#F%lm_{68EM<0~0lx=J!xIDNb%z?$zl@!ab?2OW#Lh z%F@wcaA@j$=G^Ts`9)^oEyI*N@A`EKeOBp$yFY4IN+RPS3rk=M(n6Gl+kWE})kQ z?QwbeL7dV)0P@L}SCX45>xH|Tv;@sNzr1FB0tr}I)BV%mB!Ie-I90HVW6qk z$ScT1gS)twN%M4`0pJc%V`g9`CMM<|rK*9+`s|`L$6}uJzO7cQQKO&DyAQT}aq_{F`wkPK5J`+#tA1wT9`FCU0S3`O|K&%VwNZ*W<^Q znwpwCg|ScnU+7!B*sr9d3O<~jbqyqNB;VU14(=kKU2*ZbPfbm|Q&B1M|3p+hBk}(a zXURbAjVHaJVBv@D&)*&UW|@BX<+lkxgrK>I{|Fq#=@<(tXK72}W$$xtcseq_Z*Yey zDtwstkI(-NIH9A$%(x{%{z2(M)M-Z+nt4WWX@AI@1J7!VkhRJx#sBUMHaq$c&?tH) z?#J4VtyY1}%{S_-`%+Kw&8fkxZYlR|%-2gv(Q4$Mj z-`l$SHc6rr8j?Kpdi<7L%Fai83?y5R;Hx89B-KujjMqOItj4z7>MX zH9`HyQ~vp3)BwZ5J1R6(mCFsaO43usxzy_GE$6)Z9)51B?a$>8i13ecIzRBO-ix`A zS9`Nhu6@B=CX%QXj$smU4B>j?ciIMeqTvmzSxnFU-KmcHI zu^y=@<#CTU_Fn&)slUhYj827mTUW+gx~*tKfxKlkTW7{i>cj0BVK2(KfCz84|^%+6TtCLw@Om7r6iIwDt?%{I-h-ze>q_CgqxED>y!pO-cv0dGGFHXZ@+#eh(7i$ zHA^8Be|+O}t5$!J#Qh$%#LD}?aSFd7e5-j)^A?&mB?LXm#l^+rvb5x=e<7g$+d}^Z z#rxl{|NpT7kq<_~vUVTEzhmJXWq{*a?i=Zz8M}(P_v*!DHpWF$<6~wOoh%j=eN9sv zPJJoCBWe5l-OC>O)ad8NU1DrYsqzg}M@Dd$#v?Gt7ENA9MSkVN;dp<1_-SopfTnwr zu|&y9e+BH1>k*-2GASm%=qIDT;cQwIm2NbT^yjF+1wO#8(59=aS|M#zXKBH%2dz}R z4RL$Y)^6GVuU=*t5+%Lxyht}QH;0qjsNNrxijR+H?q}iVlT zGK=v2nas6}q@*OcRaSNJUWr9Gxxu`|(CrpI{ZX4Y!GBBuz}S-gYcIRIme7mr9UTu( zFE20mIr54M6$z7rfMt0U^8jL`r|0z=uTyhuY^>mjVvM0gd!hZ7H{?D3r+l=!k42rL zF~39QXYmh2N&Jre+m45hoP8Z-r2Y1$rYqOj+Z0VNF&K#?Fn~~dt`gYwxY1c7&Q>BC zZYU<|abV(x-9)6Kj;BFH#GCf7C3-(ryn6AP)AL6pkfg-JPCW@7CK*kL+T77vaSy=$ zCLZ0_vYqA7!Xh&+cb`Q&1{CkIX2oU;}Q~^pQUT<7tREqlb^o zhXTq-yM((A*{T(Ee*#;zJ+Mv0hFQFN;SqygHiv9!8;kXSi3Yp<35_$oWC}*yo%zWJ zXzfd4F!<4*)_NJ}a8z?Mv}IlId$yQI1MALrskSqvXRQq1r=q*76#%VMoX)>-o#MLe z)2(g(!jMkDB;pu%(AR|8&!V24%B%{JF3UDQ*(3SWr&o07fZG!C z#X=XeW2~&ovO&N8iigqd9(YJ?x)U%_emTh3#m8C9$u+}9@Vzn z!SO}B9{T|dr`!Ei{l!?4TLBv1$9n_+UT#hB%eDMN1AkrFhu8`qMy%Q@IPCjxUu7KC z!;TQ#ua2s4tbm{Nfdu#O(+&Y7g}Ar0LvJx{#3GWb=B=yry1|ap&)>>jPQ`-3hPC#v z>wA7ZK{XI<>9YC>nMirL-7hqGaRWy?Hf4M4tQ@!ljVBW_>1kBvb^6NdX-{D_=GunpA(PFAz)EMJj>_#U)7;)B)o)YM#m zjIIQd7HQLX??%=UywGSZ=;2Hf$euTJUl4utv={(*>JznymrJyO@~|A}$4baFe4(|fS9y$V5ua@XmUcC-tJPovvzzs~ z3`iF%FO{N<_}ss?x|V$hk7^XBEHfyCQS4&IJY_&W$Px^89SeT=c7wdbO#n>%?1Eyz z!@K2_*n!xE+{gE;v^;Ev@Q-&`C1Sq%y3cS6B5(Au#y$GIeIoRw=S$O|ly@=BUIVz( zrp@V(%f2|l{a)n>KAGQFOW-hclPzwpdD^5^ROy147HQQkTcQSdIe}7!-*Omxt}d5Q zGCnt0V!d~<@@HmrQiiOj;NKljXLymXuebBkSJI{)A+vYJ1$a10EJt!m4V#!AtaZQY z6~S0 zM;B>6AerG=`uTk&BhdD@MSwzg(lD%@qysumF~(1MW@;wb_EUEE3nt%GVBq&cH>|?j zSa^I}z)pl)UK!K4cW%!$ypAx913~Q|%q~*Wp;={#^tw9XJ4HQ##rdi{&Cbel`3zf) zi3xLuc@o~x-oKYG<$u?Ko$B&m3B?KnT^QT+xzQ6&;ZDvNsKnT;^*5@R=PD84&8tdZ z@lyy3%Cg_4xcTi`)t-G_f{Ce$%!kn3J^^K06vB@w2Zxd!D36jm_gaApECn~YA;`D^ z3=jcW@Nv&fF>j6O)kk%ptgH-bDELiX{^tjrHT8*!@l{}JFe~bjGrpfAf+8%e% zMg@icBmLQ%1CtW8ti_xhg3}d-5O;U8o52*5We^$+Q2&g%dAjo;lhfb&$>ei&KE!`wfoglNl6hg z#?Wf+RN0cBpMTWZmwGf+1YJMB8#DdQhTOXjzG$Y3Oc>I?3ns8ExslsLh?V*&5HX4l;%p3>sx?-lkpty$oCxBKwLy0WfYq31i^`m-{( z>q`veqW+4&zXDT+Cdp^4(^n7C{-)eqb$g4ey%l%;`e+tp)bEki-_IKt;^}cf9&pd6 z=KYP~sk7p*n8Qa>+p0!O6Q9o@NUs7P_|lE zS66&l>-EKS1Ff%trP)g3ZrQ%?tUCuK5jnZ`*0~@jLSvgGTCCM{@#3U>t|)J7@at1( zmwF2ef2iN}S~?RM8JU)W?+FjCqqvLVK(ycG8ahy1WtZDf>^KfLY;sOdJzjrX^*y3h z?0h}eGHWnlD8>17UrdGHc{8H5``p;KhHhTP{}y%L7|3~PV4$Ds#&;LeM0>Vz%QAz8 ztD~ovziB8%sEiEy&Qf{T2?}zWo|$c_Vszo^QdSG+h-983z!71(9xG(IZW6K3Qr4xS|3XuVql^)>4Y4~=$blTUi8Q};HqCnh;9fd*9v5fQ40 zI?~6-4VwYi!9pvPWQuISM?Y(5-JKl5>QTWe8;u)iZdQTpT%}b z-4sl2YVqici8UKK)tR)|FSVq~N11t|71>iCoOR>=tbDR`*qE<~ zgS?q(8cn;pl8yZmz^+cskY*FP1-3H5M_cmU`p_+>W$z;j=J{}o^jgpq>q3;v38CFzDu1VL1mysmOFi5d zuv(_G{gT47n{~~mT_(s{TCeBXx_2}na`!OV)uu}9s}N$jT{1-e0=b{!(V@tPzcbe2 zou&A?5vcfc-Mql3oEAGn!O9*8TbW?74Ao;YE2Xh`UK@|t_i+wFrw0c(Ax~S3VXbo_ z4|*UMJ4L?6zUNb8@*y3rbG^i@Rb>}9r*KU9q8%k7kC*J?q(#M2=v_>7MJyZ-92FNL zRh3_l$4-!d^Gj;ElB@OKnvKg%y2QZWnJ+YQ+bznuNQLw$KOp{n91;oJG6_yPCMIYg4Q)!S48|7aRt7bqv_ zFq|P4rBPjMHP1aF-1HtQv zxvbTx1*{Cm#2ldzH&Y?;n(;M#4%)wF@r(nl8u5?utSsATkqZc!9Uk?YNI@?R=!l|7 z!A+mKGV3SLhwg(jtqq=F?%ipOo_#E#;G6K8bT`C^;Bj$lXdjRh6oQTskgqrGSkB?x z61AMdH_d^ZJ}ar2Tq^1OjuMcHo``*3`|IYIpdoEavB1D4Bt(&y8y42T1H68EbXp8fW}@Y5*gEW?O{CQ}Q=g%|JV3w-P-*)` zWzCI;X-$Z)R5mngTw7pgyO((WLcvH;)X8oNd0p2wIpnOzQ;vJ>tknj)(w%uI25TLu zeB1l5nOZ2UNCGWY&=NJh-(((XWe~b;2%6nEl!==Bxk_tfaIt)gkX>$Ca$+-vv`8y{ z3A9_%)0N@1KE@C&2t)<%kr`)@lYs#sXRr9_cez|D;0lwowG-IQomWe*d%qL|;^TXe z>$Mg2&e;2;CfocoxtQNsVl?lP<2*H@XPK)Max%SFa!mG=rS&*UD7SMdNAkc+V^4?e zvRoy#?nT)P%(lbwh=V8xPcsUrd5Ks4RkTQ+rG~aP^b(2iMJ%q1tWL3M?_W&Vl-XV+ z%Fw_?%QG_cn@>kG8Jx0Rg;Hm@P4sIB14iUc&eA@Rzi~;aQ&FuO-{@5E}}T<0&0BY)t8G;sg5w>G^n@Q61%+Ia(0q9Xc2IE zt+_QSEfz)1oon-;h~G8ce1Cr}T5LKa*KadI%wG38p0rDj{qTSYn}-Zd?B_wpG0@&& z;1IiI_E(YKNFjOAhoyz)*qi1~hgkkx=F)kfH=no=zBfNdj$@bk8Vr1}+`Gay=0gZ6 zm)I`FemHDCwETHfZIol)qiJfD`z`aU*XhT|-GP{8J~?OcYyaWHxxNcgz2|v^=TAj7 zv_Q|PCM!soPsFaO-%-LYM;_|m3ksp}^jJw6Ggo_gSgh*}3BS}`-;#Z;j^@L-q-pW! zuZe*+p7If)j$jH2dnMa(kT^qc}>@ggn61HH4u zv#LB0+&M_;t6+_Z?pUSmG5OP(i|JzB6qtvvm*A)p^K@rOAbrrp`Po5sG%xQIo;#oj z6N*9OpVZ5>$pEUgk7srClZ%-Lf>;}eZ% zJy?!iatzt7WZZK|Uwi)TqUad5vUE5mr&H@k*(zygt=4#ht4;ZbEi1ma+vN1N#p$X1 zI+dXYzWbCXAuWA_{d=QL%IT>p>N5z)<&<$`sA7mYH#EHCKu8X4q0ShxPV=Ud%R1K4 z8hJZ`(#t0b-QmZICp_BkD4WE~1@VRA33D#BP(hfpk1>C1w4nFto-3iq(P&IA#@xDK z&>gZI1Qd{*x;>uX)ak0m zzQ@XFi%>@+P#$A8vV}?&+?p(CSnT=2@G-g<7i>c`Iko3E^vS>hIR2g%is} z-L$vhJS=y+{cwHsQO2cSf~}v zzgSc+I&yNZ0yud`s)wJ5@N$EOo-OSe)%cyj7?y;(4rtzKx&oj{z=M9}`A;#KxH(#W zj=y9E`>5S~|DGwbhAQY2Fl=(&bvfM<6LVQ^3oM0QH9=Bh-`l@`D7Y)X#qgp@32tg0 zl3N#_0AJVzZ~cst7NvSEKq*%`o3fhJ2UIZZr!bZ~ZG>rvr%x29H(olz@)kopUO({4 zA2ShyE98p$dTlNEjwmbb&DHE0br_}AZ&m^UJK+PGvx&2H06_I!%Ho>xz43u% z@#R4(R`c<$cfbp{+7C_dbi*lEf zA^zKZnAnpfEV#QBL1{B`i9-lnxVFw?8J zRq`cUdXrtZno$Jgd}Z@~=0L8*9wFK?5ukjvb_e?IwApl``>M4EOMm#{+zRgXAd6LO z`-{M3e(d3eO<7*@$;UaAi!QI-jE>iaruL8(oM$Hu8DHj8^9%=6R9I-8=6U*6%D(k* zGq-V#1%@0zH8KtL@1`{&w?3{tAia+#zX)rI7OJnADbP+ef5H$&^VNMdj$HmdPgvAv)8bIvK1zEuS@4l<{T{jN22M09?Uw4{MqlIM~<}p`%e00#Bw$92Z@7K~Wvdk9T94Uhk3L z`uU~>{`{wo2%WAm#Lf32^^Lyz0FZGN{7kMA5j65yk=k}IPUO^Y_1$lDEzn!oPzWEl z*j}tthPPc_N(T+-+cj9cUZoKXlXp$7DQm`KrAl=p1e=nI9G=Cl@a&Lo+jJ3>-wpA( zq;bD;DdZM~2MF5H&h(OPjm=_d)8^cmW9qVwx`B~u znmqHXJnB`iRAnJwy_Yf4l@SQ+GQ%p4sb)Sqwnfe93?y6$*on}$;7H;t%c-n<9`Ck? zf3XWJ!lp4=mCdVRoP_e$MQaX96R?>ZrP^fu;q^JJCgH7S=L^_zthbVEGH}i;tS8OK z$27){Dp4RRoC<2reFT)h*fYfV_Bma49xjduA4kxKdQ(|HnT1Y1pFGW5OB-D~HbU|e zd~rD*;)?{{%F5HK^MPxMpzznz%(OzDWhUN$%y|*O+%~&BOQ))X3^XD|(_#~$JVFU< ze&V1y^*lwJgTjslBup8CY$`Hy4}yHVYO(Vc<+w^O5n*5v`ei=A50{_eb`q2h-#wlo zB5EcxE76$fY4p51Z?0(KmK00TUR=)3Mm4{z;4njDgB21i0M{paJ3$k`pQ=iQ#mh?{ znR0}+;T{Ek+j4M;yE_6|zWhGv(N0eU97=-_IKR0>Sdwva=&3nrL>mc^8#~FF`XHaD zk@#?@`5kt}A0A`T4lmM-7ex+v;$jhQJ0ipugwBD@Hlx~i6S+rYnYG9`bup+|)D&fO zl-vP7_td_j4s2WFo(t7Xwgdt{U00d13-aJ<>lour|fNzw$J%MHtOg8 z#QDB%6`w1%0F98FK^ZP*vxCQLPNj)FW#b0d-P##}IgsKI`xfYN>sAKGipZ|M8 zb!0mM%ER1@oEKnY^DcAuG4{JUAw@J_DP8o0cnkySRKv1R-GYz7rSM5yEY{T-oYu1C z=xD&E-z`B?IrT-wRu{Rk@S|-H>%P^;`fDochcmv4McO5^0$!6pG{gm1@i>1D*&AsJ z+P8mSHI>9Y&Q$^nn#_!vw(O*do#ez`6dP8#Ax~}RpO8P*D__fsz*TQrd(iB@=nDPd zx(kgz*%{;Bs#hU_X)GJ?wKS$9T@mCQM%A_^?QI%cCVWPIS2?Y|UYtJm!>D<|E!RF_ z-ngqvT#ipSW$F_#QsFH(DJE2HYG^)aIs}jZ&abe2$S~+XEs_Nmp40DFm|puNrN3Jj z^dqUA+HX0fJWO&}I$pVSU)$mjK6yZwPO@3=!?$Ns$-GhyF;r^m?|)+6qfv1H5c8qZ zAJO)}%UY<>GMZH6Ra2{<#MUsl%E|e-^5z0^?b=L>pPOiW9c@u%*%DtEI$!OmE~UdM zk1>t2){RU#=s3KhNWIT{xkAXv&c0MDLVDJ%)UYa4dUfHqfchCsZot3#3s`}Tey|%Y zdNEVU+N1pN^UoQd>4%nN-3_2*8?Cb0!_HV`DiwS`=KFGR>m9bfG=iagEO^(YeJ!qJ*iN#Jq0{Z^w9WL|H%0axXg0aG%A6ubG}5s}Ri(+AE;@2Rx?zWLPhhyc4q0XzK`OTS8fZl6y)9}dCO z+oqyfd2`8g5jlMhuKA`V`7HJ`_%0#=Ln(ZDe)svk)_aYBR6=SZ!0cinE>sMKpl|VRkfdd3ec=(onmdwuA+9^O8wKcV;y9v@( zx#BlA@b&I6Zt>Qo_MJzv5A?fFz0kZ~2ShH%b38Wk5?ktQ_KoNB+!VN=SaXOUlyLKU zvkvmrSW|a)8T4^?av0y75$4zfwl6cT6J5M)c;fOlAr8`fw8pd}=XEGD=KvFBVP$=% zqTkA#bU6^ox5&?MXR1#?PL|TIy8h~P9=22tG7n1LJmWiTyF~~p_d403K5TYatVXrM zWz>k;9KsjulrZ!LDTN{6$YNQd1~oDZ2@u zR0!s6E1VHe7E6^fYh}B=O>DIo#1tFNA9LQq)>UPSLw0! zQAORD@5&>(<3MrIxoQ1viEd5f`=!A1$H18q_<=tgw_coh8Y4xkM-k5)$8%`bdZH0u z;=fK+H0BmEMZ_CaJa<`$|4Fc@(HLUm4FX*^9L|-s9H|vWap}8m5=tmuX}v?yVFUvy)%&0 z!<-8c*T?a1xwSxW{ebk#-?Pd}2!q}M{19Vq1{0}Znntu~{{5o4JOZrSwK-hz@GV|c zQ?RFOQqSJkwIbUJt-bBf-Ie7per2)ZBIxK2B1A>MpYl7{i7;k7>3%hPn_%tY5CpA-30 z{#v-{F!6$1h&+^jhw;B#sbv6K6++4@{oN`$Mu;Zeiyk{C?2L|NE^=n^3{C9nV9O6^ z^_rIjy_o+b0U0N_A2w$S(CT>^cs3n&N6M-0(K*Os##l-mMes9{+ipr>wheu7ruhBw z7Mu@r;F)7E1jx|VoDPaGmEJvvV&#*t6CfXLGuvn}L?rWgJ9$0M;Pwep_NWtzXG z>??l{T$%-QeB^`3$R|n1p|?hoXbZ3T^L{@u%%zCuFS15k3=i%lEiUz!He+JHVE-&k z5@Y#lLWbsA1Y^0wk8u6(?2m|UlnK+?+B)1^nwz^yur3sDfDyRiSAX|J(rN6i(X0Qy zxT3A1>QiSoH!b9;mfOZ-@r-u?si~=x-1MH(FMQWmU<_!Ymq>Af|2!~DWaKtp3?+>z z34o)lNggK1VPF!3iYvLf?R@<#%s|j5mEuW^?!dj0D*aENtn4x3H>RRLK8L=sv_t|= z(UW+MEm!C)oB`69t5tNOB;QMufm@f3vKC3fY%AF^>c#nOCr#YutJ9Q$Cr_Sieo*}^ z`18k-xl7S-@gVW9!T9UDPdcjTMSrzQxcUfVIjGI~$?xyB;Am(k7?OB-mF!FwO!xzF zhqSith>a5+BOSZbQrw5E(^3N4zwGLb^6u3eyt-*``}K%_7M#%?Osx{V8d1OH&&{L6 z(*>Ec<_MKTbyDkK^%lvx#=(9f;38ke@j%B%M`|^YCildf_tS&hH>Y0>i*J*Vq1Dml z=KQwT{!5doev2})`*;sy zgOASq^n}6}Az*?67VjBg{RlE8kkx6qc$h0+;8DyfqeiFIIIoOYZ& zaF*qqs-a;`Q)6T9^X%H(MyBfMz0W|>=(=HK2h1M%4BqTo$({pRp=`;X!NI|(S;tfu z|E2C8x~Q86=`GmIp1|bg^&?D39bdeX%>oCSU8K8I+VA_YePyyUIl*MPwJv;bb4?=Q zgmXd~p7Q=4KX$;GIW%>Kwr%h$H%#o43&B7E;F90rS-+<#gTgY91W+a{vL5%V7`x~J zlClu@y_rmze8!!)FJtuFPldYWm-(r6ziClm$fSv%K`3sjx}_AQrEOhx5}=clWYEd! z`(2KpH5D1#%(^WG#4ro-KcoEHEdL~Kf6e&+{p)|$`0cg-_~8E)E^)JMvy6sz+d=Nt zOO5~e?f<6g?;QI73g`TvL;lYp|G(#uK3W(zwCXQ#AK&Hh0yr#aXmV0YuSz9M0{;)R ClP^O6 literal 0 HcmV?d00001 diff --git a/docs/assets/plugin-executable-layout/after-path-480-light.png b/docs/assets/plugin-executable-layout/after-path-480-light.png new file mode 100644 index 0000000000000000000000000000000000000000..7cceae53010a5d369df51c4091b1e04b53de5943 GIT binary patch literal 37533 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 C^*Ry& literal 0 HcmV?d00001 diff --git a/docs/assets/plugin-executable-layout/before-detail-700-dark.png b/docs/assets/plugin-executable-layout/before-detail-700-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..9fd8e40dd06b5d741f3c5c0b52103f01d441a6a8 GIT binary patch literal 99547 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 literal 0 HcmV?d00001 diff --git a/docs/assets/plugin-executable-layout/before-detail-700-light.png b/docs/assets/plugin-executable-layout/before-detail-700-light.png new file mode 100644 index 0000000000000000000000000000000000000000..11bbe32576616d62b18f645379b98871335a203c GIT binary patch literal 96324 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

Zt+Jk+#1076WIy44GQO-g;X; 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 literal 0 HcmV?d00001 diff --git a/docs/assets/plugin-executable-layout/before-path-480-dark.png b/docs/assets/plugin-executable-layout/before-path-480-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..a343f436fb20d1aa1f330a1116e72b39817ec264 GIT binary patch literal 27390 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 OWOxN~x%i@O@P7b*%1K%P literal 0 HcmV?d00001 diff --git a/docs/assets/plugin-executable-layout/before-path-480-light.png b/docs/assets/plugin-executable-layout/before-path-480-light.png new file mode 100644 index 0000000000000000000000000000000000000000..3674bf8091a90cbdc7e3e0195abee71c8a1acc4d GIT binary patch literal 27334 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 Dx%*~M literal 0 HcmV?d00001 diff --git a/docs/plugin-executable-layout-visual-check.md b/docs/plugin-executable-layout-visual-check.md new file mode 100644 index 0000000000..a4bac975be --- /dev/null +++ b/docs/plugin-executable-layout-visual-check.md @@ -0,0 +1,48 @@ +# 插件路径控件和详情分栏的原生截图 + +以下图像使用 `PluginSettingsLayoutTests`、`PluginDetailLayoutTests` 中相同的 +SwiftUI/AppKit 视图、示例数据、尺寸和主题。原布局取自 PR 基线 +`fe0b31c71f692bbb60bf938da9c47498bbd1d0ec` 的三个视图文件;当前布局包含 +`fc653d5c0` 和 `589906520` 两个独立 UI 修复提交。此次 Runtime/Provider 修复 +没有继续修改布局实现。 + +截图由原生视图绘制生成,测试宿主的左栏是占位文字;不代表完整产品窗口或 +真实桌面合成验收。前后图均在初始未滚动的位置采集。原布局只用于渲染对比; +当前布局另外运行完整的几何、输入实例、横向滚动与路径选择断言。 + +## 路径控件,480pt 宿主 + +原布局里的输入框固定占宽,按钮文字被挤掉。当前布局保留选择按钮的自然宽度, +标题与输入框随可用空间缩短,右侧的作用域与生效标签仍可见。 + +| 主题 | PR 基线 | 当前布局 | +| --- | --- | --- | +| 浅色 | ![浅色原路径控件](assets/plugin-executable-layout/before-path-480-light.png) | ![浅色修复后路径控件](assets/plugin-executable-layout/after-path-480-light.png) | +| 深色 | ![深色原路径控件](assets/plugin-executable-layout/before-path-480-dark.png) | ![深色修复后路径控件](assets/plugin-executable-layout/after-path-480-dark.png) | + +## 插件详情,700 × 700pt 分栏宿主 + +原布局的详情内容越过分隔线进入左栏。当前布局接受分栏宽度,内容留在分隔线 +右侧;窄设置表单可横向滚动。回归还验证 900、1000 和 1100pt 宽度,以及 +窗口高度变化时的顶部对齐和输入框实例保持。 + +| 主题 | PR 基线 | 当前布局 | +| --- | --- | --- | +| 浅色 | ![浅色原插件详情](assets/plugin-executable-layout/before-detail-700-light.png) | ![浅色修复后插件详情](assets/plugin-executable-layout/after-detail-700-light.png) | +| 深色 | ![深色原插件详情](assets/plugin-executable-layout/before-detail-700-dark.png) | ![深色修复后插件详情](assets/plugin-executable-layout/after-detail-700-dark.png) | + +## 验证出口 + +在仓库根目录运行完整断言及当前布局截图导出: + +```sh +LITHE_PLUGIN_SETTINGS_LAYOUT_CAPTURES="$PWD/.artifacts/plugin-layout-check" \ +LITHE_PLUGIN_DETAIL_LAYOUT_CAPTURES="$PWD/.artifacts/plugin-layout-check" \ + ./.agents/skills/write-stable-tests/scripts/test-stability-macos.sh -- \ + --filter 'PluginSettingsLayoutTests|PluginDetailLayoutTests' +``` + +标准导出的详情图在横向滚动到末端后采集,便于检查右侧设置是否仍可访问。 +本表另在同一视图布局完成后、滚动前采集,以保持前后位置一致。 +截图是文档静态材料,不被产品加载,也不进入应用资源包、安装目录或工作树 +资源复用清单。测试窗口由各用例关闭,不保留临时应用或后台进程。 diff --git a/macos/Sources/Lithe/Platform/MacOS/Build/MacBuildToolResolver.swift b/macos/Sources/Lithe/Platform/MacOS/Build/MacBuildToolResolver.swift index 7f2e75a92e..019f5a81f8 100644 --- a/macos/Sources/Lithe/Platform/MacOS/Build/MacBuildToolResolver.swift +++ b/macos/Sources/Lithe/Platform/MacOS/Build/MacBuildToolResolver.swift @@ -138,9 +138,17 @@ final class MacBuildToolResolver: BuildToolResolving { case .terminalFailure(let message): throw BuildToolResolutionError(message, terminal: true) case .resolved(let choices): for choice in choices { + // Probes and execution need the same PATH, including helpers + // next to a selected runtime. Failed candidates must not + // contribute their environment to the next choice. + var selectedEnvironment = environment + if let javaHome { selectedEnvironment["JAVA_HOME"] = javaHome.path } + let directory = choice.url.deletingLastPathComponent().path + let path = environment["PATH"] ?? "" + selectedEnvironment["PATH"] = path.isEmpty ? directory : directory + ":" + path if !choice.executesProjectCode, let minimum = dependency.minimumVersion, let arguments = dependency.versionArguments { - let output = await probe(choice.url, arguments: arguments, environment: environment) + let output = await probe(choice.url, arguments: arguments, environment: selectedEnvironment) let check: BuildVersionCheck do { check = try checkVersion(dependency.id, output) } catch { throw BuildToolResolutionError(error.localizedDescription, terminal: choice.terminal) } @@ -150,10 +158,7 @@ final class MacBuildToolResolver: BuildToolResolving { continue } } - if let javaHome { environment["JAVA_HOME"] = javaHome.path } - let directory = choice.url.deletingLastPathComponent().path - let path = environment["PATH"] ?? "" - environment["PATH"] = path.isEmpty ? directory : directory + ":" + path + environment = selectedEnvironment return choice.url } } diff --git a/macos/Sources/LitheCoreContracts/Execution/BuildSystemContracts.swift b/macos/Sources/LitheCoreContracts/Execution/BuildSystemContracts.swift index 1a181e3fcb..84f5384aa5 100644 --- a/macos/Sources/LitheCoreContracts/Execution/BuildSystemContracts.swift +++ b/macos/Sources/LitheCoreContracts/Execution/BuildSystemContracts.swift @@ -455,6 +455,16 @@ package struct BuildInvocation: Equatable, Sendable { package let versionArguments: [String]? package let minimumVersion: String? + /// After resolution fails, a provider must not discard a configured tool + /// or runtime by doing its own lookup. Check this only on failure: an + /// earlier successful candidate still wins over a later setting. + package var hasExplicitExecutableSelection: Bool { + (executables + runtimeDependencies.flatMap(\.executables)).contains { + if case .setting(_, let path) = $0 { return path.map { !$0.isEmpty } ?? false } + return false + } + } + package init( executables: [Executable], environmentInputs: [String] = [], runtimeDependencies: [RuntimeDependency] = [], versionArguments: [String]? = nil, diff --git a/macos/Sources/LitheExecutionModule/Services/BuildSystemService.swift b/macos/Sources/LitheExecutionModule/Services/BuildSystemService.swift index c6cd19c265..04f6d9b90b 100644 --- a/macos/Sources/LitheExecutionModule/Services/BuildSystemService.swift +++ b/macos/Sources/LitheExecutionModule/Services/BuildSystemService.swift @@ -1288,7 +1288,9 @@ package final class BuildSystemService: ObservableObject { } catch is CancellationError { throw CancellationError() } catch { - if (error as? BuildToolResolutionError)?.terminal == true { throw error } + // Runtime resolution can fail before the selected tool is visited. + // Delegating then would lose the invocation's explicit selection. + if invocation.hasExplicitExecutableSelection || (error as? BuildToolResolutionError)?.terminal == true { throw error } if canAppend(owner) { appendOutput( "\n" + String(localized: "The provider looks up the build tool itself: \(error.localizedDescription)") + "\n", diff --git a/macos/Tests/LitheTests/BuildToolProviderResolutionTests.swift b/macos/Tests/LitheTests/BuildToolProviderResolutionTests.swift new file mode 100644 index 0000000000..94e7454301 --- /dev/null +++ b/macos/Tests/LitheTests/BuildToolProviderResolutionTests.swift @@ -0,0 +1,174 @@ +import Combine +import Foundation +import LitheCoreContracts +import LitheExecutionModule +import Testing +@testable import Lithe + +/// Exercise the real Core plan, native resolver, and service together: an +/// earlier runtime failure must not let a provider discard a later selection. +@MainActor +struct BuildToolProviderResolutionTests { + @Test(arguments: ["tool", "runtime", "empty"], ["missing", "old"]) + func runtimeFailurePreservesExplicitSelections(selection: String, failure: String) async throws { + let root = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString) + defer { try? FileManager.default.removeItem(at: root) } + try FileManager.default.createDirectory(at: root, withIntermediateDirectories: true) + try Data().write(to: root.appendingPathComponent("build.fixture")) + if failure == "old" { + let executable = root.appendingPathComponent("runtime") + try Data("#!/bin/sh\nprintf 'runtime 1.0\\n'\n".utf8).write(to: executable) + try FileManager.default.setAttributes([.posixPermissions: 0o755], ofItemAtPath: executable.path) + } + let source = try Self.source(root: root) + let settings: [String: ToolingJSONValue] = [ + "toolPath": .string(selection == "tool" ? root.appendingPathComponent("missing tool").path : ""), + "runtimePath": .string(selection == "runtime" ? root.appendingPathComponent("missing runtime").path : "") + ] + let planner = RustBuildSystemOperations(core: RustCoreBridge()) + let runtime = ProjectRuntimeService(runtimeLocator: ProviderRuntimeLocator(root: root), store: ProviderEmptyStore()) + let resolver = MacBuildToolResolver(runtime: runtime, processRunner: MacProcessRunner(), fileStorage: MacFileStorage()) + let target = BuildSystemTarget(manifest: source.manifest, buildSystemID: "fixture") + let invocation = try planner.invocationPlan(target, root: ".", settings: settings) + // Verify the exact review scenario: failure happens in the first, + // automatic runtime, before any explicit candidate is inspected. + do { + _ = try await resolver.resolve(invocation, displayName: "Fixture", workspaceURL: root) { id, output in + try planner.checkToolVersion(target, runtime: id, output: output) + } + Issue.record("The prerequisite runtime must fail") + } catch let error as BuildToolResolutionError { + #expect(!error.terminal) + #expect(error.message.contains("Prerequisite runtime")) + } + let providers = ProviderRequestRecorder() + let service = BuildSystemService( + planner: planner, tools: resolver, optionsStore: MacBuildOptionsStore(store: ProviderEmptyStore()), + stateLocator: ProviderStateLocator(root: root), runner: ProviderUnexpectedCommandRunner(), + providers: providers, settings: { _ in settings }, sources: { [source] } + ) + defer { service.stop(); runtime.closeProject() } + service.reset(workspaceURL: root) + try #require(await Self.wait(service) { $0.first?.modelState == .notLoaded }) + let id = try #require(service.entries.first?.id) + service.loadModel(id) + try #require(await Self.wait(service) { + if selection == "empty" { return $0.first?.modelState == .loaded } + if case .failed = $0.first?.modelState { return true } + return false + }) + if selection == "empty" { + #expect(providers.requests.count == 1) + guard case .object(let params)? = providers.requests.first?.params else { + Issue.record("A provider request must have object params") + return + } + #expect(params["tool"] == nil) + } else { + #expect(providers.requests.isEmpty) + guard case .failed(let message)? = service.entries.first?.modelState else { return } + #expect(message.contains("Prerequisite runtime")) + } + service.loadDependencies(id, project: nil) + try #require(await Self.wait(service) { + if selection == "empty", case .loaded = $0.first?.dependencies["."] { return true } + if selection != "empty", case .failed = $0.first?.dependencies["."] { return true } + return false + }) + if selection == "empty" { + #expect(providers.requests.map(\.method) == ["lithe/build/model", "lithe/build/dependencies"]) + guard case .object(let params)? = providers.requests.last?.params else { + Issue.record("A dependency request must have object params") + return + } + #expect(params["tool"] == nil) + } else { + #expect(providers.requests.isEmpty) + guard case .failed(let message)? = service.entries.first?.dependencies["."] else { return } + #expect(message.contains("Prerequisite runtime")) + } + } + + private static func wait(_ service: BuildSystemService, until predicate: @escaping ([BuildSystemEntry]) -> Bool) async -> Bool { + let finished = TestGate() + let observation = service.$entries.sink { if predicate($0) { finished.open() } } + defer { observation.cancel() } + return await finished.waitUntilOpen(timeout: .seconds(5)) + } + + private static func source(root: URL) throws -> BuildSystemPluginSource { + let fixture = DeclarativePluginTestSupport.repositoryRoot.appendingPathComponent("shared/contracts/plugins/v1/fixtures/build-tool-path.plugin.json") + var manifest = try #require(JSONSerialization.jsonObject(with: Data(contentsOf: fixture)) as? [String: Any]) + manifest["requires"] = ["buildSystems": 1, "buildProviders": 1, "executableResolution": 1, "settings": 2, "serverProcess": 1] + manifest["permissions"] = ["process.build", "languageServer.launch"] + var settings = try #require(manifest["settings"] as? [[String: Any]]) + settings.append(["id": "runtimePath", "type": "file", "title": "Runtime", "default": "", "scope": "global", "effect": "reload"]) + manifest["settings"] = settings + var systems = try #require(manifest["buildSystems"] as? [[String: Any]]) + systems[0]["invocation"] = [ + "executables": [["kind": "setting", "settingID": "toolPath"]], + "environmentInputs": ["FIXTURE_RUNTIME"], + "runtimeDependencies": [ + ["id": "prerequisite", "displayName": "Prerequisite runtime", "minimumVersion": "2", + "executables": [["kind": "environment", "variable": "FIXTURE_RUNTIME", "path": "runtime"]], + "version": ["arguments": ["--version"], "pattern": "runtime ([0-9.]+)"]], + ["id": "selected-runtime", "executables": [["kind": "setting", "settingID": "runtimePath"]]] + ] + ] + systems[0]["model"] = ["source": "provider"] + systems[0]["dependencies"] = ["source": "provider", "scopes": ["workspace"]] + systems[0]["provider"] = ["launch": ["kind": "packaged", "path": "provider"], "executesProjectCode": false, "mayUseNetwork": false] + manifest["buildSystems"] = systems + let descriptor = try DeclarativePluginTestSupport.descriptor(manifest) + return BuildSystemPluginSource(pluginID: descriptor.id.rawValue, manifest: descriptor.normalizedManifest, + packageURL: root, buildSystems: descriptor.buildSystems) + } +} + +@MainActor +private final class ProviderRequestRecorder: BuildProviderRequesting { + var requests: [BuildProviderRequest] = [] + func send(_ request: BuildProviderRequest, to target: BuildProviderTarget, timeout: Duration) async throws -> ToolingJSONValue { + requests.append(request) + if request.method == "lithe/build/dependencies" { + return .object(["format": .string("litheDependencies"), "version": .integer(1), "dependencies": .array([])]) + } + return .object(["format": .string("litheBuildModel"), "version": .integer(1), + "projects": .array([.object(["path": .string("."), "name": .string("fixture")])])]) + } + func retainProviders(_ keep: (BuildProviderTarget) -> Bool) {} +} + +private actor ProviderUnexpectedCommandRunner: BuildCommandRunning { + func run(_ request: BuildCommandRequest, onOutput: @escaping @Sendable (String) -> Void) async throws -> BuildCommandResult { + Issue.record("Provider loading must not run a build command") + return BuildCommandResult(termination: .exited(1)) + } +} + +private struct ProviderStateLocator: BuildSystemStateLocating { + let root: URL + func workspaceStateDirectory(pluginID: String, buildSystemID: String, workspaceURL: URL) throws -> URL { root } + func allocateOutputFile(in workspaceStateDirectory: URL) throws -> URL { root.appendingPathComponent(UUID().uuidString) } + func removeOutputFile(_ url: URL) {} +} + +private struct ProviderRuntimeLocator: RuntimeLocator { + let root: URL + func environment() -> [String: String] { ["FIXTURE_RUNTIME": root.path] } + func discover() -> RuntimeDiscoveryResult { .init(javaRuntimes: [], mavenRuntimes: []) } + func validJavaHome(path: String) -> URL? { nil } + func javaRuntime(at homeURL: URL) -> JavaRuntimeCandidate? { nil } + func isExecutable(at url: URL) -> Bool { false } + func systemMavenExecutable() -> URL? { nil } + func mavenExecutable(forHomePath path: String) -> URL? { nil } + func mavenRuntime(at executableURL: URL) -> MavenRuntimeCandidate? { nil } +} + +private struct ProviderEmptyStore: KeyValueStore { + func data(forKey key: String) -> Data? { nil } + func object(forKey key: String) -> Any? { nil } + func string(forKey key: String) -> String? { nil } + func stringArray(forKey key: String) -> [String]? { nil } + func set(_ value: Any?, forKey key: String) {} +} diff --git a/macos/Tests/LitheTests/MacBuildToolResolverTests.swift b/macos/Tests/LitheTests/MacBuildToolResolverTests.swift index 24d8c1f3a2..4f425f3ac0 100644 --- a/macos/Tests/LitheTests/MacBuildToolResolverTests.swift +++ b/macos/Tests/LitheTests/MacBuildToolResolverTests.swift @@ -116,6 +116,39 @@ struct MacBuildToolResolverTests { } catch let error as BuildToolResolutionError { #expect(error.terminal) } } + @Test + func customRuntimeProbeAndExecutionUseTheSameSiblingHelper() async throws { + let root = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString) + defer { try? FileManager.default.removeItem(at: root) } + let executable = root.appendingPathComponent("custom runtime/runtime") + let helper = executable.deletingLastPathComponent().appendingPathComponent("fixture-helper") + try FileManager.default.createDirectory(at: executable.deletingLastPathComponent(), withIntermediateDirectories: true) + for (url, script) in [(executable, "#!/bin/sh\nexec fixture-helper\n"), + (helper, "#!/bin/sh\nprintf 'fixture 2.0\\n'\n")] { + try Data(script.utf8).write(to: url) + try FileManager.default.setAttributes([.posixPermissions: 0o755], ofItemAtPath: url.path) + } + // The injected environment has no PATH entry for the helper. Only the + // candidate-specific environment can make this version probe succeed. + let runtime = ProjectRuntimeService(runtimeLocator: BuildProbeRuntimeLocator(home: root), store: BuildProbeEmptyStore()) + let runner = MacProcessRunner() + let resolver = MacBuildToolResolver(runtime: runtime, processRunner: runner, fileStorage: MacFileStorage()) + let invocation = BuildInvocation(executables: [.runtime("custom")], runtimeDependencies: [ + .init(id: "custom", hostManaged: false, minimumVersion: "2", + executables: [.setting(id: "runtimePath", path: executable.path)], versionArguments: ["--version"]) + ]) + let resolved = try await resolver.resolve(invocation, displayName: "Fixture", workspaceURL: root) { id, output in + #expect(id == "custom") + #expect(output == "fixture 2.0\n") + return BuildVersionCheck(satisfied: output == "fixture 2.0\n", version: "2.0") + } + #expect(resolved.environment["PATH"] == executable.deletingLastPathComponent().path) + let request = ProcessRequest(executablePath: resolved.executableURL.path, arguments: [], + environment: resolved.environment, timeoutMilliseconds: 2_000) + let output = await Task.detached { runner.run(request).output }.value + #expect(output == "fixture 2.0\n") + } + @Test func languageImportDiscoversWrapperWithoutExecutingItOrRuntimeProbes() throws { let root = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString) diff --git a/shared/contracts/plugins/v1/README.md b/shared/contracts/plugins/v1/README.md index 686b3fdd92..3b66a6332a 100644 --- a/shared/contracts/plugins/v1/README.md +++ b/shared/contracts/plugins/v1/README.md @@ -1498,8 +1498,15 @@ resolver's fallback-to-default behavior. Project overrides never select tools. The host checks file permissions and versions: a configured failure is terminal, including a failure to probe, and must not fall back to subsequent candidates or a Provider's own lookup. Paths with spaces remain single paths. The selected -setting's directory precedes PATH. Provider hints and task/test execution use -this same plan/selection mechanism. +setting's directory precedes PATH. Runtime candidates construct their environment +before version probing and reuse it for execution; a rejected candidate's +environment does not leak into the next choice. Provider hints and task/test +execution use this same plan/selection mechanism. If resolution fails before a +configured candidate is reached (for example, an earlier Runtime is missing), +any nonempty setting in the tool or Runtime candidate sets still forbids the +Provider's independent lookup. All-empty settings retain automatic-discovery +fallback. This check applies after failure, so an earlier successful candidate +is unaffected by a later unused setting. Optional metadata applies within **one candidate set owned by one plugin**: diff --git a/shared/platform-feature-matrix/features/build-system-plugins.json b/shared/platform-feature-matrix/features/build-system-plugins.json index 310b844704..e6b33c26de 100644 --- a/shared/platform-feature-matrix/features/build-system-plugins.json +++ b/shared/platform-feature-matrix/features/build-system-plugins.json @@ -26,7 +26,9 @@ "macos/Tests/LitheTests/PluginMarketplaceServiceTests.swift", "shared/contracts/plugins/v1/fixtures/build-tool-path.plugin.json", "rust/lithe-core/src/plugins/executables.rs", - "macos/Sources/LitheCoreContracts/Execution/ExecutableResolution.swift" + "macos/Sources/LitheCoreContracts/Execution/ExecutableResolution.swift", + "macos/Tests/LitheTests/BuildToolProviderResolutionTests.swift", + "macos/Tests/LitheTests/MacBuildToolResolverTests.swift" ], "implementationStatus": "partial", "verificationStatus": "pending" @@ -41,5 +43,5 @@ "verificationStatus": "not-applicable" }, "owner": "Extensions", - "verification": "macOS 已接入 static、command、hostIntegration、provider 四种模型来源:宿主向 Core 声明 buildSystems 与 buildProviders 能力,插件市场因此列出兼容的 API 3 声明式和 Provider 版本;Provider 进程按插件、构建系统和工作区各自独立,经各自 stdio 用 JSON-RPC(LSP 基础协议)与宿主通信,initialize 协商 capabilities.experimental.litheBuild 后宿主才经 lsp.buildRequest 发送 lithe/build/model、lithe/build/dependencies,回复交给 Core 解码;共享写法只复用同一插件的语言服务器会话;进程只在用户加载模型或依赖时启动,切换工作区、关闭项目窗口、停止执行模块、停用或更新插件、退出应用时停止;ExecutionFeatureGraph.stop 经 BuildSystemService.stop 同时回收已就绪和初始化中的 Provider,停止后的初始化完成也不得重新登记会话;状态写入插件状态目录;每个已启用的构建系统插件在打开工作区后各有一个右侧工具窗口(标题为 displayName、图标为 icon),不依赖识别结果,工作区没有对应工程时窗口内显示未检测到该构建系统,工具栏放运行、参数任务、刷新和 presentation=toolbar 的开关,树顶部是 presentation=tree 的勾选选项,工程下按 category(缺省按 group)分级列出任务,再列测试、目标和依赖;内置 Maven 窗口与共享 Build 窗口已删除,Build Output 显示输出、诊断与测试结果。窗口恢复先激活所属插件模块,激活中的命令面板项禁用;参数任务遵守 workspace/project/target 作用范围与目标标签,模型或工作区变化后清除旧选择。隔离回归覆盖这些边界、窗口布局恢复及包内图标读取前后文件清单与字节不变;多实例的根目录选择器保留每个实例的模型候选和生效值,编辑多选时保留兄弟实例独有的已选值;显式清空按实例根持久化为空覆盖,检测、同步指纹、任务计划和语言服务器导入使用同一覆盖,兄弟编辑或重开不会恢复非空默认值,非空编辑清当前实例标记而共享编辑/重置清该选项全部标记;真实 Core、生产存储与服务回归核对最终 argv 和导入值;列表单选与多选支持 allowCustom 原生输入和移除已选自定义值,文本/文件/目录清空提交显式空字符串,只有重置删除覆盖。插件选项在项目打开、选项修改和模型加载完成后通过 Core build.languageImport 归一化为 mavenContext/javaGradle,与构建计划使用同一生效值,并在 Java 启动前等待同一工作区代次的最新配置;运行时准备后再等一次,覆盖等待期间失效。唯一发布回调优先 Maven 原地热更新,被拒绝时串行恢复重启;停用最后一个 Maven 插件时,仅清除曾带 Maven 输入的同一会话,纯 Gradle 首次启动保持 nil。Gradle 在下次启动生效,取消/重置拒绝旧检测与恢复任务,被动工具路径发现不执行 Wrapper/版本探测;没有对应插件导入输入时兼容原 Maven 设置。模型 run 入口与 lithe/build/execute 尚未接入,Provider 无操作系统级沙盒;Windows 宿主尚未调用 build.* 命令。自动化:cargo test -p lithe-core --lib build_systems、cargo test -p lithe-core --lib lsp、scripts/verify-shared-contracts.sh、./scripts/test-macos.sh --filter 'BuildSystemToolWindowTests|RustBuildSystemOperationsTests|BuildSystemServiceTests|PluginMarketplaceServiceTests'。手动验证:安装 fixtures 中 cargo-build、go-build 形态的插件包,确认每个构建系统各出现一个工具窗口,列出工程、分级任务、选项和依赖,停用插件后窗口消失;执行任务与测试的 argv 与 build-plans.json 一致,停止与输出上限生效;JUnit 报告与 lineMatcher 诊断可跳转到源码;命令模型和项目内 Wrapper 只在用户点击加载或运行后启动;禁用插件后实例消失;Windows 接入后另需验证未信任工作区不启动任何模型命令或 Wrapper;gradle-provider 形态的自有 Provider 只在用户操作或工作区信任后启动、停用插件时停止,mix-provider 形态复用语言服务器会话而不启动第二个进程;运行前后 app bundle 文件清单不变(scripts/verify-runtime-bundle-immutability.sh)。;新路径选择使用 executableResolution 1 + settings 2,已发布 buildSystems 2 旧字段只作统一候选输入适配:MacBuildToolResolverTests 验证带空格绝对路径、权限与版本失败不回退,BuildSystemServiceTests 验证 Provider 失败不独立发现,RustBuildSystemOperationsTests 验证全局值接入。Cargo 独立仓库以显式本地 Core bridge 验证自选路径用于 metadata 和全部构建/测试/运行/清理;发布前需把独立仓库 sdk.lock.json 的宿主 pin 更新到包含该能力的已发布提交。;回归增加非法存储值不回默认、数组/priority/插入顺序与拒绝循环、宿主注入发现、空设置跳过和被动选择不探测;Language Server/Execution Provider 新清单语法尚未开放,Windows 不声明 executableResolution。" + "verification": "macOS 已接入 static、command、hostIntegration、provider 四种模型来源:宿主向 Core 声明 buildSystems 与 buildProviders 能力,插件市场因此列出兼容的 API 3 声明式和 Provider 版本;Provider 进程按插件、构建系统和工作区各自独立,经各自 stdio 用 JSON-RPC(LSP 基础协议)与宿主通信,initialize 协商 capabilities.experimental.litheBuild 后宿主才经 lsp.buildRequest 发送 lithe/build/model、lithe/build/dependencies,回复交给 Core 解码;共享写法只复用同一插件的语言服务器会话;进程只在用户加载模型或依赖时启动,切换工作区、关闭项目窗口、停止执行模块、停用或更新插件、退出应用时停止;ExecutionFeatureGraph.stop 经 BuildSystemService.stop 同时回收已就绪和初始化中的 Provider,停止后的初始化完成也不得重新登记会话;状态写入插件状态目录;每个已启用的构建系统插件在打开工作区后各有一个右侧工具窗口(标题为 displayName、图标为 icon),不依赖识别结果,工作区没有对应工程时窗口内显示未检测到该构建系统,工具栏放运行、参数任务、刷新和 presentation=toolbar 的开关,树顶部是 presentation=tree 的勾选选项,工程下按 category(缺省按 group)分级列出任务,再列测试、目标和依赖;内置 Maven 窗口与共享 Build 窗口已删除,Build Output 显示输出、诊断与测试结果。窗口恢复先激活所属插件模块,激活中的命令面板项禁用;参数任务遵守 workspace/project/target 作用范围与目标标签,模型或工作区变化后清除旧选择。隔离回归覆盖这些边界、窗口布局恢复及包内图标读取前后文件清单与字节不变;多实例的根目录选择器保留每个实例的模型候选和生效值,编辑多选时保留兄弟实例独有的已选值;显式清空按实例根持久化为空覆盖,检测、同步指纹、任务计划和语言服务器导入使用同一覆盖,兄弟编辑或重开不会恢复非空默认值,非空编辑清当前实例标记而共享编辑/重置清该选项全部标记;真实 Core、生产存储与服务回归核对最终 argv 和导入值;列表单选与多选支持 allowCustom 原生输入和移除已选自定义值,文本/文件/目录清空提交显式空字符串,只有重置删除覆盖。插件选项在项目打开、选项修改和模型加载完成后通过 Core build.languageImport 归一化为 mavenContext/javaGradle,与构建计划使用同一生效值,并在 Java 启动前等待同一工作区代次的最新配置;运行时准备后再等一次,覆盖等待期间失效。唯一发布回调优先 Maven 原地热更新,被拒绝时串行恢复重启;停用最后一个 Maven 插件时,仅清除曾带 Maven 输入的同一会话,纯 Gradle 首次启动保持 nil。Gradle 在下次启动生效,取消/重置拒绝旧检测与恢复任务,被动工具路径发现不执行 Wrapper/版本探测;没有对应插件导入输入时兼容原 Maven 设置。模型 run 入口与 lithe/build/execute 尚未接入,Provider 无操作系统级沙盒;Windows 宿主尚未调用 build.* 命令。自动化:cargo test -p lithe-core --lib build_systems、cargo test -p lithe-core --lib lsp、scripts/verify-shared-contracts.sh、./scripts/test-macos.sh --filter 'BuildSystemToolWindowTests|RustBuildSystemOperationsTests|BuildSystemServiceTests|PluginMarketplaceServiceTests'。手动验证:安装 fixtures 中 cargo-build、go-build 形态的插件包,确认每个构建系统各出现一个工具窗口,列出工程、分级任务、选项和依赖,停用插件后窗口消失;执行任务与测试的 argv 与 build-plans.json 一致,停止与输出上限生效;JUnit 报告与 lineMatcher 诊断可跳转到源码;命令模型和项目内 Wrapper 只在用户点击加载或运行后启动;禁用插件后实例消失;Windows 接入后另需验证未信任工作区不启动任何模型命令或 Wrapper;gradle-provider 形态的自有 Provider 只在用户操作或工作区信任后启动、停用插件时停止,mix-provider 形态复用语言服务器会话而不启动第二个进程;运行前后 app bundle 文件清单不变(scripts/verify-runtime-bundle-immutability.sh)。;新路径选择使用 executableResolution 1 + settings 2,已发布 buildSystems 2 旧字段只作统一候选输入适配:MacBuildToolResolverTests 验证带空格绝对路径、权限与版本失败不回退,BuildSystemServiceTests 验证 Provider 失败不独立发现,RustBuildSystemOperationsTests 验证全局值接入。Cargo 独立仓库以显式本地 Core bridge 验证自选路径用于 metadata 和全部构建/测试/运行/清理;发布前需把独立仓库 sdk.lock.json 的宿主 pin 更新到包含该能力的已发布提交。;回归增加非法存储值不回默认、数组/priority/插入顺序与拒绝循环、宿主注入发现、空设置跳过和被动选择不探测;Language Server/Execution Provider 新清单语法尚未开放,Windows 不声明 executableResolution。;真实 Core + macOS resolver + BuildSystemService 组合回归覆盖前置 Runtime 缺失/版本不足时保留工具或后置 Runtime 的非空 setting 约束,Provider 不发送独立发现请求;全部设置为空时仍可回退。自定义 Runtime 先构造含所选目录的 PATH,再以同一环境探测与执行,同目录 helper 的带空格路径回归通过。" }