Fix Node ESM index path normalization

This commit is contained in:
Tobi Lütke 2026-05-09 17:56:03 +00:00
parent 3653f6015c
commit 656707c6b4
No known key found for this signature in database
4 changed files with 32 additions and 8 deletions

View File

@ -11,6 +11,7 @@
when the scoped clear empties all vectors.
- Hybrid search: weight RRF lists by query type so original FTS and original vector evidence get the intended 2x boost, instead of accidentally boosting the first lexical expansion. #591
- MCP: seed llama.cpp/GGML quiet env vars before launching `qmd mcp` so native logs cannot pollute stdio JSON-RPC framing. #593
- CLI: remove CommonJS `require()` calls from ESM index path normalization so `qmd --index <path>` no longer crashes with `ERR_AMBIGUOUS_MODULE_SYNTAX` on Node 22+. #634
- GPU: respect explicit `QMD_LLAMA_GPU=metal|vulkan|cuda` backend overrides instead of always using auto GPU selection. #529
- Fix: preserve original filename case in `handelize()`. The previous
`.toLowerCase()` call made indexed paths unreachable on case-sensitive

View File

@ -3,7 +3,7 @@ import type { Database } from "../db.js";
import fastGlob from "fast-glob";
import { execSync, spawn as nodeSpawn } from "child_process";
import { fileURLToPath } from "url";
import { dirname, join as pathJoin, relative as relativePath } from "path";
import { dirname, join as pathJoin, relative as relativePath, resolve as pathResolve } from "path";
import { parseArgs } from "util";
import { readFileSync, realpathSync, statSync, existsSync, unlinkSync, writeFileSync, openSync, closeSync, mkdirSync, lstatSync, rmSync, symlinkSync, readlinkSync } from "fs";
import { createInterface } from "readline/promises";
@ -173,9 +173,7 @@ function setIndexName(name: string | null): void {
let normalizedName = name;
// Normalize relative paths to prevent malformed database paths
if (name && name.includes('/')) {
const { resolve } = require('path');
const { cwd } = require('process');
const absolutePath = resolve(cwd(), name);
const absolutePath = pathResolve(process.cwd(), name);
// Replace path separators with underscores to create a valid filename
normalizedName = absolutePath.replace(/\//g, '_').replace(/^_/, '');
}

View File

@ -6,7 +6,7 @@
*/
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
import { join, dirname } from "path";
import { join, dirname, resolve } from "path";
import { homedir } from "os";
import YAML from "yaml";
@ -101,9 +101,7 @@ export function setConfigSource(source?: { configPath?: string; config?: Collect
export function setConfigIndexName(name: string): void {
// Resolve relative paths to absolute paths and sanitize for use as filename
if (name.includes('/')) {
const { resolve } = require('path');
const { cwd } = require('process');
const absolutePath = resolve(cwd(), name);
const absolutePath = resolve(process.cwd(), name);
// Replace path separators with underscores to create a valid filename
currentIndexName = absolutePath.replace(/\//g, '_').replace(/^_/, '');
} else {

View File

@ -0,0 +1,27 @@
import { describe, expect, test } from "vitest";
import { execFileSync } from "child_process";
import { mkdtempSync } from "fs";
import { tmpdir } from "os";
import { dirname, join, resolve } from "path";
import { fileURLToPath } from "url";
const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
describe("Node ESM entrypoints", () => {
test("CLI --index path normalizes via setIndexName/setConfigIndexName under Node 22+", () => {
execFileSync("bun", ["run", "build"], {
cwd: repoRoot,
encoding: "utf-8",
stdio: "pipe",
});
const indexPath = join(mkdtempSync(join(tmpdir(), "qmd-index-")), "nested", "idx");
const output = execFileSync("node", ["dist/cli/qmd.js", "--index", indexPath, "--version"], {
cwd: repoRoot,
encoding: "utf-8",
stdio: "pipe",
});
expect(output).toContain("qmd ");
}, 120_000);
});