Skip to content

feat: 项目生成器增加通用工具字段(projectGenerators 2,API-33) - #1740

Merged
xiaoyumuxi merged 13 commits into
previewfrom
feat/1495-project-generator-tool-field
Nov 5, 2026
Merged

xiaoyumuxi merged 13 commits into
previewfrom
feat/1495-project-generator-tool-field

Conversation

@xiaoyumuxi

@xiaoyumuxi xiaoyumuxi commented Nov 4, 2026 •

Copy link
Copy Markdown
Collaborator

Refs #1495

做了什么(API-33)

项目生成器可以声明通用的"工具"字段。用户新建项目时从任意工具定义的已有安装里选一个,选择结果写进新项目的工具 pin。不新增 API 编号,不改 pluginAPIVersion,Windows 行为不变。

契约与 Rust Core

  • 新增 projectGenerators: 2,字段为 {type:"tool", tool, minimumVersion, pinAs:"project", optional}。tool 是工具定义 ID,没有封闭枚举。
  • 清单校验:版本 2 不允许 runtime,版本 1 不允许 tool;plugins.declarative.validate 接受 type:tool。
  • 表单:宿主传入候选安装 tools。Core 负责选择(保留用户的选择,否则取最新版本,同版本保持宿主给的顺序)和最低版本检查,返回 installations(含 meetsMinimum)以及 toolTooOld / required 问题。
  • 计划:步骤支持 ${field.<id>} 和 ${field.<id>.executable},计划结果返回 toolPins。
  • 目录:条目返回 tools(声明该工具的插件及启用状态)。
  • 修复:插件限定的工具 ID(<pluginID>:<id>)原来匹配不到提供插件,现在按限定 ID 匹配。
  • 契约 README 新增 Tool fields 一节,补了 schema、夹具和黄金用例;verify-shared-contracts.sh 检查夹具是否存在。
  • 版本 1 的 runtime(Java)不变,旧路径等 Java 逻辑迁出时再删。

macOS

  • 新建项目窗口增加工具下拉。候选来自通用工具发现,版本太旧的安装置灰。找不到工具时,插件已装未启用提示"启用",没有插件定义则提示"在插件市场中查找"。
  • MacProjectToolInstallations:新建项目时还没有工作区,所以在一个空的临时目录里复用设置页的工具发现,用完删除。
  • MacProjectToolPins:项目创建后通过设置页同一个存储写 .lithe/run/local.json。写失败不让创建失败(项目已经移到位,回滚没有意义),改为提示 toolPinWarning。
  • 热激活:只含项目生成器或工具定义的插件,安装、更新、卸载后免重启生效。
    • MacServiceContainer 把启动时登记的插件和实时注册表合并成"当前生效的插件",生成器列表、工具发现、pin 的只读目录检查都读这一份。
    • 新建项目窗口监听插件变化并刷新条目。
    • 工具链设置页打开时也监听插件变化并重读快照;页面没加载过时不做任何事。
    • 含语言服务器等其他贡献或后端的插件仍需重启,测试里有反例。
    • 这一条反转了两个原有的"需要重启"断言(ToolchainPluginAdmissionTests 的独立定义用例、PluginLiveActivationTests 中的 project-generator),热激活 Note 的清单同步更新。
  • hostCapabilities 声明 projectGenerators: [1, 2];新增中英文词条,都走 shared/i18n 和 L10n.string。

文档与测试

  • 计划 API-33、功能矩阵 plugin-project-generators、新建项目向导 Note(新增"工具字段"一节和两个被否方案)、热激活 Note、rust-core-api.md 都已同步。
  • 测试:Core project_generators 用例;Swift ProjectGenerationTests、新文件 ProjectToolAdaptersTests(用真实的 MacToolchainPreferencesStore)、PluginLiveActivationTests、ToolchainPluginAdmissionTests、ToolchainSettingsFeatureTests(新增"只有打开的页面才重读"用例)。

评审修复(lithe-code-review)

  • Core 解析工具字段时,如果固定的版本已经卸载或候选列表为空,回退到可用的安装,并补了测试。
  • 查找已安装工具失败时记录日志,新建项目窗口显示失败原因和"重试"按钮,不再当成"没有安装"。
  • 插件变化后清空已缓存的工具列表;没选工具时保留空选项,选中后空行不再出现。
  • 临时目录创建和清理失败都写日志,不再静默吞掉。
  • 契约 README、fixtures、Agent Note 和 i18n 词条都已同步(新增词条走 shared/i18n 和 L10n.string)。

同步 preview(含 #1727、#1744、#1747、#1748、#1750)

验证

已通过:

  • cargo test --lib project_generators:41 个通过;之前 plugins:: 有 101 个、toolchain 有 99 个通过
  • scripts/macos/test/test-macos.sh --filter 'ProjectGenerationTests|ProjectToolAdaptersTests|PluginLiveActivationTests|ToolchainPluginAdmissionTests|ToolchainSettingsFeatureTests':5 个套件 83 个测试通过(同步 preview 后重跑)
  • verify-no-host-language-specifics.mjs(Ratchet verified)、verify-shared-contracts.sh、verify-log-usage.mjs、verify-rust-core-comments.sh、generate-i18n.mjs --check、verify-app-language-localization.mjs、verify-agent-notes.mjs、test-stability 静态闸门、功能矩阵 change 闸门、rustfmt
  • 更早一轮已通过:verify-service-boundaries.sh(含运行时 bundle 不可变检查)、verify-module-boundaries.sh、verify-java-semantic-ownership.mjs;在 macOS 上 cargo check Windows 目标没有新增错误。Windows 实机没跑。

已知未完成

  • 版本 1 的 runtime 和 Java 专用路径保留,等 Java 逻辑迁出时删除。
  • Windows 不变(不声明 projectGenerators)。
  • 合并后在 lithe-plugin-docs 运行 node scripts/contract.mjs sync --revision <合并后的 preview commit> 同步契约。在同一个 PR 里,把本 PR(projectGenerators: 2)登记进 reference/protocol-changelog.md,新版本号写进"按协议查首次出现"表,并在 PR 描述里 @ 本 PR 作者核对。

新增 type:"tool" 字段:由 tool 指定工具定义 ID,minimumVersion 过滤过旧的安装,
pinAs:"project" 让计划带出创建后要写入的工具 pin。步骤里可用 ${field.<id>} 和
${field.<id>.executable}。表单返回候选安装与 toolTooOld 问题,目录条目返回声明
该工具的插件。版本 1 的 runtime 字段保持不变,版本 2 不允许 runtime 字段,
版本 1 不允许 tool 字段。

Refs #1495
README 增加 Tool fields 小节、模板变量 ${field.<id>.executable}、表单 tools 输入、
installations 输出、toolTooOld 问题、计划 toolPins 与目录 tools。manifest schema 接受
projectGenerators 2、tool 字段类型、tool 与 pinAs 属性。共享契约校验脚本检查
project-plans 用例指定的 manifest 夹具存在。

Refs #1495
- 新建项目窗口为 type:tool 字段显示工具下拉:候选来自通用的工具发现,低于最低版本的安装置灰,找不到工具时提示启用或到插件市场查找
- 新增 MacProjectToolInstallations:新建项目没有工作区,在空的临时目录里复用设置页的工具发现,用完删除
- 新增 MacProjectToolPins:创建成功后把所选安装写入新项目的工具 pin(.lithe/run/local.json),与设置页共用同一个存储;写入失败不让创建失败,改为提示
- 新建项目窗口监听插件变化并重新载入条目;当前生效的插件由启动时登记的插件和实时注册表合并得到
- hostCapabilities 声明 projectGenerators 1 和 2
- 新增 5 条中英文界面文案并重新生成 Localizable.strings

Refs #1495
- canActivateWithoutRestart 放行 projectGeneratorsExtension 和 toolchainsExtension:生成器清单和工具定义是宿主每次用到时才读取的数据,不依赖启动时构建的模块图
- 含语言服务器、构建等其他贡献或后端的插件(例如 Java Support)判断不变,仍然重启后生效

Refs #1495
- ProjectGenerationTests:工具字段的目录候选、表单版本检查、计划里的工具 pin 与命令展开、创建后写 pin、pin 写失败的提示、没有工具定义时的市场提示、插件变化后重新载入
- ProjectToolAdaptersTests:临时目录里的工具发现与清理,工具 pin 写入设置页同一个存储且不覆盖已有 pin
- PluginLiveActivationTests、ToolchainPluginAdmissionTests:生成器和工具定义插件满足免重启谓词,安装与卸载即时生效;工具链 provider 仍需重启

Refs #1495
- 计划:API-33 状态改为 projectGenerators 2 增加通用工具字段,能力版本列表加入 projectGenerators 2
- 跨平台功能矩阵:补充工具字段、免重启和对应验证步骤,Windows 不变
- Agent 笔记:新建项目向导增加工具字段一节(职责划分、pin 失败不回滚、被否方案);热激活笔记更新谓词范围和已知边界
- rust-core-api:说明工具候选由宿主提供、Core 只做选择与校验

Refs #1495
工具定义插件现在可以免重启生效,已打开的工具链设置页也应立即看到新增或移除的工具定义。
AppModel 已有的 pluginRegistrationChanges 订阅额外通知 ToolchainSettingsFeatureModel,
后者复用文件变化的合并重载路径;页面加载前不触发读取。同步更新热激活与新建项目向导 Note。
@ghfind-review ghfind-review Bot added the review: high ghfind author score; see https://ghfind.com label Nov 4, 2026
@xiaoyumuxi
xiaoyumuxi marked this pull request as ready for review November 4, 2026 23:13
@lithe-code-review

lithe-code-review Bot commented Nov 4, 2026 •

Copy link
Copy Markdown

Lithe Review

结论: ⚠️ 有建议
范围: preview ← feat/1495-project-generator-tool-field · head: 6f89834

未发现需要阻塞合并的问题。以下均为 P2 非阻塞建议;当前失败 CI 的原因尚未确认。

Findings

  1. [P2] 插件变化时应撤销所有工具安装缓存
    macos/Sources/Lithe/Application/Features/NewProjectFeatureModel.swift:290

    • 实际影响:停用或卸载工具定义插件后,生成器仍可使用旧安装创建项目并写入 pin,且不显示启用或安装提示。
    • 触发条件:插件变化发生时,当前选择的生成器不使用该工具。
    • 复现步骤:先打开使用 Python 的生成器并完成发现,切到空项目,停用另一个提供 Python 定义的插件,再切回原生成器。reloadCatalog() 只刷新当前条目的工具,而这里因 listedTools 已有缓存而跳过发现;旧候选继续进入表单和生成计划。
    • 来源:本次引入。
  2. [P2] 工具版本比较需要统一处理末尾零
    rust/lithe-core/src/project_generators/form.rs:369

    • 实际影响:满足最低版本的安装被标记为 toolTooOld,导致无法创建项目;等价版本的默认选择也可能违背宿主顺序。
    • 触发条件:安装版本与最低版本使用不同数量的末尾零,例如 3.11 和 3.11.0。
    • 复现步骤:声明 minimumVersion: "3.11.0",传入安装版本 3.11。这里直接比较向量,得到 [3,11] < [3,11,0]。既有 toolchain/resolution.rs 的 components() 已通过去除末尾零处理这种等价关系。
    • 来源:本次新增的工具字段路径引入。
  3. [P2] 可选工具没有合格安装时应允许保持为空
    rust/lithe-core/src/project_generators/form.rs:329

    • 实际影响:机器上存在旧版本工具,反而使原本可选的字段阻止项目创建;没有安装该工具时却能创建。
    • 触发条件:字段同时声明 optional: true 和 minimumVersion,所有候选均低于要求。
    • 复现步骤:声明最低版本 3.11 的可选字段,仅传入 3.10.14。代码自动选择旧安装并返回 toolTooOld;将字段值清空仍会再次选择它。共享契约规定,没有可用安装的可选字段应为空且不产生 pin。
    • 来源:本次引入。
  4. [P2] 工具下拉应禁用低于最低版本的选项
    macos/Sources/Lithe/Views/Workspace/NewProjectView.swift:402

    • 实际影响:旧版本仍以可用选项呈现并能选中,用户选择后才发现创建按钮不可用,与新增契约及 PR 描述不符。
    • 触发条件:候选包含 meetsMinimum == false 的安装。
    • 复现步骤:同时提供 Python 3.10 和 3.12,最低要求为 3.11,打开下拉并选择 3.10。此调用没有传 isAvailable,而 LitheSettingsSelect 默认允许所有选项;标题后缀不会禁用选项。
    • 来源:本次引入。
  5. [P2] 临时目录创建失败不能伪装成没有工具安装
    macos/Sources/Lithe/Platform/MacOS/ProjectGeneration/MacProjectToolInstallations.swift:61

    • 实际影响:工具发现因文件系统错误未执行,界面却显示没有安装,且诊断日志没有失败原因。
    • 触发条件:临时目录不可写、磁盘已满,或创建目录遇到其他 I/O 错误。
    • 复现步骤:给适配器传入不可写的 scratchParent 并请求已启用工具。这里吞掉错误返回 nil,随后 installations() 返回空字典,与成功发现但没有安装无法区分。第 38 行也无条件忽略目录清理失败。
    • 来源:本次引入。

Scope Check

  • 关联需求:本 PR 覆盖 [Feature] macOS 存量重构计划:清理废弃实现,将 Maven/Java 领域逻辑完整迁入插件后端 #1495 中 API-33 的工具字段及相关热激活能力,不能据此认定整个迁移 Issue 完成。
  • 已完成范围:能力版本、清单校验、表单与计划、共享 fixture、macOS 工具发现和 pin 存储接线,以及相关测试、i18n 和笔记。
  • 未完成范围:上述边界问题;Java 旧路径迁移和 Windows 功能实现明确不在本 PR 内,契约仓库同步计划在合并后执行。
  • 能力复用:沿用已有工具发现和偏好存储,没有新增语言或项目语义引擎;版本比较应进一步复用既有规则。
  • Findings 均指向本次新增行为,属于本次变更职责范围。

Suggestions

  1. 插件变化时清空或按注册代数撤销全部工具缓存,再刷新当前条目;刷新期间禁止使用已撤销候选创建项目。补充“切换条目后停用定义插件”的回归测试。
  2. 抽取并复用工具链已有的版本规范化规则,同时用于最低版本比较和默认排序,覆盖 3.11、3.11.0、3.11.0.0 的等价情况。
  3. 可选字段没有合格候选时返回空值并省略 pin,补充“有旧安装”和“完全没有安装”行为一致的用例。
  4. 将 Core 返回的 meetsMinimum 接入下拉的 isAvailable。
  5. 区分发现失败与正常空结果,向功能模型返回错误,并记录脱敏的目录事件;清理失败也应记录。
  6. 补充受影响新建项目界面的前后对比截图,展示工具下拉、旧版本状态和缺失提示。
  7. 提供当前 head 的 Swift tests 与 Structured Logging 失败日志,修复后补充对应结果。

Summary

主要实现复用了现有基础设施,Core 与原生 I/O 的职责总体清晰。现有测试覆盖了基本成功和失败路径,但遗漏了跨条目的缓存失效、等价版本、可选字段仅有旧安装及临时目录失败等边界。

Verification

  • 实际检查:指定 c664ef6...6f89834 的聚焦 diff、相关 base 文件,以及生成器契约、Core 表单和计划、macOS 功能模型/适配器/存储/热激活调用链、相关测试和文档。未读取生成的本地化资源正文。
  • 已提供结果:作者报告相关 Core 测试、6 套 Swift 共 80 个测试及多项静态检查通过;所附 head Check Run 中 Rust Core、Windows 和 i18n 检查成功,但 Swift tests、Structured Logging 失败,arm64 发布包验证仍在进行。缺少失败日志,无法归因。
  • 本次仅做静态只读审查,未运行代码、测试、i18n 或 bundle 不可变检查,未访问网络。
  • 未提供截图,视觉效果尚未验证;Windows 实机验证也未提供。

@lithe-code-review

Copy link
Copy Markdown

Lithe 运行验收

版本:6f89834f1eeaaee9af28166ced1ced93f603dac3;状态:partial。
本报告独立于代码审查;只报告实际执行的场景,不代表所有问题均已修复。

对照:共同祖先 4dd3165912a7ef4ccfd7240890a33b63751c9b3e → PR head;当前目标分支合并适用性:未运行。

  • 条件不足,未验证:Exercise plugins.declarative.validate and project.generatorCatalog through the checked-out lithe_core::execute_json API. Freeze identical manifests for both revisions: a v2 generator referencing an arbitrary tool ID, two definition plugins sharing a local ID, enabled/disabled variants, invalid field/version combinations, and a valid v1 Java runtime generator. Observe baseline feature absence through validation responses rather than missing symbols or head-only fixture files.
    • Cargo and rustc are available, but the inventory supplies no Windows C compiler, linker, or SDK. Core depends on native compilation through tree-sitter and ring. No per-revision compiled Core runner is supplied. These prerequisites and checkout-local locked dependencies are needed; no build was attempted.
  • 条件不足,未验证:Use production project.generatorForm and project.generationPlan with frozen manifests, fixture-owned template files, and deterministic host installation records. Cover newest selection, explicit selection, equal-version ordering, vanished selections, minimum-version boundaries, required/optional empty cases, optional fields with only old installations, hidden fields, and omitted pinAs. Inspect returned file contents, argv, environment, problems, and toolPins. This is Core API acceptance; supplied installation records do not prove native discovery or project creation.
    • Requires the same unavailable native Core compilation prerequisites as the admission scenario, or a compiled production Core runner for each exact revision. Node cannot execute these Rust implementations directly. No behavior was executed.
  • 条件不足,未验证:In an isolated macOS product instance, create a project using a local generator and qualified tool definition. Read actual project files and settings after creation. Include scratch creation failure and pin-write failure. For cache invalidation: discover a tool, switch to Empty Project, disable its definition plugin, then switch back. Exercise local install/update/uninstall of generator-only and definition-only plugins with the wizard and toolchain settings open. Inspect English and Chinese notices and close all owned application processes afterward.
    • Requires macOS, the pinned Swift/Xcode toolchain, an interactive desktop, and fixture-isolated application/plugin storage with trusted local plugin packages and tool installations. The supplied environment is headless Windows. Neither native macOS adapters nor SwiftUI workflows can be verified here.

未覆盖:

  • All runtime requirements remain unverified because every proposed scenario is blocked; empty probes and patterns are intentional.
  • Core v2 admission, arbitrary tool IDs, field-version restrictions, host capability rejection, and short/qualified provider matching with enablement states.
  • Core selection preservation, newest/equal-version ordering, trailing-zero equivalence, minimum checks, installation annotations, required/optional behavior, and optional fields with only old installations.
  • Plan home/executable expansion, conditional steps and hidden fields, requested toolPins, and omitted pins for optional or unpinned fields.
  • Native macOS discovery, scratch-directory cleanup, discovery failure diagnostics, and separation of failures from legitimate empty results.
  • Actual project creation, shared pin persistence/readback, preservation of existing pins, conflict handling, and nonfatal toolPinWarning behavior.
  • Native picker availability, missing-tool actions, application-language localization, accessibility, keyboard focus, and visual presentation.
  • Plugin install/update/uninstall and enablement refresh, cross-generator cache invalidation, settings refresh only after loading, and restart requirements for other contributions.
  • Runtime bundle/package immutability and process/resource cleanup during actual workflows.
  • Version 1 Java workflow compatibility beyond Core responses; Java is unavailable.
  • Windows compatibility, including continued omission of projectGenerators from host capabilities and marketplace filtering; no executable native Windows product was supplied.
  • Schema/fixture consistency, documentation and feature-matrix accuracy, i18n generation checks, and repository validation gates were not executed.
  • Post-merge contract synchronization to lithe-plugin-docs requires external work and is outside this planning session.
  • The full requirements of Issue [Feature] macOS 存量重构计划:清理废弃实现,将 Maven/Java 领域逻辑完整迁入插件后端 #1495 cannot be assessed because its body was not supplied; this plan covers the PR's stated API-33 scope.

工作副本与运行状态已清理;可复用编译缓存按 12 GiB / 7 天预算保留。
详细步骤和原始证据保存在服务器受限目录(14 天、总计不超过 1 GiB);当前没有公开下载链接。

- Core 解析工具字段时,固定版本已卸载或列表为空回退到可用安装,并补测试
- 查找已安装工具失败时记录日志、在新建项目窗口显示原因和重试按钮,不再当成没有安装
- 插件变化后清空已缓存的工具列表;未选工具时保留空选项,选中后不再出现空行
- 临时目录创建/清理失败写日志,不再静默吞掉
- 契约 README 与 fixtures、Agent Note、i18n 词条同步更新
# Conflicts:
#	docs/development/macos-plugin-api-plan.md
# Conflicts:
#	macos/Tests/LitheTests/PluginLiveActivationTests.swift
#	macos/Tests/LitheTests/ToolchainPluginAdmissionTests.swift
#	rust/lithe-core/src/tests/declarative_plugins.rs
#	shared/contracts/plugins/v1/README.md
#	shared/contracts/plugins/v1/fixtures/project-generators/project-plans.json
#	shared/platform-feature-matrix/features/plugin-project-generators.json
- ProjectGenerationTests 的工具字段与工具定义 fixtures 改从 project-generators/ 与 toolchains/ 读取
- 工具字段测试从定义 fixture 读取工具与插件 ID,运行时测试改用 KNOWN_RUNTIMES,语言名闸门回到基线
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

review: high ghfind author score; see https://ghfind.com

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant