Графік комітів
655 Коміти
Автор SHA1 Повідомлення Дата
arookieofc eb72b78abb fix(sdk): list conda environments from the conda on PATH (#2240) (#2273)
Python SDK discovery only scanned ~/anaconda3-style install roots and
<root>/envs — an Anaconda installed off the home dir (D:\soft\anaconda3,
ProgramData) hid every environment from the Conda Environment picker even
though 'conda env list' saw them all.

Now: the conda binary on PATH reveals its install root (<root>/Scripts or
bin → prefix), 'conda env list' adds --prefix envs kept outside envs/ and
envs_dirs configured in .condarc, and the env probe looks for python.exe at
the env root on Windows — where conda puts it — instead of only under
Scripts/ (virtualenv layout).
2026-11-09 13:32:28 +08:00
l0ng-ai 542584abb8 feat(debug): debug programs in a plugin run target (#2264) 2026-11-09 12:52:41 +08:00
arookieofc 0ccc1e687d fix(run): pin the JDWP port for Maven test forks (#2215) (#2268)
A Surefire/Failsafe fork started with suspend=y never reaches the console
with its "Listening for transport" line: surefire buffers the fork's
output until the tests run, and the tests wait for the debugger. The IDE
found no port, never attached, and Stop left an orphan debug session.

Pick a free port up front (new debug_free_port IPC), pass it to the
-Dmaven.surefire.debug/-Dmaven.failsafe.debug agent as
address=127.0.0.1:<port>, and attach right away — java-debug retries the
connect while the fork starts, so no output line is needed. A duplicated
line that does arrive later is deduplicated by port.
2026-11-09 12:50:40 +08:00
l0ng-ai 0e81c6aeb1 feat(lsp): run language servers in a plugin run target (#2250)
* feat(lsp): run language servers in a plugin run target

* test(settings): list the language server targets page
2026-11-09 12:22:21 +08:00
l0ng-ai f8e15a7980 fix(plugins): give test selection the command budget (#2258)
* fix(plugins): give test selection the command budget

* test(plugins): bound test selection timeouts by the command budget
2026-11-09 12:21:32 +08:00
ppxb d17f6755f3 fix(dap): avoid free-port race when starting debug adapters (#2262) 2026-11-09 12:10:31 +08:00
l0ng-ai 54d35d8a67 feat(lsp): language servers inside plugin-injected ranges (#2235)
* feat(lsp): language servers inside plugin-injected ranges

* chore(plugins): rebuild bundled plugins for the updated injections docs
2026-11-09 11:53:07 +08:00
arookieofc b6b09eb968 fix(delve): retry removing __debug_bin leftovers on Windows (#2257)
A just-killed dlv can still hold this session's binary while the previous
run's lock is already released, so one remove_file attempt only ever
deleted the older leftover. Retry with a short back-off so the sweep
outlasts the handle release.
2026-11-09 11:47:26 +08:00
arookieofc c90d3a7a8e fix(java): run jdtls on a new-enough JDK behind Scoop shims and project JAVA_HOME (#2230)
* fix(java): run jdtls on a new-enough JDK behind Scoop shims and project JAVA_HOME

Two ways jdtls ended up on a JDK too old for its bundles (#2227):

- jdtls_min_java resolved the command's own path to derive the install
  root, but a Scoop shim (shims\jdtls.exe) hides the release layout, so
  the bundles' real requirement fell back to JDTLS_MIN_JAVA (21) while a
  1.64 install needs JavaSE 25. Extract the resolve/follow-shim flow
  from launch_directly into jdtls::script_for and share it.
- configure_jdtls only wrote JAVA_HOME when the config had none, so a
  project JAVA_HOME (JDK 8 for compilation) won over the chosen
  server_jdk. Probe the configured value: a home too old or incomplete
  for the server is replaced by server_jdk or any usable JDK; an
  unresolvable explicit value stays (the user's call).

* test(java): compare JDK homes against canonical paths

jdk_at reports the canonicalized home (macOS /var -> /private/var,
Windows 8.3 short names), which configure_jdtls now writes to JAVA_HOME.
Have test_jdk canonicalize too, and assert the runtimes/JAVA_HOME values
against the Jdk.home fields instead of raw fixtures.path() joins, which
also differ on Windows when the join arg uses forward slashes.

* test(jdtls): compare JAVA_HOME against the canonical jdk home

test_jdk now canonicalizes home, so the duplicate-versions assertion must
compare against server.home rather than the raw tempdir join, which on
Windows carries 8.3 short names.
2026-11-09 11:08:28 +08:00
l0ng-ai 13b590f2c7 feat(plugins): let test frameworks select tests to rerun (#2228)
* feat(plugins): let test frameworks select tests to rerun

* test(smoke): await Rerun Failed Tests
2026-11-09 10:08:51 +08:00
l0ng-ai 60b19b2ffb Revert "fix(agents): stop defaulting new tasks to bypass" (#2234)
Reverts #2232: new agent tasks default to Bypass again.
2026-11-09 09:55:17 +08:00
l0ng-ai 73b3a99699 fix(agents): stop defaulting new tasks to bypass (#2232)
New agent tasks defaulted to Bypass whenever the provider offered it, whatever the user had chosen. A task now starts with the settings shown in the composer: the provider's reported mode, or Ask for Cursor. An explicit choice is kept, including Bypass, and running tasks keep their own mode. Cached provider settings could hold a Bypass written automatically with no record of its source, so a cached bypass is dropped on load, read and save while the option stays offered.

Fixes #740
2026-11-09 09:46:57 +08:00
l0ng-ai 3dac5b8bdc fix(plugins): report Problems to plugins in remote projects (#2223) 2026-11-09 09:18:11 +08:00
l0ng-ai fd8b4ff14c fix(terminal): resume pasted input as soon as the PTY accepts more (#2220) 2026-11-09 09:17:30 +08:00
f70eb13f75 fix(process): don't spawn taskkill when the child started nothing (#2056)
`kill_tree` and `kill_tree_of` run `taskkill /T /F /PID` on Windows even when the child has no descendants, which is the common case for a program a plugin started, read from and closed. `taskkill` is a process spawn — ~0.7 s here, measured on this machine — and it runs inside host calls that are inside a plugin call's budget: dropping eight process handles at once overran a 5 s budget, so the plugin was trapped for something the host did.

When `descendants(pid)` is empty the child itself is all there is to kill, and both callers already do that (`kill_tree` follows with `child.kill()` + `child.wait()`, `kill_tree_of` leaves the child to its owner), so the spawn buys nothing. Skip it.

Verified:

- `cargo test -p ide-core` → 77 passed.
- `cargo test -p ide-host --test plugins` → 95 passed, including `a_plugin_keeps_a_process_running_behind_a_handle`, which fails on unmodified `main` on Windows (`plugin "misbehave" timed out after 5s` at its `childdrop` step, which drops eight handles) and now passes in 9.7 s instead of 20 s.
- clippy `--all-targets -D warnings` and `cargo fmt --check` clean; no component or WIT change, so nothing to rebuild.

Co-authored-by: chao <[email protected]>
Co-authored-by: l0ng-ai <[email protected]>
2026-11-09 09:14:41 +08:00
l0ng-ai 337bf4b1ca fix(terminal): configure ConPTY compatibility on Windows (#2180) 2026-11-09 09:12:20 +08:00
l0ng-ai 047cac209b feat(plugins): plugin API 1.4 (#2207)
Plugin API 1.4: grants for unencrypted HTTP, local sockets, IDE commands and owned database sources; window status items, output channels, content tabs, editor selections, decorations, search, Problems and VCS reads; runs, keyed terminals with exit events, plugin run targets, dynamic run configurations and test parsers; language features, injections, snippets and menu locations; plugin MCP tools on the built-in server; four official API examples. Released 1.3 plugins keep working.
2026-11-09 08:40:40 +08:00
SunZhiQiang 1f2d86f793 feat(agents): load Claude's models and effort before the first task (#2212)
New Agent Task showed no model, effort or mode for Claude until an agent had run a task. The `initialize` request that already loads commands also returns those options, so they are now remembered and shown, with one extra `get_settings` request to read the configured effort. No prompt or session starts, a failed lookup is not repeated, and a session's own report always wins, in memory and on disk.

Co-authored-by: panda-student <[email protected]>
2026-11-09 08:34:46 +08:00
lleviathe 8dd29bad41 feat(workbench): toggle the toolbar, status bar and tool window bars from View › Appearance (#2206)
The main toolbar and status bar could not be hidden, Tool Window Bars was a Settings row only, and widgets could be switched only from the status bar's context menu. View > Appearance now has Toolbar, Tool Window Bars, Status Bar and Status Bar Widgets, with check marks in the macOS and in-app menus, plus Settings toggles. Both new settings default to shown. With the toolbar hidden, the window keeps a compact header with the title, which Distraction Free now shares.

Controls stay reachable with a bar hidden: the Git branches popup and background tasks have their own hosts, and background tasks has an action.

Co-authored-by: lleviathe <[email protected]>
2026-11-09 07:20:54 +08:00
l0ng-ai 75565927d8 fix(plugins): cover indexed code names and translate rename refusals (#2209)
The refusal added for indexed-only renames missed code names in Go, Ruby and PHP, ran without the rename cancellation, and was English only. It now covers those node kinds, honours cancellation, and translates the hint.
2026-11-09 07:15:13 +08:00
Pedro Pessoa 02ff61e6a7 fix(plugins): refuse indexed-only renames of code identifiers the language server can't rename (#2205)
When no language server answers a rename (none running, or no rename
support) and the indexed anchor under the caret is a code identifier,
prepare and rename now refuse instead of renaming only the plugin's
anchors, which left the declaration, imports and file name behind.
Anchors in strings, comments, attribute values or files without a
grammar keep their indexed rename.

Closes #2204
2026-11-09 06:46:56 +08:00
lleviathe 1dbebefa94 fix(lsp): end the earlier task when a progress token begins again (#2199)
Some servers reuse one `$/progress` token for concurrent work (PHPantom sends begin, begin, end, end). The second begin overwrote the first task, which never got a done event and stayed at 0% in the background tasks popup. A begin on a token with a live task now ends that task first. The progress map keeps one entry per token, so busy status and idle waits count as before.

Co-authored-by: lleviathe <[email protected]>
2026-11-09 06:01:48 +08:00
Pedro Pessoa e0982cc51d feat(plugins): brand document-indexer gutter markers with marker icons (#2196)
Indexed markers (Edges.markers) were always drawn with the navigation glyph,
so a plugin couldn't tell its marker kinds apart. A [[contributes.markerIcons]]
entry can now claim them by key prefix (`markers`), with an optional
`tooltip` shown above the targets. The host matches the longest prefix and
sends the declaration id with each marker; the editor resolves the icon and
the translated tooltip from the projected declaration. Manifest only, under
the existing API 1.3 gate of markerIcons.

Closes #2194
2026-11-09 04:53:03 +08:00
l0ng-ai a41fe86d47 fix(agents): list native Codex skills in command completion (#2190)
Native Codex sessions never requested `skills/list` or published available commands, so slash completion showed no skills. New, resumed and forked sessions now publish enabled skills as `$<name>`, and `skills/changed` refreshes them. Failed or unsupported requests stay silent.
2026-11-09 03:56:34 +08:00
l0ng-ai 7579ecbbe1 fix(build-tools): load Maven and Gradle builds of linked workspace projects (#2187)
The Maven and Gradle tool windows disappeared in a workspace, because detection only inspected the workspace metadata folder. They now discover builds in every linked project; models, caches, Maven profile choices, refreshes and run directories use the owning project, and Java reload notifications target its build files. CMake already handled linked projects. Spring's endpoint filter is unchanged.

Fixes #932
2026-11-09 03:40:12 +08:00
Deng Liuтаdengliu 3dae4ef729 feat(plugins): support secondary split on [[contributes.views]] (#2185)
Plugin tool windows could only target the primary split of their dock, because the view was never registered as secondary. An optional secondary = true on [[contributes.views]], gated to plugin API 1.3, places a view in Left Bottom, Right Bottom or Bottom Right. Existing plugins stay where they are, and a user's saved layout wins.

Co-authored-by: dengliu <[email protected]>
2026-11-09 03:35:57 +08:00
l0ng-ai 067feac89c fix(debugger): wait for slow launch and attach without a deadline (#2186)
Launch and attach were cut off after 60 seconds, so a slow interpreter start failed with "debug adapter did not answer launch in time". They now wait for the adapter's result: an adapter error or a closed connection still fails startup, Stop cancels it without an error, and other request deadlines stay.

Fixes #1773
2026-11-09 03:33:31 +08:00
l0ng-ai a7a00da263 fix(java): reject unusable language server JDKs (#2184)
An installed JDK that cannot run, such as an Intel-only JDK on Apple silicon, was registered as a project runtime and could crash Java language server initialization even with a working JDK selected. Each JDK's executable is now probed before selection, off the UI thread and outside the cache lock; unusable JDKs are left out, working Java 8 runtimes stay, and macOS bundle paths are accepted. An explicit choice that cannot run reports its actual executable. Since JDT keeps VM installs in its workspace, a project with an excluded JDK gets one fresh workspace; everyone else keeps their path.

Fixes #1668
2026-11-09 03:21:47 +08:00
misswellтаmisswell 9f9a2d8cf0 feat(run): share Java preparation and add incremental build policies (#2156)
Run and Debug now share one Java preparation path: save documents, build with the configured policy, resolve the module classpath and JDK, and stop on a failed build. Incremental Make is the default; Rebuild, NoBuild and Build-no-error-check are persisted on the run configuration, and the form offers only what a build tool supports. Delegated Gradle goes through the same path, Debug reports save failures, Maven snapshots honour Rebuild, and scoped diagnostics are retained so incremental Maven cannot erase compilation errors.

Co-authored-by: misswell <[email protected]>
2026-11-09 03:18:13 +08:00
l0ng-ai 43bcd66b2b fix(terminal): write process input off the UI thread (#2183)
A child that stopped reading its input could freeze the whole window, because terminal input was written synchronously on the UI thread. Terminal, Run and debug stdin now share a per-session ordered writer queue bounded to 4 MiB and 1,024 writes. An overflow rejects the whole write and shows an error; closing or killing a session discards pending input without waiting for the child, and an explicit stdin EOF drains accepted writes first.

Refs #2160
2026-11-09 03:06:46 +08:00
l0ng-aiтаkrmbzds ea8e04e448 fix(debugger): preserve Ruby output and session cleanup (#2182)
Fixes found while verifying Ruby debugging. An entry point with no arguments reached Ruby's single-string exec in rdbg, so spaces and shell syntax were interpreted; it now goes through ruby -S -- and stays literal. rdbg sends no DAP output or process events, so its output streams are forwarded and drained at shutdown, and the launched process group is terminated on Stop or a failed start; attach leaves the process alone. Bundler lookup respects BUNDLE_GEMFILE and gems.rb, gem discovery uses the configuration's environment, and the missing debug gem message is translated.

Refs #2170

Co-authored-by: krmbzds <[email protected]>
2026-11-09 02:22:04 +08:00
arookieofc b9d18250f0 feat(settings): toggle main menu focus on a lone Alt press (#2174)
A lone Alt press always opened or focused the main menu, with no way to
turn it off. Add `appearance.mainMenuAlt` (default on, mirroring IDEA's
ide.windows.main.menu.focus.on.alt) in Appearance > UI options; when off,
Alt key combinations keep working but pressing Alt alone does nothing.

Closes l0ng-ai/openidea#1155
2026-11-09 02:12:28 +08:00
Kerem Bozdas 75607c0bbf feat(debugger): debug Ruby programs and tests with rdbg (#2173)
Ruby files, `rails server`, Rake tasks, RSpec and Minitest configurations
can be debugged with rdbg, using the project's Ruby. In a Bundler project
it runs through the bundle; if the bundle lacks the `debug` gem, debugging
stops with an error asking to add `gem "debug"` to the Gemfile.
2026-11-09 01:41:27 +08:00
misswellтаmisswell c133d2dba9 feat(hotswap): make Reload Changed Classes cancellable (#2152)
Reload Changed Classes ran an uncancellable JDT build with a fresh token. The UI now allocates a request id, offers Cancel Hot Swap Build and treats cancellation as cancelled rather than a failed reload; overlapping reloads no longer overwrite the active request. A cancelled build can write class files without publishing their build deltas, so java-debug cannot recover them on the next build: after a cancel, Hot Swap reports that the session needs a restart rather than claiming success with classes left out.

Co-authored-by: misswell <[email protected]>
2026-11-09 01:39:48 +08:00
SunZhiQiang 25cd480c30 test(agents): keep ide-agent tests off the user's profile and git settings (#2168)
Four ide-agent tests failed on a Windows machine with a normal setup: skill discovery walked up from a temp project into the real profile's skills, and a fixture repo inherited the global core.autocrlf. The fixtures now bound the walk at the project and turn autocrlf off.

Co-authored-by: panda-student <[email protected]>
2026-11-09 01:26:34 +08:00
misswellтаmisswell 8427e48975 feat(maven): support toolchains file and active profiles (#2151)
Adds Maven toolchains file (-t) and active profiles (-P) settings, emitted before the goals. They combine with the Maven tool window's profile checkboxes, a configuration's own -t or -P overrides them, and repeated launches do not duplicate them. The settings do not reach jdtls's import: no toolchains file or explicit profile deactivation there.

Co-authored-by: misswell <[email protected]>
2026-11-09 01:25:06 +08:00
l0ng-ai 68782a7220 feat(workspace): find projects under a chosen folder (#2167)
Adding projects to a workspace took one folder at a time. Choosing a folder that is not itself a project now scans below it, up to four levels and a shared entry budget, without following symlinks or descending into a project and skipping dependency, output and hidden directories. The projects found appear in a checklist with linked ones disabled; a folder with none is added as before. The scan is cancellable and runs in both the create and manage dialogs.

Fixes #2102
2026-11-09 00:37:13 +08:00
l0ng-ai cb6bcd2fa2 fix(agents): discover Claude commands before the first task (#2166)
Claude Code reports its slash commands only after a session starts, so New Task listed only skills on disk. When the native provider has no remembered commands, a CLI process now runs only the initialize request, with a five-second timeout, shared by concurrent calls, and its result goes into the existing per-project store. A failed attempt keeps the disk list and is not repeated. No prompt or session is created.

ACP and other native providers still report commands after a session starts.

Fixes #2144
2026-11-09 00:27:03 +08:00
l0ng-ai a243c255fe fix(agents): group all composer commands and skills (#2163)
The shared twelve-result cap hid commands late in the order, and commands and skills looked the same. Command records now carry a source (stored tasks default to command; disk skills and Codex $skills are marked as skills), and the popup shows every match under Commands and Skills headers in the existing virtualized list, with keyboard selection skipping headers. File completion keeps its cap.

Fixes #2145
2026-11-08 23:38:20 +08:00
e7287394d1 feat(mcp): add an opt-in built-in IDE server (#2149)
Serve the open projects to MCP clients and the IDE's agents: files, search, symbols, problems, edits through IDE documents, run and build with confirmation in the project's window, and Git status and diff.

Co-authored-by: haruka <[email protected]>
Co-authored-by: imacross <[email protected]>
2026-11-08 22:46:42 +08:00
Shohruh Ismoilovтаshohruh-genius fff2c35181 fix(go): enable semantic colors and Go scheme settings (#2017)
Go files showed no semantic colours because gopls semantic tokens were not requested, and Color Scheme had no Go page.

gopls is now initialised with semantic tokens, constants, package variables and package references get Go-specific roles, and Color Scheme has a Go page with a preview.

Siblings covered: Go-specific attributes inherit from Language Defaults, Reset restores them, Chinese labels show in the Color Scheme tree, and a user's own gopls settings are kept.

Co-authored-by: shohruh-genius <[email protected]>
2026-11-08 22:28:20 +08:00
Shohruh Ismoilovтаshohruh-genius c20f4c0e84 fix(kotlin): highlight declarations and semantic roles (#2097)
Kotlin files showed declarations, parameters, fields, annotations, KDoc and escapes in generic lexer colours, because the CodeMirror mode alone drove their highlighting.

Kotlin now gets supplemental backend marks from its tree-sitter grammar, which take precedence over lexer marks while LSP semantic marks stay innermost. The semantic provider also maps the mutable and operator-declaration tokens.

Siblings covered: other grammars keep their parameter colours, and constructor default values are highlighted as values.

Co-authored-by: shohruh-genius <[email protected]>
2026-11-08 21:56:26 +08:00
misswellтаmisswell c1e5db9511 fix(java): count only the launched module's jdtls compile errors (#2147)
jdtls reports diagnostics for every imported project, so a module launch was treated as having compile errors because of unrelated sibling modules or its own test sources.

Launch errors now count only the launched module and the modules on its classpath, and application launches ignore test sources. A build with errors becomes a success only when the scope is known and nothing in it fails; if the classpath cannot be resolved, all errors are kept. What a launch does with reported errors is unchanged.

Siblings covered: symlinked and Windows-cased paths, Gradle and Maven output folders, and module paths.

Co-authored-by: misswell <[email protected]>
2026-11-08 21:45:53 +08:00
l0ng-ai fd717d2305 fix(vcs): prevent removing worktrees containing the open project (#2150)
Removing a worktree could delete the folder the window had open: only the main worktree was blocked, so a linked worktree opened as the project, or one containing the project, went after one confirmation, and Force Remove discarded its changes.

`vcs_remove_worktree` now compares canonical paths and refuses a target that is the project root or an ancestor of it, with or without force, before running git. Worktrees below the project root stay removable, including a project opened on a parent folder.

Sibling covered: the Worktrees tab disables Remove for such a worktree and says why.
2026-11-08 21:21:28 +08:00
l0ng-ai b57fba8b43 fix(agents): preserve sign-in failure details (#2141)
Any agent error containing the substring "auth" was replaced by generic sign-in guidance and the agent's own message was dropped, so a real failure could not be told apart and errors about an "author" looked like a sign-in problem.

Sign-in failures are now recognised by ACP's auth-required code or by whole authentication words and phrases. The guidance keeps the agent's text after it, and the code and message are logged. A Registry agent that advertises a terminal login now gets that command for the exact binary being launched.

Siblings covered: session creation, prompts and the native Codex adapter all use the same check.

Refs #2080
2026-11-08 20:34:39 +08:00
l0ng-aiтаjaw52 0bfd4fa3cc feat(app): install the openidea command on macOS, Windows and Linux (#2009)
Adds Install/Uninstall 'openidea' Command actions. macOS uses the bundle launcher, Windows a user PATH wrapper and named pipe, and Linux the executable/AppImage path with a PATH hint. Files, folders, positions and `diff` go to the running app or start it.

Closes #1286

Co-authored-by: jaw52 <[email protected]>
2026-11-08 19:25:50 +08:00
Shohruh Ismoilov f42d10d86c fix(run): canonicalize complete Windows Tomcat roots (#2096) 2026-11-08 18:08:14 +08:00
l0ng-aiтаClaude 78784837d1 fix(icons): restore the light rounded-square backing on the app icon (#2125)
Reverts #2112. The app icon, its platform sizes and the source SVGs go back to the
version with the light rounded-square backing.

Co-authored-by: Claude <[email protected]>
2026-11-08 17:46:46 +08:00
arookieofc f6e942dd00 feat(languages): start Laravel LSP next to Intelephense in Laravel projects (#2117)
Laravel ships a first-party language server (laravel/lsp, the one behind
the official VS Code/Zed/Sublime extensions) that answers hover,
definition and completion inside config('…'), route('…') and view('…')
calls — places Intelephense returns null.

Register it in languages/php.toml after Intelephense and the phpactor
fallback (Intelephense keeps hover, rename and symbols for PHP code),
gated by require-root-marker on artisan so it only starts in Laravel
projects — the same pattern angular-language-server uses for
angular.json.

Add a ToolSpec so Settings › Language Servers can install it: GitHub
releases carry plain per-platform binaries (server-v*-<arch>-<os>[.exe]),
which Method::Release + ArchiveKind::Raw already handle; the versioned
asset name lands in bin/ via the usual link/wrapper step. laravel-lsp
runs the project's PHP, so needs stays empty (PHP detection is the
project interpreter's job).

Closes #2100
2026-11-08 17:36:30 +08:00
arookieofc f07627ada6 fix(icons): drop the light rounded-square backing from the app icon (#2112)
* fix(icons): drop the light rounded-square backing from the app icon

The source SVGs drew an #EAE7E0 rounded rect behind the mark, which shows
as a pale border/frame around the icon on dark taskbars and in the app
window chrome. Remove the backing rect from both openidea.svg and
openidea-windows.svg, enlarge the mark to fill the canvas (scale 1.55 and
1.8 respectively), and regenerate the raster set with the tauri icon
toolchain.

Closes #2111

* fix(run): skip the drive prefix when canonicalizing verbatim roots

canonical_path walks a path component by component so it can compare a
not-yet-created base with existing sources. On Windows, a verbatim root
(\?\D:\...) puts a bare \?\D: Prefix component first; canonicalizing
that prefix alone fails with ERROR_INVALID_FUNCTION (GetFinalPathNameByHandle
has no directory form for a bare drive), aborting prepare() before any
work — the verbatim-roots test fails on windows-latest.

Skip Component::Prefix: the drive prefix has nothing to canonicalize, and
the RootDir right after it resolves the drive itself.

This fixes the same upstream-main failure tracked in #2057/#2096, scoped
to this branch so the icon change doesn't inherit a red job.
2026-11-08 17:04:03 +08:00