Skip to content

[Feature] 运行环境页解析纳入项目 wrapper(mvnw、gradlew 等 projectFile 候选) #1640

Open

Description

@xiaoyumuxi

Problem to solve / 要解决的问题

工具定义可以声明 projectFile 候选,也就是项目里自带的启动脚本,例如 mvnw、gradlew。Core 在项目层处理这类候选时:

  • 从当前目录逐级向上,检查 <祖先目录>/<path> 及其 requires 标记文件是否存在;
  • 运行项目里的脚本属于执行项目代码,所以还要求输入里有 projectCodeAllowed。

macOS 运行环境设置页(PR #1581)目前满足不了这两个条件:

  1. 宿主拿不到路径。 toolchains.discoveryPlan 只输出扫描规则、home 布局、可执行布局、版本探测和登录 Shell 变量,没有 projectFile 候选的 path 和 requires。宿主不知道该给 Core 收集哪些文件事实。
  2. 没有项目代码授权的来源。 设置页不传 projectCodeAllowed。

结果:Core 解析时找不到这些文件的事实,于是静默跳过项目 wrapper,wrapper 永远不会被选中。带 mvnw 的 Maven 项目在页面上会显示全局默认或自动检测到的 Maven,而将来实际构建用的是 wrapper,两者对不上。用户看不出项目里有 wrapper,也看不出它为什么没被用上。

Proposed solution / 建议方案

  1. discoveryPlan 输出 projectFile 候选。 把每个工具在当前平台适用的 projectFile 候选(path、requires)放进 toolchains.discoveryPlan 的输出。宿主照着清单,为每个查询目录及其祖先收集这些文件的事实(设置数量上限),不认识任何工具名。这是插件契约变更:修改 shared/contracts/plugins/v1/ 后,合并时要同步到 lithe-plugin-docs。
  2. 设计项目代码授权的来源。 例如沿用工作区信任,或逐项目确认。
    • 未授权时,页面在项目步骤显示 Core 的 projectCodeRequiresAction,并提供授权入口;
    • 不默认授权,也不在打开页面时执行项目脚本;
    • 运行 wrapper 来探测版本同样属于执行项目代码,受同一个授权约束。
  3. 页面展示 wrapper。 项目步骤显示找到的 wrapper、它所在的目录,以及 Core 给出的状态(已选中、需要授权、不可执行等)。

验收方式:用临时工作区覆盖以下情况:

  • 有或没有 wrapper;
  • 缺少 requires 标记;
  • 未授权和已授权;
  • wrapper 在祖先目录;
  • 超出数量上限时有诊断。

测试不执行真实的项目脚本。

Target platform / 目标平台

macOS

Area / 模块

Extensions / 扩展

Priority / 优先级

P2 / 后续考虑:目前不着急,可安排到后续版本

Alternatives considered / 已考虑的替代方案

  • 宿主按工具名写死 mvnw、gradlew。 不采用。违反“宿主不认识工具名,工具内容全部由插件注入”的规则,每新增一种 wrapper 都要改宿主。
  • 设置页默认传 projectCodeAllowed: true。 不采用。等于默认允许执行项目里的脚本,打开一个不可信的项目就可能运行其中的代码。
  • 保持现状,在文档里说明。 页面会长期显示与实际构建不一致的结果,用户无法从界面发现原因。

Additional context / 补充信息

  • 相关:PR feat(plugins): 插件注入的工具链框架与 macOS 只读环境设置页 #1581(Core 解析接入设置页)。
  • 代码位置:
    • rust/lithe-core/src/toolchain/resolution.rs:discovery_plan 的输出字段;项目层 projectFile 的祖先目录查找;projectCodeAllowed 检查与 projectCodeRequiresAction;
    • macos/Sources/Lithe/Platform/MacOS/Runtime/MacToolchainDiscovery.swift:宿主按 discoveryPlan 收集事实,并调用 toolchains.resolve。
  • 决策记录:.agents/notes/proposed/architecture/2026-10-31-plugin-injected-toolchains.md 中“macOS 设置页的解析取舍”一节,已把这一点记为已知限制。
  • 依据:源码阅读,不是发布包复现。Core 和契约是双端共享的,但 Windows 运行环境页尚未接入,本 Issue 按 macOS 设置页提出。

Checklist / 提交前检查

  • I searched existing issues for duplicates. / 我已搜索现有 Issue,确认没有重复建议。

Activity

  1. added
    enhancementNew feature or request
    P2后续考虑:目前不着急,可安排到后续版本
    on Nov 1, 2026
  2. xiaoyumuxi commented on Nov 1, 2026

    @xiaoyumuxi
    CollaboratorAuthor

    补充:现状核对与分期方案

    契约里已有的部分(不需要另做一套 wrapper 优先级)

    • 插件 manifest 已支持 wrappers、projectFile、projectKind(shared/contracts/plugins/v1/plugin-manifest.schema.json),Core 会校验每个 wrapper 都有对应的 projectFile 候选。插件作者现在就能声明 mvnw、gradlew,后续补的都是宿主侧接线,插件契约不变。
    • 优先级已在契约中规定:四层为“固定 → 项目 → 全局 → 自动”,项目层内部是 wrapper > 项目环境 > 版本文件声明,且最近的目录会遮住上层目录(shared/contracts/plugins/v1/toolchains.md)。
    • 路径注入已有定义:wrapper 的 home 可以为 null,这时不导出 home 变量、不加 PATH;projectKind: "environment" 带 home 时按定义的 pathPrepend、exports 注入。解析结果带有 projectCode: true。
    • 结果格式已留好位置:unmet 每项的原因码已包含 projectCodeRequiresAction,也有 source 字段(shared/contracts/plugins/v1/proposals/toolchains/resolution.schema.json),把“需要授权”记进去不用改 schema。

    另做一套 wrapper 优先级会和 Core 的四层规则打架。#1581 刚修掉的就是这个问题:Swift 自己排的顺序和 Core 对不上。

    新发现:wrapper 因未授权被跳过时,结果里看不出来

    项目层只留一条 trace。wrapper 因 projectCodeRequiresAction 失败后,Core 会接着试同目录的版本文件声明;一旦声明成功,结果里就只剩“已解析”,看不出这里其实有 ./mvnw、只是需要授权。目前 unmet 只记录 requestedNotInstalled(rust/lithe-core/src/toolchain/resolution.rs 项目层循环与 project_selection)。

    不补这一点,页面会显示全局或版本文件指定的 Maven,而用户授权后实际构建会用 wrapper,两边对不上。

    第一期:只展示,不执行任何项目代码

    前置条件:#1581 合并。Core 的工具链模块是随它一起进入 preview 的。

    1. Core:toolchains.discoveryPlan 输出项目文件候选。 每个工具在当前平台适用的 projectFile 候选(path、requires、home、projectKind)。只更新 toolchains.md 里宿主接口的说明,manifest schema 不变;合并后在 lithe-plugin-docs 同步契约目录。
    2. Core:记下“需要授权”。 项目层候选因 projectCodeRequiresAction 被跳过时,把 {code, tool, source: wrapper 路径} 记入 unmet,现有 schema 已允许。
    3. macOS:收集文件事实。 按 discoveryPlan 为每个查询目录及其上级目录收集 path 和 requires 的文件事实,设数量上限,超限给诊断;宿主不认识任何工具名。有 wrapper 的目录也算“有自己的项目来源”,作为查询目录。
    4. 设置页:只展示。 始终传 projectCodeAllowed: false。项目步骤显示 wrapper 路径和“运行前需要确认”,摘要说明授权后优先用 wrapper、不授权时退到哪一层。新文案走 shared/i18n/。
    5. 测试。
      • Core 单测:discoveryPlan 输出、unmet 记录、wrapper 在上级目录、缺少 requires 标记。
      • macOS:用临时工作区测试,不执行任何脚本。

    第二期:随 Build/Run 接入 toolchains.resolve 一起做

    1. 授权。 按提案 Note 第 6 节“执行仓库代码”的逐次确认规则:用户确认后,这一次操作带 projectCodeAllowed: true 解析;拒绝则退到下一层。目前没有持久的工作区信任状态,不能把“打开过项目”当成授权。
    2. 版本。 授权后才探测 wrapper 版本。或者由 Maven/Gradle 插件的提供方读取 maven-wrapper.properties、gradle-wrapper.properties 后上报,这类工具专属解析放在插件里,宿主不碰。
    3. 启动。 用 wrapper 启动时,home 为 null 不导出 home 变量和 PATH,避免把仓库根当成工具安装目录。
    4. 已知约束。 Core 目前对规范路径与声明路径不一致的项目程序一律拒绝。原生链接链验证要在平台接入时单独验证后再放开。

    为什么不放进 #1581

    #1581 已有 82 个文件、新增约 1.8 万行,正在等评审,且已是 ready 状态,每次推送都会重跑完整 CI。第二期依赖的 Build/Run 调用方在 #1581 里还不存在。上面的改动全部是新增,不需要推翻 #1581 的结构。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2后续考虑:目前不着急,可安排到后续版本area:extensionsExtensions / 扩展enhancementNew feature or requestplatform:macosMacOS的需求review: highghfind author score; see https://ghfind.com

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions