feat(java): add mise version manager support and refactor detection#84
Conversation
…ogic - Add scan_java_dir() helper to filter symlinks and scan directories - Implement find_mise_java() for ~/.local/share/mise/installs/java/ - Refactor find_sdkman_java() to scan candidates dir instead of 'current' - Fix import paths to use absolute crate::core::java:: paths - Add mise detection to Linux and macOS candidates Reviewed-by: Claude Sonnet 4.5
- Regenerate ts-rs bindings with single-line type definitions - Add new bindings: account_storage.ts, java module types - Update all existing binding files to compact format - Add generated types for old UI package Reviewed-by: Claude Sonnet 4.5
|
@BegoniaHe is attempting to deploy a commit to the retrofor Team on Vercel. A member of the Team first needs to authorize it. |
There was a problem hiding this comment.
Sorry @BegoniaHe, your pull request is larger than the review limit of 150000 diff characters
There was a problem hiding this comment.
Pull request overview
This PR expands the Java subsystem (detection + resolution) and refreshes Rust→TypeScript bindings, while also switching the Tauri build to a new ui-new frontend package.
Changes:
- Add new Java modules for detection/validation/priority resolution (including mise + improved SDKMAN handling) and wire launch-time Java selection through a priority resolver.
- Introduce/activate the new
packages/ui-newfrontend and update Tauri config to build/run it. - Add/regen ts-rs bindings (plus a new
dropout-macrosproc-macro crate) and update repo tooling/config around generation and formatting.
Reviewed changes
Copilot reviewed 97 out of 100 changed files in this pull request and generated 17 comments.
Show a summary per file
| File | Description |
|---|---|
| src-tauri/tauri.conf.json | Switches Tauri dev/build to @dropout/ui-new and its dist output. |
| src-tauri/src/main.rs | Uses priority-based Java resolution; updates Java-related Tauri commands and async calls. |
| src-tauri/src/core/manifest.rs | Adds ts-rs TS exports for version manifest structs. |
| src-tauri/src/core/java/detection.rs | New Java candidate detection (PATH + platform paths + SDKMAN/mise helpers). |
| src-tauri/src/core/java/validation.rs | New Java validation/parsing helpers (version, arch, vendor, compatibility). |
| src-tauri/src/core/java/priority.rs | New “priority: instance > global > preferred > auto-detect” Java resolver. |
| src-tauri/src/core/java/persistence.rs | New persistence for user-defined/preferred Java paths. |
| src-tauri/src/core/java/error.rs | New unified Java error type. |
| src-tauri/src/core/java/provider.rs | New provider trait abstraction for Java distributions. |
| src-tauri/src/core/java/providers/mod.rs | Provider module wiring/export. |
| src-tauri/src/core/java/providers/adoptium.rs | Adoptium provider implementation (catalog/releases/available versions). |
| src-tauri/src/core/instance.rs | Adds TS export + instance-level Java override field. |
| src-tauri/src/core/game_version.rs | Adds ts-rs exports/annotations for game version JSON types. |
| src-tauri/src/core/forge.rs | Adds ts-rs exports/annotations for Forge-related types. |
| src-tauri/src/core/fabric.rs | Adds ts-rs exports/annotations for Fabric-related types. |
| src-tauri/src/core/downloader.rs | Adds ts-rs exports/annotations for downloader types. |
| src-tauri/src/core/config.rs | Adds ts-rs exports/annotations for config types. |
| src-tauri/src/core/auth.rs | Adds ts-rs exports/annotations for auth types; changes OAuth client id. |
| src-tauri/src/core/assistant.rs | Adds ts-rs exports/annotations for assistant types. |
| src-tauri/src/core/account_storage.rs | Adds ts-rs exports/annotations for account storage types. |
| src-tauri/Cargo.toml | Adds ts-rs dependency and new dropout-macros crate dependency. |
| Cargo.toml | Expands workspace members to include crates/*. |
| crates/macros/Cargo.toml | New proc-macro crate manifest. |
| crates/macros/src/lib.rs | New #[dropout::api] proc-macro to generate TS invoke wrappers via tests. |
| package.json | Adds a generation script for bindings + formatting. |
| biome.json | Enables Tailwind directive parsing for Biome CSS parsing. |
| .pre-commit-config.yaml | Updates tsconfig exclusion to include ui-new. |
| .changes/config.toml | Registers the new dropout-macros package for changes tooling. |
| .changes/ts-bindings.md | Changeset note for adding ts-rs bindings. |
| .changes/dropout-macros.md | Changeset note for adding the macros crate. |
| packages/ui/src/types/generated/downloader.ts | Generated TS output for legacy UI downloader progress type. |
| packages/ui-new/package.json | New ui-new package deps/scripts (React + Tailwind + Zustand + Radix). |
| packages/ui-new/index.html | New Vite HTML entry for ui-new. |
| packages/ui-new/vite.config.ts | New Vite config for ui-new. |
| packages/ui-new/tsconfig.json | New TS project references for ui-new. |
| packages/ui-new/tsconfig.app.json | New app TS config for ui-new. |
| packages/ui-new/tsconfig.node.json | New node/vite TS config for ui-new. |
| packages/ui-new/.gitignore | New package-level gitignore. |
| packages/ui-new/components.json | shadcn/ui generator config for ui-new. |
| packages/ui-new/public/icon.svg | New UI icon asset. |
| packages/ui-new/src/main.tsx | New React app entry + router setup. |
| packages/ui-new/src/index.css | New Tailwind 4 styles/theme variables and global UI styling. |
| packages/ui-new/src/lib/utils.ts | Utility cn() helper for Tailwind class merging. |
| packages/ui-new/src/lib/tsrs-utils.ts | Helpers for converting ts-rs bigint/number/string values. |
| packages/ui-new/src/lib/effects/SaturnEffect.ts | Canvas particle effect implementation used by the new UI. |
| packages/ui-new/src/types/bindings/index.ts | Barrel export for generated bindings. |
| packages/ui-new/src/types/bindings/core.ts | Generated core bindings for UI consumption. |
| packages/ui-new/src/types/bindings/config.ts | Generated config bindings for UI consumption. |
| packages/ui-new/src/types/bindings/auth.ts | Generated auth bindings for UI consumption. |
| packages/ui-new/src/types/bindings/assistant.ts | Generated assistant bindings for UI consumption. |
| packages/ui-new/src/types/bindings/downloader.ts | Generated downloader bindings for UI consumption. |
| packages/ui-new/src/types/bindings/fabric.ts | Generated Fabric bindings for UI consumption. |
| packages/ui-new/src/types/bindings/forge.ts | Generated Forge bindings for UI consumption. |
| packages/ui-new/src/types/bindings/game_version.ts | Generated game version bindings for UI consumption. |
| packages/ui-new/src/types/bindings/instance.ts | Generated instance bindings for UI consumption. |
| packages/ui-new/src/types/bindings/manifest.ts | Generated manifest bindings for UI consumption. |
| packages/ui-new/src/types/bindings/account_storage.ts | Generated account storage bindings for UI consumption. |
| packages/ui-new/src/types/bindings/java.ts | Generated Java bindings (note: overlaps with bindings/java/index.ts). |
| packages/ui-new/src/types/bindings/java/index.ts | Generated Java module bindings (catalog/install/release/installations). |
| packages/ui-new/src/types/bindings/java/persistence.ts | Generated Java persistence bindings. |
| packages/ui-new/src/types/bindings/java/providers/adoptium.ts | Generated Adoptium provider bindings. |
| packages/ui-new/src/stores/ui-store.ts | UI state store (view selection, console, version). |
| packages/ui-new/src/stores/releases-store.ts | Store for fetching GitHub releases from backend. |
| packages/ui-new/src/stores/logs-store.ts | Logs aggregation/parsing store with Tauri event listeners. |
| packages/ui-new/src/stores/instances-store.ts | Instance CRUD store and active instance tracking. |
| packages/ui-new/src/stores/game-store.ts | Version loading and game start orchestration store. |
| packages/ui-new/src/stores/auth-store.ts | Auth (offline/MS device flow) store + polling + event listening. |
| packages/ui-new/src/stores/assistant-store.ts | Assistant chat/stream store. |
| packages/ui-new/src/pages/index.tsx | Main layout shell and store initialization (sidebar/outlet/overlays). |
| packages/ui-new/src/pages/instances-view.tsx | Instances UI page (create/edit/duplicate/delete/select). |
| packages/ui-new/src/components/sidebar.tsx | Sidebar navigation component. |
| packages/ui-new/src/components/particle-background.tsx | Particle background canvas integration. |
| packages/ui-new/src/components/login-modal.tsx | Login modal UI wiring to auth store. |
| packages/ui-new/src/components/game-console.tsx | In-app console UI over logs store. |
| packages/ui-new/src/components/download-monitor.tsx | Download monitor UI (currently static demo content). |
| packages/ui-new/src/components/bottom-bar.tsx | Bottom bar (instance/version selection + start + login + console). |
| packages/ui-new/src/components/ui/badge.tsx | New shadcn-style badge component. |
| packages/ui-new/src/components/ui/button.tsx | New shadcn-style button component. |
| packages/ui-new/src/components/ui/card.tsx | New shadcn-style card component. |
| packages/ui-new/src/components/ui/checkbox.tsx | New shadcn-style checkbox component. |
| packages/ui-new/src/components/ui/dialog.tsx | New shadcn-style dialog component. |
| packages/ui-new/src/components/ui/input.tsx | New shadcn-style input component. |
| packages/ui-new/src/components/ui/label.tsx | New shadcn-style label component. |
| packages/ui-new/src/components/ui/scroll-area.tsx | New shadcn-style scroll-area component. |
| packages/ui-new/src/components/ui/select.tsx | New shadcn-style select component. |
| packages/ui-new/src/components/ui/separator.tsx | New shadcn-style separator component. |
| packages/ui-new/src/components/ui/sonner.tsx | Sonner toaster wrapper component. |
| packages/ui-new/src/components/ui/switch.tsx | New shadcn-style switch component. |
| packages/ui-new/src/components/ui/tabs.tsx | New shadcn-style tabs component. |
| packages/ui-new/src/components/ui/textarea.tsx | New shadcn-style textarea component. |
| export type JavaInstallation = { | ||
| path: string; | ||
| version: string; | ||
| is64bit: boolean; | ||
| }; |
There was a problem hiding this comment.
This JavaInstallation type (and the overall java.ts module) doesn’t match the Rust JavaInstallation shape exported from src-tauri/src/core/java/mod.rs (which includes arch, vendor, source, is_64bit and uses snake_case). Also, having both bindings/java.ts and bindings/java/index.ts means import "../types/bindings/java" will resolve to java.ts and silently ignore the generated java/index.ts. Remove/rename the conflicting file(s) and ensure the exported TS type matches the runtime payload.
| #[derive(Debug, Clone, Serialize, Deserialize, TS)] | ||
| #[serde(rename_all = "camelCase")] | ||
| #[ts( | ||
| export, | ||
| export_to = "../../packages/ui/src/types/generated/downloader.ts" | ||
| )] |
There was a problem hiding this comment.
This ProgressEvent ts-rs export still targets the legacy UI path (../../packages/ui/src/types/generated/downloader.ts) even though the rest of the bindings were moved under packages/ui-new. This will either generate types into the wrong package or leave ui-new missing the type. Update export_to to the correct ui-new bindings path (or keep it consistent across all TS exports).
| #[derive(Debug, Clone, Serialize, Deserialize, TS)] | ||
| #[serde(rename_all = "camelCase")] | ||
| #[ts( | ||
| export, | ||
| export_to = "../../packages/ui-new/src/types/bindings/config.ts" | ||
| )] | ||
| #[serde(default)] | ||
| pub struct AssistantConfig { |
There was a problem hiding this comment.
LauncherConfig is persisted to config.json, but adding #[serde(rename_all = "camelCase")] changes the on-disk schema. Existing snake_case configs will fail to deserialize and ConfigState::new() falls back to defaults (unwrap_or_default()), which can silently wipe user settings. Consider adding #[serde(alias = "min_memory")]-style aliases for backward compatibility or performing an explicit migration before switching serialization naming.
| import { useTheme } from "next-themes" | ||
| import { Toaster as Sonner, type ToasterProps } from "sonner" | ||
|
|
||
| const Toaster = ({ ...props }: ToasterProps) => { | ||
| const { theme = "system" } = useTheme() | ||
|
|
||
| return ( | ||
| <Sonner | ||
| theme={theme as ToasterProps["theme"]} |
There was a problem hiding this comment.
useTheme() from next-themes is used here, but there is no ThemeProvider in ui-new (no matches in the codebase), which will typically throw at runtime. Either wrap the app in ThemeProvider, or remove next-themes and pass a fixed theme (e.g. "dark") to Sonner since the app forces dark mode anyway.
| let vendor_name: HashMap<&str, &str> = [ | ||
| // Eclipse/Adoptium | ||
| ("temurin", "Temurin (Eclipse)"), | ||
| ("adoptium", "Eclipse Adoptium"), | ||
| // Amazon | ||
| ("corretto", "Corretto (Amazon)"), | ||
| ("amzn", "Corretto (Amazon)"), | ||
| // Alibaba | ||
| ("dragonwell", "Dragonwell (Alibaba)"), | ||
| ("albba", "Dragonwell (Alibaba)"), | ||
| // GraalVM | ||
| ("graalvm", "GraalVM"), | ||
| // Oracle | ||
| ("oracle", "Java SE Development Kit (Oracle)"), | ||
| // Tencent | ||
| ("kona", "Kona (Tencent)"), | ||
| // BellSoft | ||
| ("liberica", "Liberica (Bellsoft)"), | ||
| ("mandrel", "Mandrel (Red Hat)"), | ||
| // Microsoft | ||
| ("microsoft", "OpenJDK (Microsoft)"), | ||
| // SAP | ||
| ("sapmachine", "SapMachine (SAP)"), | ||
| // IBM | ||
| ("semeru", "Semeru (IBM)"), | ||
| ("sem", "Semeru (IBM)"), | ||
| // Azul | ||
| ("zulu", "Zulu (Azul Systems)"), | ||
| // Trava | ||
| ("trava", "Trava (Trava)"), | ||
| // Huawei | ||
| ("bisheng", "BiSheng (Huawei)"), | ||
| // Generic OpenJDK | ||
| ("openjdk", "OpenJDK"), | ||
| ] | ||
| .iter() | ||
| .cloned() | ||
| .collect(); | ||
|
|
||
| for (key, name) in vendor_name { | ||
| if lower.contains(key) { | ||
| return name.to_string(); | ||
| } | ||
| } |
There was a problem hiding this comment.
vendor_name is built as a HashMap and then iterated, but HashMap iteration order is nondeterministic. With overlapping keys (e.g. "sem" vs "semeru") this can produce inconsistent vendor detection across runs. Use an ordered list/array of (key, value) pairs and iterate in priority order. Also "albba" looks like a typo (likely intended "alibaba").
| const CLIENT_ID: &str = "fe165602-5410-4441-92f7-326e10a7cb82"; | ||
| const SCOPE: &str = "XboxLive.SignIn XboxLive.offline_access"; |
There was a problem hiding this comment.
The OAuth CLIENT_ID was changed here, which is a behavior change that can break Microsoft auth if the new client isn’t correctly configured for Device Code Flow. This change isn’t mentioned in the PR description; please confirm it’s intentional and update any related documentation/config so users aren’t unexpectedly logged out or blocked.
| <li | ||
| key={instance.id} | ||
| onClick={() => setActiveInstance(instance.id)} | ||
| onKeyDown={(e) => | ||
| e.key === "Enter" && setActiveInstance(instance.id) | ||
| } | ||
| className={`relative p-4 text-left rounded-lg border-2 transition-all cursor-pointer hover:border-blue-500 ${ | ||
| isActive ? "border-blue-500" : "border-transparent" | ||
| } bg-gray-100 dark:bg-gray-800`} |
There was a problem hiding this comment.
This clickable <li> is not keyboard-focusable (no tabIndex) and has no semantic role, so keyboard users can’t activate it reliably. Consider using a <button> inside the list item or add role="button", tabIndex={0}, and handle both Enter/Space for accessibility.
| /// Represents a game instance/profile | ||
| #[derive(Debug, Clone, Serialize, Deserialize)] | ||
| #[derive(Debug, Clone, Serialize, Deserialize, TS)] | ||
| #[serde(rename_all = "camelCase")] | ||
| #[ts( | ||
| export, | ||
| export_to = "../../packages/ui-new/src/types/bindings/instance.ts" | ||
| )] |
There was a problem hiding this comment.
Instance/InstanceConfig are persisted to instances.json, but switching to #[serde(rename_all = "camelCase")] will make existing snake_case files fail to deserialize. Because InstanceState::new() uses unwrap_or_else(|_| InstanceConfig::default()), this can silently drop all saved instances. Add field aliases (e.g. #[serde(alias = "game_dir")]) or a migration step so older installs remain readable.
| <button | ||
| type="button" | ||
| onClick={() => { | ||
| authStore.loginMode = "select"; |
There was a problem hiding this comment.
This directly mutates Zustand state (authStore.loginMode = "select"), which won’t update the underlying store or trigger re-renders reliably. Use the existing action authStore.setLoginMode("select") instead.
| authStore.loginMode = "select"; | |
| authStore.setLoginMode("select"); |
| setNewInstanceName(""); | ||
| }; | ||
|
|
||
| const confirmEdit = async () => { |
There was a problem hiding this comment.
Unused variable confirmEdit.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
HsiangNianian
left a comment
There was a problem hiding this comment.
all ts file should not upload
| @@ -0,0 +1,16 @@ | |||
| // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. | |||
| @@ -1,25 +1,9 @@ | |||
| // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. | |||
| @@ -1,32 +1,13 @@ | |||
| // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. | |||
| @@ -1,61 +1,30 @@ | |||
| // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. | |||
| @@ -0,0 +1,3 @@ | |||
| // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. | |||
| @@ -1,22 +1,16 @@ | |||
| // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. | |||
| @@ -0,0 +1,11 @@ | |||
| // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. | |||
| @@ -0,0 +1,3 @@ | |||
| // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. | |||
| @@ -0,0 +1,9 @@ | |||
| // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. | |||
There was a problem hiding this comment.
Okay, should I just directly remove them, or add into gitignore? I've noticed that #77 has also uploaded ts as bindings. Maybe we should open a new pr to fix this.
There was a problem hiding this comment.
Okay, should I just directly remove them, or add into gitignore? I've noticed that #77 has also uploaded ts as bindings. Maybe we should open a new pr to fix this.
directly remove, DONT put them into .gitignore file, its still need to use, but off topic in this PR and no need to generate them so early, the reason why #77 upload ts file is that its the goal of #77, it need migrate to the react framework, so we need upload generated ts file in #77
…matting" This reverts commit c075dd8.
0e61d6b
into
HydroRoll-Team:refactor/migrate-to-react
描述
此 PR 为 Java 检测模块添加了 mise 版本管理器支持,并重构了 SDKMAN 检测逻辑,使其更加健壮。同时更新了 TypeScript 类型绑定的格式。
更改类型
LLM 生成代码声明
模型: Claude Sonnet 4.5
相关 Issue
相关 #(如有)
更改内容
后端 (Rust)
Java 检测模块重构
新增 mise 版本管理器支持
find_mise_java()函数扫描~/.local/share/mise/installs/java/重构 SDKMAN 检测逻辑
find_sdkman_java()从检查current符号链接改为扫描整个 candidates 目录添加通用扫描辅助函数
scan_java_dir<F>()泛型函数,支持自定义过滤条件修复模块导入路径
super::改为绝对导入crate::core::java::改进文档注释
前端 (React)
配置
account_storage.ts、java/*模块类型测试
测试环境
测试用例
测试步骤
cargo tauri dev确保编译通过cargo check和cargo clippy确保无警告注意:此 PR 主要是代码重构和新增功能,建议在具有 mise/SDKMAN 环境的 Linux/macOS 系统上进行实际功能测试。
检查清单
代码质量
测试验证
文档更新
依赖项
Cargo.lock和/或pnpm-lock.yaml已更新(如果依赖项有变化)截图 / 视频
N/A(后端功能,无 UI 变更)
附加说明
技术细节
为什么添加 mise 支持?
mise (前身 rtx) 是一个现代的版本管理工具,越来越多的开发者使用它来管理 Java 等运行时。添加此支持可以提高启动器的兼容性。
符号链接过滤的重要性
版本管理器(mise/SDKMAN)通常会创建符号链接作为版本别名(如
21、lts、current),过滤这些链接可以:代码重构的影响
后续工作建议
破坏性更改说明
无破坏性更改。此 PR 完全向后兼容。
维护者专用:
提交记录:
Reviewed-by: Claude Sonnet 4.5