diff --git a/CHANGELOG.md b/CHANGELOG.md index 1af3da0..4191964 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 ` 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 diff --git a/src/cli/qmd.ts b/src/cli/qmd.ts index 4ceecbe..0c3a1e1 100755 --- a/src/cli/qmd.ts +++ b/src/cli/qmd.ts @@ -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(/^_/, ''); } diff --git a/src/collections.ts b/src/collections.ts index e68ff65..a295de7 100644 --- a/src/collections.ts +++ b/src/collections.ts @@ -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 { diff --git a/test/esm-ambiguous-module.test.ts b/test/esm-ambiguous-module.test.ts new file mode 100644 index 0000000..80e61b7 --- /dev/null +++ b/test/esm-ambiguous-module.test.ts @@ -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); +});