Skip to content

fix(windows): resolve Windows binary, ONNX, and storage bugs#65

Open
Zireael wants to merge 2 commits into
cortexkit:mainfrom
Zireael:fix/windows-doctor-issue-64
Open

fix(windows): resolve Windows binary, ONNX, and storage bugs#65
Zireael wants to merge 2 commits into
cortexkit:mainfrom
Zireael:fix/windows-doctor-issue-64

Conversation

@Zireael
Copy link
Copy Markdown
Contributor

@Zireael Zireael commented May 26, 2026

Windows-specific fixes across the TypeScript and Rust layers for issue #64.

Binary resolution:

  • findHighestCachedVersion() in resolver.ts falls back to the highest cached binary when the exact plugin version isn't in cache — handles aft doctor --fix downloading a newer version.
  • unlinkSync before renameSync on Windows in both resolver.ts and downloader.ts to avoid EEXIST when the target already exists.

ONNX Runtime detection (Windows):

  • findSystemOnnxRuntime in both onnx-runtime.ts and onnx.ts searches %ProgramFiles%, NuGet cache (%USERPROFILE%\.nuget\packages), and every %PATH% directory for onnxruntime.dll.
  • PATH entries skip version-compatibility filtering to maximize discovery.
  • Dedup logic ensures paths aren't checked twice.

Storage directory:

  • getStorageDir() in opencode.ts returns %LOCALAPPDATA%\cortexkit\aft (Windows) / ~/.local/share/cortexkit/aft (Unix), matching the runtime path used by the AFT binary.

Doctor CLI:

  • Issues summary section lists actionable bullets (missing binary, ONNX not installed, config parse errors).
  • log.success("Everything looks good.") renders in green instead of the previous red outro().

Rust layer (verified via cargo check + clippy):

  • pre_validate_onnx_runtime on Windows now actually validates via LoadLibraryExW/FreeLibrary (raw kernel32 FFI, no crate deps) instead of being a no-op.
  • ONNX_RUNTIME_INSTALL_HINT includes Windows guidance + npx @cortexkit/aft doctor hint.
  • fs::create_dir_all(storage_dir) in handle_configure so the storage root exists immediately after configure.

Diagnostics:

  • diagnoseHarness creates the storage directory on best-effort basis before reporting storage subtrees.

All Rust changes verified via cargo check --workspace --all-targets and cargo clippy --workspace --all-targets --all-features -- -D warnings.



Summary by cubic

Fixes Windows reliability across binary resolution, ONNX Runtime detection, and storage paths so aft doctor and semantic search work as expected on Windows. Also improves diagnostics and ensures storage directories are created early.

  • Bug Fixes
    • Binary: fall back to the highest cached version when the exact plugin version isn’t cached (only if newer than the plugin; never downgrade); on Windows, unlink before rename to avoid EEXIST in both resolver and downloader; fixed a JSDoc tokenization issue in findHighestCachedVersion() that broke TypeScript 6.0.3 builds.
    • ONNX: on Windows, search %ProgramFiles%, NuGet cache, and all %PATH% dirs for onnxruntime.dll; skip version checks for PATH entries; dedupe paths; Rust pre-validation now loads the DLL via LoadLibraryExW and updates the install hint.
    • Storage: use %LOCALAPPDATA%\cortexkit\aft on Windows; create the storage root during configure; doctor/diagnostics best-effort create the storage dir for clearer reports.
    • Doctor CLI: add an actionable issues summary and show a green success message when all checks pass.

Written for commit 70d677c. Summary will update on new commits. Review in cubic

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

6 issues found across 9 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/aft-cli/src/lib/onnx.ts">

<violation number="1" location="packages/aft-cli/src/lib/onnx.ts:65">
P3: Path deduplication doesn't normalize internal separators, so Windows PATH entries like `C:/Program Files/onnxruntime/lib` and `C:\Program Files\onnxruntime\lib` won't be recognized as duplicates. Consider applying `path.normalize()` before lowercasing for more robust deduplication.</violation>
</file>

Tip: instead of fixing issues one by one fix them all with cubic

Re-trigger cubic

Comment thread packages/aft-bridge/src/onnx-runtime.ts Outdated
Comment thread packages/aft-bridge/src/resolver.ts Outdated
Comment thread packages/aft-bridge/src/resolver.ts Outdated
Comment thread packages/aft-bridge/src/onnx-runtime.ts Outdated
Comment thread packages/aft-cli/src/adapters/opencode.ts Outdated
Comment thread packages/aft-cli/src/lib/onnx.ts Outdated
// Deduplicate paths
const seen = new Set<string>();
for (const dir of searchPaths) {
const normalized = dir.toLowerCase().replace(/[/\\]+$/, "");
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot May 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: Path deduplication doesn't normalize internal separators, so Windows PATH entries like C:/Program Files/onnxruntime/lib and C:\Program Files\onnxruntime\lib won't be recognized as duplicates. Consider applying path.normalize() before lowercasing for more robust deduplication.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/aft-cli/src/lib/onnx.ts, line 65:

<comment>Path deduplication doesn't normalize internal separators, so Windows PATH entries like `C:/Program Files/onnxruntime/lib` and `C:\Program Files\onnxruntime\lib` won't be recognized as duplicates. Consider applying `path.normalize()` before lowercasing for more robust deduplication.</comment>

<file context>
@@ -31,15 +31,41 @@ export function getManualInstallHint(): string {
+  // Deduplicate paths
+  const seen = new Set<string>();
+  for (const dir of searchPaths) {
+    const normalized = dir.toLowerCase().replace(/[/\\]+$/, "");
+    if (seen.has(normalized)) continue;
+    seen.add(normalized);
</file context>
Fix with Cubic

Closes cortexkit#64.

Windows-specific fixes across the TypeScript and Rust layers:

- **Binary version cache** (resolver.ts): add `findHighestCachedVersion()` to
  fall back to a newer cached binary when the exact plugin version isn't cached.
- **Windows rename safety** (resolver.ts, downloader.ts): `unlinkSync` before
  `renameSync` to avoid `EEXIST` on Windows.
- **ONNX Runtime detection** (onnx-runtime.ts, onnx.ts): search
  `%ProgramFiles%`, NuGet cache, and `%PATH%` directories for `onnxruntime.dll`.
- **Storage directory** (opencode.ts): return `%LOCALAPPDATA%\cortexkit\aft` on
  Windows instead of falling through to the Unix path.
- **Doctor output** (doctor.ts): issues summary section for actionable bullets;
  green `log.success()` instead of red `outro()` for the "looks good" message.
- **Rust pre-validation** (semantic_index.rs): `pre_validate_onnx_runtime` now
  actually validates on Windows via `LoadLibraryExW` instead of being a no-op;
  `ONNX_RUNTIME_INSTALL_HINT` includes Windows guidance.
- **Storage dir creation** (configure.rs): `fs::create_dir_all` in
  `handle_configure` so the root exists immediately after configure.
- **Diagnostic robustness** (diagnostics.ts): best-effort `mkdirSync` in
  `diagnoseHarness` before reading storage subtrees.

All Rust changes verified via `cargo check --workspace --all-targets` and
`cargo clippy --workspace --all-targets --all-features -- -D warnings`.
@Zireael Zireael force-pushed the fix/windows-doctor-issue-64 branch from 9843233 to f0a471c Compare May 26, 2026 07:38
…mination

The JSDoc for findHighestCachedVersion contained the literal text 'v*/'
which the TypeScript 6.0.3 tokenizer interprets as closing the multi-line
comment, causing 62 cascading TS errors across the file.

Replaced the glob pattern description with an explicit versioned-cache
example that avoids the */ sequence.
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review completed

Re-trigger cubic

@ualtinok
Copy link
Copy Markdown
Collaborator

Hey Zireael, thanks for taking time to send PRs for both projects. Sorry for the timing collision: we shipped a partial fix for #64 in v0.31.1 while this PR was open, which is why CI is now red.

Message from AFT's agent:

Could you rebase on the latest main (post-v0.31.1)? Once you do, several hunks will naturally drop out as already-shipped, and one section needs a small change to clear CI. Here's the breakdown:
Please keep (genuinely new, all valuable):

  • crates/aft/src/semantic_index.rs — pre_validate_onnx_runtime actually validating on Windows via LoadLibraryExW/FreeLibrary is a clear win. Currently a no-op, and getting a friendly error before fastembed's deep LoadLibrary failure is exactly what users need. The raw kernel32 FFI approach (no crate deps) is the right choice.
  • crates/aft/src/commands/configure.rs — fs::create_dir_all(storage_dir) during configure is small and low-risk.
  • packages/aft-bridge/src/onnx-runtime.ts and packages/aft-cli/src/lib/onnx.ts — NuGet cache scan + %PATH% discovery + case-insensitive dedup are well-thought-through. We don't have this and need it.
  • packages/aft-bridge/src/downloader.ts and packages/aft-bridge/src/resolver.ts (the unlinkSync before renameSync parts only) — real EEXIST fix on Windows file replacement.
  • packages/aft-cli/src/lib/diagnostics.ts — best-effort storage mkdirSync for clearer diagnostic output.

Please drop (already shipped or conflicting):

  • packages/aft-cli/src/adapters/opencode.ts getStorageDir() rewrite — after rebase, this function already returns getCortexKitStorageRoot() which resolves to the same cortexkit/aft path you computed inline. Inlining it would introduce drift if the shared helper ever changes.
  • packages/aft-cli/src/commands/doctor.ts issue bullets + log.success outro — we shipped an equivalent (slightly different shape) in v0.31.1. After rebase these hunks should fall out cleanly.
  • packages/aft-bridge/src/resolver.ts findHighestCachedVersion() — this is the one part that needs a real design decision. It's failing the existing test skips mislabeled newer cached binary instead of accepting directory name, which deliberately rejects cache directories whose label doesn't match the binary's reported version (mislabeled cache could indicate a corrupted download, a stale migration, or an injection vector). The use case in your PR description — "doctor --fix downloaded v0.30.3 but plugin still resolves by v0.29.1" — is now handled in v0.31.1 by detecting the plugin/CLI skew up front and prompting the user before downloading a binary that won't be loaded. Would you be open to dropping this hunk? If you've hit a remaining failure mode that the v0.31.1 skew detection doesn't catch, I'd love to hear the exact repro so we can fix it directly rather than via fallback.

Net after the trim should be ~150 LOC of focused Windows hardening across Rust validation, ONNX discovery, and file-replacement robustness — all CI-clean once rebased.

Happy to merge once the rebase lands and the resolver hunk is resolved one way or the other. Thanks again for the careful work — the Windows ONNX detection in particular is a real improvement.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants