Skip to content

fix(cli): resolve dynamic imports to file:// URLs so the DB fallback works on Windows - #11238

Merged
diegosouzapw merged 1 commit into
diegosouzapw:release/v3.8.50from
pacocartones:fix/windows-esm-absolute-path-imports
Aug 23, 2026
Merged

diegosouzapw merged 1 commit into
diegosouzapw:release/v3.8.50from
pacocartones:fix/windows-esm-absolute-path-imports

Conversation

@pacocartones

Copy link
Copy Markdown
Contributor

omniroute combo list, create, delete and switch all exit 1 on Windows whenever the server is offline and the CLI takes its direct-DB fallback path:

Error: Only URLs with a scheme in: file, data, and node are supported by the
default ESM loader. On Windows, absolute paths must be valid file:// URLs.
Received protocol 'e:'

Cause

import() resolves its specifier as a URL, not as a filesystem path.

A POSIX absolute path (/home/x/src/lib/db/combos.ts) also happens to be a valid relative URL, so interpolating it into import() works by accident on Linux and macOS. A Windows absolute path is E:\checkout\src\lib\db\combos.ts, and the loader parses the leading drive letter as the URL scheme e:, which it rejects.

Four call sites build a specifier this way:

File Line
bin/cli/runtime.mjs 25, 26
bin/cli/commands/setup.mjs 19
bin/cli/commands/serve.mjs 384

runtime.mjs is the impactful one: importDbModules() is what every withRuntime/withDb caller depends on when isServerUp() returns false, so the entire offline fallback of the CLI is unreachable on Windows.

Fix

Route each specifier through pathToFileURL(...).href.

Verification

tests/unit/cli-combo-command.test.ts was already failing on Windows on a clean checkout of release/v3.8.50 (0b41259f3) — this is not a new test:

before: pass 1, fail 4
after:  pass 5, fail 0

The four failures were combo create, combo delete, combo list and combo switch, each asserting exit === 0 and getting 1.

That file also had a second, unrelated Windows problem: its withComboEnv teardown called fs.rmSync on the temp data dir while SQLite still held the file open, throwing EPERM and failing a test whose assertions had all passed. It now retries and degrades to best effort, since the OS reclaims its own temp dir anyway.

Regression guard

Adds tests/unit/cli/windows-esm-import-paths.test.ts, which does two things:

  1. greps bin/cli for the import(`${SOME_ROOT}/...`) pattern, so a new call site cannot reintroduce this;
  2. actually loads the DB fallback modules through withDb on the current platform.

Verified RED before the fix and GREEN after.

Scope

tests/unit/cli/** reports 182 tests, 170 pass, 9 fail both with and without this change — those 9 failures (aliasResolver, buildRunPlan, the outboundUrlGuard child-process specs) are pre-existing on 0b41259f3 and untouched here. I mention it so the number isn't attributed to this PR; happy to open a separate issue for them if useful.

…works on Windows

Dynamic import() resolves its specifier as a URL, not as a filesystem path. A POSIX absolute path doubles as a valid relative URL so interpolating it works by accident; a Windows absolute path begins with a drive letter, which the ESM loader parses as the URL scheme 'e:' and rejects:

  Error: Only URLs with a scheme in: file, data, and node are supported by the default ESM loader. On Windows, absolute paths must be valid file:// URLs. Received protocol 'e:'

This broke every CLI command that falls back to direct DB access when the server is offline: combo list/create/delete/switch all exited 1 on Windows. Fixed in runtime.mjs, setup.mjs and serve.mjs by routing through pathToFileURL().

tests/unit/cli-combo-command.test.ts went 1/5 to 5/5. The temp-dir teardown in that file also threw EPERM on Windows because SQLite still held the file open, failing a test whose assertions had passed; it now retries and degrades to best effort.

Adds tests/unit/cli/windows-esm-import-paths.test.ts, which greps bin/cli for the bad pattern and loads the db fallback for real. Verified RED before the fix, GREEN after.
@diegosouzapw
diegosouzapw merged commit e32b926 into diegosouzapw:release/v3.8.50 Aug 23, 2026
9 of 16 checks passed
diegosouzapw pushed a commit that referenced this pull request Aug 23, 2026
, #11267)

Three reds the PR's CI surfaced after the base advanced past the branch
cut — each discriminated with its origin PR:

1. chatcore-translation-paths 'Combo skip behavior' (shard 3/4) — REAL
   BUG in #11178: the incompatible-reasoning action derivation switched
   from the explicit fallback config to isComboStep =
   Boolean(comboStepId || comboExecutionKey). Combos whose records carry
   no explicit stepId/executionKey (plain model-list combos) had their
   explicit reasoningTransportFallback: 'skip' config silently degraded
   to 'drop', contradicting the PR's own stated intent ('combos keep
   their explicit strategy'). Fix: isComboStep now honors the isCombo
   marker (isCombo || step ids present). RED->GREEN on the exact CI
   failing test; the #10959 single-target drop defaults stay green.

2. check-db-rules-classification 'recovery zero importers' (shard 1/4)
   — STALE GATE, not dead code: #11238 converted bin/cli/runtime.mjs
   dynamic imports to the Windows-safe projectFileUrl('...') idiom, and
   the gate's importer regexes only recognized static/from/template
   import forms. recovery's only importer became invisible. Fix: gate
   pattern set extended to recognize import(projectFileUrl('…/db/<mod>.ts')).

3. mutation-test-coverage gate — #11267 added
   tests/unit/quota-exhaustion-cutoff-opencode.test.ts covering
   src/sse/services/auth.ts without registering it in stryker.conf.json
   tap.testFiles. Fix: register it (gate green locally).

Refs #9985
muhamadgalihsaputra pushed a commit to niyatna/NiyatnaRoute that referenced this pull request Sep 27, 2026
…works on Windows (diegosouzapw#11238)

Validated on the combined 12-PR batch board: cli-combo-command + windows-esm-import-paths suites pass, typecheck:core clean. pathToFileURL on the four dynamic-import call sites unbreaks the CLI offline DB fallback on Windows. Thank you @pacocartones!
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