buildSystems 用数据描述一个项目级构建工具(Cargo、Go、Gradle、Maven 等):怎么识别项目根目录、找哪个可执行文件、怎么得到项目模型、有哪些任务和运行入口、哪些文件变化要重新同步。所有构建工具共用同一套模型和命令:Core 校验声明、检测实例、解码模型、展开每一条命令行,宿主只执行 Core 规划好的进程并把输出交回。所以社区插件加一个构建工具不需要改宿主,宿主代码也不按构建系统 ID 分支。模型需要程序计算时,再加一个构建提供者。
宿主支持。 Lithe 桌面端声明
buildSystems和buildProviders(版本都是0):构建窗口发现构建实例、加载提供者模型、解析 Core 返回的有序可执行文件候选,并运行命令任务和提供者任务。桌面端不声明buildModelInputs、executionProviders和toolchainProviders:requires里有其中任何一个的插件不会被提供安装,所以modelSharing和modelInputs在桌面端用不上。 构建系统的实例级选项(scope: "instance")和项目任务的preparation,桌面端尚未呈现:插件照常安装,这部分没有界面,也不会被调用。构建提供者的运行准备、测试、调试准备、模型输入、原生配置、内联测试报告和运行时调试同样尚未呈现,见构建提供者。 宿主只呈现它实现的功能,插件不得依赖宿主一定会调用其中任何一个。该注释还写到系统命令的工具发现目前只读PATH,依赖项目工具链或用户覆盖的计划会被拒绝,它是否也约束可执行文件候选里的setting和toolchain来源,注释没有说明;依赖这两种来源前,先在桌面端实际试一遍。说明见pluginhost.go;各能力的对照见能力与协议版本对照。 对契约有疑问,请到 Lithe-core-rust 的 Issues 反馈。
| 项目 | 内容 |
|---|---|
| 清单字段 | buildSystems[]:id、displayName、icon、detection、invocation、options、model、provider、tasks、run、test、diagnostics、dependencies、sync、layout、hostIntegration,以及可选的 modelSharing、modelInputs(见下文)和 configuration(原生配置,见构建提供者) |
| 能力版本 | buildSystems 0。不带 provider 的构建系统只需要它;带 provider 还要 buildProviders: 0;modelSharing、modelInputs 另需 buildModelInputs: 0(消费者还需要 buildProviders: 0);可执行文件候选用 setting 来源时还要 settings: 0(见 build-tool-path)。可执行文件解析本身是基础契约,不是能力,不需要在 requires 里声明。requires 必须恰好列出清单用到的能力,见版本对照 |
| 协议 | 没有进程协议;model.source: "provider" 时走 litheBuild |
| API 编号 | API-29:构建、任务、测试、运行准备 |
| 权限 | process.build |
| 激活事件 | onBuildSystem:<id> |
| 宿主支持 | Lithe 桌面端:见上面的说明 |
构建系统、任务和运行入口的 ID 以小写字母开头,只用小写字母、数字和连字符;选项 ID 用 camelCase,和设置 ID 一样。声明里的路径都是相对路径,用 /,不能越出各自的基准目录(否则是 plugin.path.invalid)。完整字段表见契约。
| 字段 | 决定什么 |
|---|---|
detection |
用 markers 里的文件名识别候选根目录。Core 最多向下找 6 层,跳过已知的缓存和构建输出目录,以及被 Git 忽略的目录(规则来自工作区内途经的 .gitignore,以及根目录在工作区内的仓库的 info/exclude;不读工作区根以上的目录、core.excludesFile 和索引,所以被忽略目录下即使有已跟踪的清单文件也不算候选)。检测还会跳过工作区的忽略路径:这是用户在构建选项里编辑的 .gitignore 规则,存放在团队或本机的构建选项中,默认是所有名字以 . 开头的目录(如 .claude/worktrees),用户可以再添加,也可以用 ! 放回某个目录;nesting 决定深层候选并入外层实例(outermost,如 Gradle、Maven)还是各自独立(separate,默认,如 Cargo);priority 决定多个插件声明同一个 ID 时谁优先 |
invocation |
可执行文件候选(executables,按偏好排序)、globalArguments、版本探测和 minimumVersion |
runtimeDependencies |
构建工具依赖的运行时。node、go 由宿主管理;其他运行时要么命名同 ID 的工具定义,要么自己声明 executables 和版本探测 |
options |
用户选择的构建维度:boolean、singleSelect、multiSelect、text、file、directory;每个选项在有值时贡献 arguments 和 environment |
model |
怎么得到项目模型,见下表 |
provider |
没有命令能打印模型时,由构建提供者回答模型和依赖请求 |
tasks、run、test |
任务目录、从模型目标或任务生成的运行入口、测试的范围、过滤器和结果文件 |
diagnostics、dependencies |
诊断的行匹配或 litheDiagnostics;依赖列表或依赖树的来源 |
sync、layout |
哪些文件变化会让模型过期;每个项目要作为 excluded 内容根加入的目录 |
model.source |
怎么得到模型 | 示例 |
|---|---|---|
static |
读取项目里的 toml 文件,检测时完成,不启动进程 |
build-static-file(Cargo) |
command(标准输出) |
运行命令,解码标准输出(jsonStream 或规范格式) |
build-command-stdout(Go) |
command(输出文件) |
运行命令,解码它写到 ${outputFile} 的文件 |
build-command-output-file(Gradle) |
provider |
由插件的构建提供者回答 lithe/build/model |
构建提供者 |
hostIntegration |
保留字段:任何 ID 都返回 plugin.integration.unsupported。构建系统用声明式契约或规范格式 |
— |
command 来源要声明 executesProjectCode 和 mayUseNetwork。命令只在宿主按请求启动时运行,静态文件在检测时读取。map 只负责选取值,不是转换语言:map 表达不了的(其他文件格式、从工具读出的任务、显式的父子关系、计算出的标签、依赖树)由插件自己的命令或构建提供者输出规范格式 litheBuildModel、litheDependencies、litheTestResults 或 litheDiagnostics(version 都是 0)。不符合解码器的输出是 plugin.build.invalidOutput。
构建系统的 hostIntegration 和语言服务器的 hostIntegration 都是保留字段:Core 不实现任何宿主集成,任何 ID 都返回 plugin.integration.unsupported,见语言服务器的宿主集成。
- 选项范围。 选项可以声明
scope: "instance",按检测到的每个根目录分别保存:改动或重置a不会影响b。省略范围(或"workspace")使用工作区和构建系统存储。显式的false、""、[]仍然是用户保存的值。实例值不能覆盖工作区选项,工作区值也不能悄悄覆盖实例选项。示例:build-instance-options。 - 可执行文件解析。
invocation.executables按偏好顺序列出来源:projectFile(项目里的包装脚本,总是运行项目代码)、environment、command(PATH上的命令名)、runtime、setting(引用声明为file的全局设置)和toolchain(工具定义 ID)。可以用id、priority、insertBefore、insertAfter调整同一个候选集内的顺序。用户配置的路径失败是终止性的,不会回退到后面的候选或提供者自己的查找。示例:build-tool-path(setting)、build-toolchains(toolchain)。规则见可执行文件解析。 - 展示。 每个启用的构建系统有自己的工具窗口,由宿主按模型绘制;
options[].presentation把布尔选项放到工具栏(toolbar,需要icon)或把多选选项放成树顶部的清单(tree),tasks[].category给任务归类。这些字段不改变任何计划。 - 项目准备任务。 项目任务可以声明
preparation: { purpose, sourceRoles },按用途(如run)和内容根角色绑定运行前要执行的任务;宿主从当前模型选出最深的所属项目和内容根,要求恰好一个匹配的声明,不猜任务名,也不回退到约定的任务 ID。示例:build-providers/build-provider-preparation。 - 只读模型输入。 生产者用
modelSharing: { options: [...] }公开规范化的项目、目标和内容根(以及明确列出的普通选项的有效值),消费者用modelInputs: [{ pluginID, buildSystemID }]读取,最多 8 个槽位。缺失、被禁用或不公开的生产者只会让该槽位unavailable,从不被自动安装或激活;一个生产者不能同时是消费者。示例:build-model-producer、build-model-consumer。
| 章节 | 内容 |
|---|---|
| Build systems | 字段表:识别、可执行文件、运行时依赖、选项、模型、任务、运行、测试、诊断、依赖、同步、布局,以及实例级选项 |
| Presentation | 宿主绘制的构建窗口,插件不需要自带界面 |
| Templates | 命令行模板变量 |
| Model and outputs | 统一模型、诊断、测试结果和依赖的格式 |
| Optional read-only model inputs | 插件之间共享只读模型 |
| Declarative project preparation | 运行前准备任务 |
| Executable resolution | 可执行文件候选、排序、严格选择 |
| Host integrations | 构建系统的宿主集成(保留字段,Core 不实现) |
| Commands | build.* Core 命令:检测、规划、解码、同步指纹 |
示例以 Cargo、Go、Gradle 为真实输入,但不是那些插件本身。
| 文件 | 内容 |
|---|---|
build-systems/build-static-file.plugin.json |
static 模型(Cargo) |
build-systems/build-command-stdout.plugin.json |
命令标准输出模型(Go) |
build-systems/build-command-output-file.plugin.json |
命令输出文件模型(Gradle) |
build-systems/build-instance-options.plugin.json |
按实例保存的选项 |
build-systems/build-tool-path.plugin.json |
用 file 设置选择构建工具 |
build-systems/build-toolchains.plugin.json |
可执行文件候选和运行时依赖用 toolchain 来源 |
build-systems/build-model-producer.plugin.json |
公开模型的生产者 |
build-systems/build-model-consumer.plugin.json |
读取模型的消费者(带构建提供者) |
build-systems/build-plans.json |
build.* 标准答案:每个宿主从上面的声明得到的计划和解码结果 |
build-providers/build-provider-preparation.plugin.json |
运行前准备任务 |
构建相关的拒绝用例在 manifest/invalid-manifests.json。
buildSystems describes a project-level build tool (Cargo, Go, Gradle, Maven, …) as data: how to recognize a project root, which executable to use, how to get the project model, which tasks and run entries exist, and which file changes require a re-sync. Every build tool shares the same model and commands: Core validates the declaration, detects instances, decodes the model, and expands every command line; the host only runs the processes Core planned and passes their output back. A community plugin therefore adds a build tool without any host change, and no host code branches on a build-system ID. When the model must be computed by a program, add a build provider.
Host support. The Lithe desktop declares
buildSystemsandbuildProviders(both version0): the Build window detects build instances, loads provider models, resolves the ordered executable candidates Core returns, and runs command and provider tasks. The desktop does not declarebuildModelInputs,executionProvidersortoolchainProviders: a plugin whoserequireslists any of them is not offered for installation, somodelSharingandmodelInputsare unusable there. Build-system instance options (scope: "instance") and project-taskpreparationare not presented on the desktop yet: the plugin installs, and that part has no surface and is never called. Build-provider run preparation, tests, debug preparation, model inputs, native configuration, inline test reports and runtime debug are not presented either; see Build providers. A host presents the features it implements; a plugin must not depend on a host calling any of them. The same comment says tool discovery for system commands readsPATHonly and that a plan depending on a project toolchain or a user override is refused. It does not say whether that also limits thesettingandtoolchainsources of executable candidates, so try those two on the desktop before relying on them. Seepluginhost.go; the per-capability comparison is in Capabilities and protocol versions. Questions about the contract go to Lithe-core-rust Issues.
| Item | Value |
|---|---|
| Manifest fields | buildSystems[]: id, displayName, icon, detection, invocation, options, model, provider, tasks, run, test, diagnostics, dependencies, sync, layout, hostIntegration, plus the optional modelSharing, modelInputs (below) and configuration (native configuration, see Build providers) |
| Capability versions | buildSystems 0. A build system without provider needs only it; with provider it also needs buildProviders: 0; modelSharing and modelInputs also need buildModelInputs: 0 (a consumer also needs buildProviders: 0); a setting executable source also needs settings: 0 (see build-tool-path). Executable resolution itself is base contract, not a capability, and is not declared in requires. requires must list exactly the capabilities the manifest uses; see versions |
| Protocols | No process protocol; model.source: "provider" uses litheBuild |
| API IDs | API-29: build, tasks, tests, run preparation |
| Permissions | process.build |
| Activation events | onBuildSystem:<id> |
| Host support | The Lithe desktop: see the note above |
IDs of build systems, tasks, and run entries start with a lowercase letter and use lowercase letters, digits, and hyphens; option IDs are camelCase like setting IDs. Paths in a declaration are relative, use /, and stay inside their base directory (plugin.path.invalid otherwise). The full field table is in the contract.
| Field | What it decides |
|---|---|
detection |
Candidate roots are directories holding one of the markers file names. Core searches at most 6 levels down and skips known caches and build outputs, plus directories Git ignores (rules from the .gitignore files inside the workspace and the info/exclude of each repository rooted there; directories above the workspace root, core.excludesFile and the index are not read, so a tracked manifest below an ignored directory is no candidate). Detection also skips the workspace's ignored paths, .gitignore patterns the user edits in the team or machine-local Build options: by default every directory whose name starts with a dot, such as .claude/worktrees, and the user can add more or bring one back with !; nesting folds deeper candidates into the outer instance (outermost, such as Gradle and Maven) or keeps each one (separate, the default, such as Cargo); priority decides between plugins declaring the same ID |
invocation |
Executable candidates (executables, in preference order), globalArguments, the version probe, and minimumVersion |
runtimeDependencies |
Runtimes the build tool needs. node and go are host-managed; any other runtime either names the tool definition with the same ID or declares its own executables and version probe |
options |
Build dimensions the user chooses: boolean, singleSelect, multiSelect, text, file, directory; each contributes arguments and environment when it has a value |
model |
How the project model is obtained; see the table below |
provider |
The build provider that answers model and dependency requests when no command prints them |
tasks, run, test |
The task catalog, run entries generated from model targets or tasks, and the scopes, filters, and result files of tests |
diagnostics, dependencies |
Line matchers or litheDiagnostics for diagnostics; the source of the dependency list or tree |
sync, layout |
Which file changes make the model stale; directories added to every project as excluded content roots |
model.source |
How the model is obtained | Example |
|---|---|---|
static |
Read a toml file in the project, at detection time, with no process |
build-static-file (Cargo) |
command (stdout) |
Run a command and decode its standard output (jsonStream or a canonical format) |
build-command-stdout (Go) |
command (output file) |
Run a command and decode the file it writes to ${outputFile} |
build-command-output-file (Gradle) |
provider |
The plugin's build provider answers lithe/build/model |
Build providers |
hostIntegration |
Reserved: every ID returns plugin.integration.unsupported. Build systems use the declarative contract or a canonical format |
— |
A command source declares executesProjectCode and mayUseNetwork. A command runs only when the host starts it on request; a static file is read during detection. A map only selects values and is not a transformation language: whatever a map cannot express (other file formats, tasks read from the tool, explicit parent links, computed tags, dependency trees) is the plugin's own command or build provider printing the canonical litheBuildModel, litheDependencies, litheTestResults, or litheDiagnostics (all version 0). Output that does not fit its decoder is plugin.build.invalidOutput.
A build system's hostIntegration and a language server's hostIntegration are both reserved: Core implements no host integration, and every ID returns plugin.integration.unsupported; see language server host integrations.
- Option scope. An option may declare
scope: "instance", stored separately per detected root: changing or resettingacannot changeb. Omitting the scope (or"workspace") uses the workspace and build-system storage. Explicitfalse,"", and[]remain stored user values. Instance values cannot override workspace options, and workspace values cannot silently override an instance option. Example:build-instance-options. - Executable resolution.
invocation.executableslists sources in preference order:projectFile(a wrapper inside the project; always runs project code),environment,command(a bare name onPATH),runtime,setting(references a declared globalfilesetting), andtoolchain(a tool-definition ID).id,priority,insertBefore, andinsertAfterreorder candidates within one candidate set. A configured path that fails is terminal and never falls back to later candidates or to the provider's own lookup. Examples:build-tool-path(setting) andbuild-toolchains(toolchain). The rules are in Executable resolution. - Presentation. Every enabled build system gets a tool window of its own, drawn by the host from the model;
options[].presentationputs a boolean option on the toolbar (toolbar, needs anicon) or a multiSelect option as a checklist at the top of the tree (tree), andtasks[].categoryfiles a task under headings. None of these fields changes a plan. - Project preparation tasks. A project task may declare
preparation: { purpose, sourceRoles }, binding the task to run first by purpose (such asrun) and content-root role. The host selects the deepest owning project and content root from the current model, requires exactly one matching declaration, never guesses a task name, and never falls back to a conventional task ID. Example:build-providers/build-provider-preparation. - Read-only model inputs. A producer publishes normalized projects, targets, and content roots (and the effective values of explicitly listed ordinary options) with
modelSharing: { options: [...] }; a consumer reads them withmodelInputs: [{ pluginID, buildSystemID }], up to 8 slots. A missing, disabled, or non-public producer only makes that slotunavailableand is never installed or activated automatically; a producer cannot also be a consumer. Examples:build-model-producerandbuild-model-consumer.
| Section | Content |
|---|---|
| Build systems | The field table: detection, executables, runtime dependencies, options, model, tasks, run, tests, diagnostics, dependencies, sync, layout, and instance options |
| Presentation | The host-drawn build window; the plugin brings no UI |
| Templates | Command-line template variables |
| Model and outputs | The shared model, diagnostics, test results, and dependency formats |
| Optional read-only model inputs | Sharing read-only models between plugins |
| Declarative project preparation | Tasks that run before a launch |
| Executable resolution | Executable candidates, ordering, strict selection |
| Host integrations | Host integrations for build systems (reserved; Core implements none) |
| Commands | build.* Core commands: detection, plans, decoding, sync fingerprints |
The examples use Cargo, Go, and Gradle as realistic inputs; they are not those plugins.
| File | Content |
|---|---|
build-systems/build-static-file.plugin.json |
static model (Cargo) |
build-systems/build-command-stdout.plugin.json |
Command stdout model (Go) |
build-systems/build-command-output-file.plugin.json |
Command output-file model (Gradle) |
build-systems/build-instance-options.plugin.json |
Per-instance options |
build-systems/build-tool-path.plugin.json |
A file setting selects the build tool |
build-systems/build-toolchains.plugin.json |
Executable candidates and a runtime dependency with toolchain sources |
build-systems/build-model-producer.plugin.json |
A model producer |
build-systems/build-model-consumer.plugin.json |
A model consumer (with a build provider) |
build-systems/build-plans.json |
Golden build.* results: the plans and decoded outputs every host gets from the declarations above |
build-providers/build-provider-preparation.plugin.json |
Tasks that run before a launch |
Build rejections are in manifest/invalid-manifests.json.