Fix QMD CI test runtime assumptions

This commit is contained in:
Tobi Lütke 2026-05-16 23:20:47 +00:00
parent 028e8fc86f
commit ad8a371be2
No known key found for this signature in database
4 changed files with 41 additions and 28 deletions

View File

@ -27,14 +27,15 @@ let testCounter = 0; // Unique counter for each test run
const thisDir = dirname(fileURLToPath(import.meta.url));
const projectRoot = join(thisDir, "..");
const qmdScript = join(projectRoot, "src", "cli", "qmd.ts");
// Resolve tsx binary from project's node_modules (not cwd-dependent)
const tsxBin = (() => {
const candidate = join(projectRoot, "node_modules", ".bin", "tsx");
if (existsSync(candidate)) {
return candidate;
}
return join(process.cwd(), "node_modules", ".bin", "tsx");
})();
const isBunRuntime = typeof (globalThis as { Bun?: unknown }).Bun !== "undefined";
const tsxCli = join(projectRoot, "node_modules", "tsx", "dist", "cli.mjs");
const qmdCommand = isBunRuntime
? { command: process.execPath, args: [qmdScript] }
: { command: process.execPath, args: [tsxCli, qmdScript] };
function qmdRunnerArgs(args: string[]): { command: string; args: string[] } {
return { command: qmdCommand.command, args: [...qmdCommand.args, ...args] };
}
// Helper to run qmd command with test database
async function runQmd(
@ -44,7 +45,8 @@ async function runQmd(
const workingDir = options.cwd || fixturesDir;
const dbPath = options.dbPath || testDbPath;
const configDir = options.configDir || testConfigDir;
const proc = spawn(tsxBin, [qmdScript, ...args], {
const runner = qmdRunnerArgs(args);
const proc = spawn(runner.command, runner.args, {
cwd: workingDir,
env: {
...process.env,
@ -252,15 +254,15 @@ describe("CLI Skills", () => {
expect(stderr).toBe("");
expect(exitCode).toBe(0);
expect(stdout).toContain("qmd");
expect(stdout).toContain("Search markdown knowledge bases");
expect(stdout).toContain("Search local markdown knowledge bases");
});
test("gets version-matched runtime skill content", async () => {
const { stdout, stderr, exitCode } = await runQmd(["skills", "get", "qmd"]);
expect(stderr).toBe("");
expect(exitCode).toBe(0);
expect(stdout).toContain("# QMD - Quick Markdown Search");
expect(stdout).toContain("## MCP: `query`");
expect(stdout).toContain("# QMD - Query Markdown Documents");
expect(stdout).toContain("## MCP Tool: `query`");
expect(stdout).not.toContain("This file is a discovery stub");
});
@ -268,7 +270,7 @@ describe("CLI Skills", () => {
const { stdout, stderr, exitCode } = await runQmd(["skills", "get", "qmd", "--full"]);
expect(stderr).toBe("");
expect(exitCode).toBe(0);
expect(stdout).toContain("# QMD - Quick Markdown Search");
expect(stdout).toContain("# QMD - Query Markdown Documents");
expect(stdout).toContain("--- references/mcp-setup.md ---");
expect(stdout).toContain("# QMD MCP Server Setup");
});
@ -284,8 +286,8 @@ describe("CLI Skills", () => {
const { stdout, stderr, exitCode } = await runQmd(["skill", "show"]);
expect(stderr).toBe("");
expect(exitCode).toBe(0);
expect(stdout).toContain("# QMD - Quick Markdown Search");
expect(stdout).toContain("## MCP: `query`");
expect(stdout).toContain("# QMD - Query Markdown Documents");
expect(stdout).toContain("## MCP Tool: `query`");
expect(stdout).not.toContain("This file is a discovery stub");
});
@ -300,8 +302,8 @@ describe("CLI Skills", () => {
const installedSkillDir = join(installDir, ".agents", "skills", "qmd");
const installed = readFileSync(join(installedSkillDir, "SKILL.md"), "utf8");
expect(installed).toContain("# QMD - Quick Markdown Search");
expect(installed).toContain("## MCP: `query`");
expect(installed).toContain("# QMD - Query Markdown Documents");
expect(installed).toContain("## MCP Tool: `query`");
expect(installed).not.toContain("This file is a discovery stub");
expect(readFileSync(join(installedSkillDir, "references", "mcp-setup.md"), "utf8")).toContain("# QMD MCP Server Setup");
});
@ -370,7 +372,7 @@ describe("CLI Skill Commands", () => {
expect(exitCode).toBe(0);
const skillDir = join(projectDir, ".agents", "skills", "qmd");
expect(readFileSync(join(skillDir, "SKILL.md"), "utf-8")).toContain("# QMD - Quick Markdown Search");
expect(readFileSync(join(skillDir, "SKILL.md"), "utf-8")).toContain("# QMD - Query Markdown Documents");
expect(existsSync(join(projectDir, ".claude", "skills", "qmd"))).toBe(false);
expect(stdout).toContain(`✓ Installed QMD skill to ${skillDir}`);
expect(stdout).toContain("Tip: create a Claude symlink manually");
@ -388,9 +390,9 @@ describe("CLI Skill Commands", () => {
const skillDir = join(fakeHome, ".agents", "skills", "qmd");
const claudeLink = join(fakeHome, ".claude", "skills", "qmd");
expect(readFileSync(join(skillDir, "SKILL.md"), "utf-8")).toContain("# QMD - Quick Markdown Search");
expect(readFileSync(join(skillDir, "SKILL.md"), "utf-8")).toContain("# QMD - Query Markdown Documents");
expect(lstatSync(claudeLink).isSymbolicLink()).toBe(true);
expect(readFileSync(join(claudeLink, "SKILL.md"), "utf-8")).toContain("# QMD - Quick Markdown Search");
expect(readFileSync(join(claudeLink, "SKILL.md"), "utf-8")).toContain("# QMD - Query Markdown Documents");
expect(stdout).toContain(`✓ Installed QMD skill to ${skillDir}`);
expect(stdout).toContain(`✓ Linked Claude skill at ${claudeLink}`);
});
@ -408,7 +410,7 @@ describe("CLI Skill Commands", () => {
const skillDir = join(fakeHome, ".agents", "skills", "qmd");
expect(lstatSync(skillDir).isSymbolicLink()).toBe(false);
expect(readFileSync(join(skillDir, "SKILL.md"), "utf-8")).toContain("# QMD - Quick Markdown Search");
expect(readFileSync(join(skillDir, "SKILL.md"), "utf-8")).toContain("# QMD - Query Markdown Documents");
expect(stdout).toContain(`✓ Claude already sees the skill via ${join(fakeHome, ".claude", "skills")}`);
});
@ -1580,7 +1582,8 @@ describe("mcp http daemon", () => {
port: number,
options: { args?: string[]; env?: Record<string, string> } = {},
): import("child_process").ChildProcess {
const proc = spawn(tsxBin, [qmdScript, ...(options.args ?? []), "mcp", "--http", "--port", String(port)], {
const runner = qmdRunnerArgs([...(options.args ?? []), "mcp", "--http", "--port", String(port)]);
const proc = spawn(runner.command, runner.args, {
cwd: fixturesDir,
env: {
...process.env,

View File

@ -5,6 +5,17 @@ import { tmpdir } from "node:os";
import { afterEach, describe, expect, test } from "vitest";
import { findLocalConfigPath, getLocalDbPath } from "../src/collections.js";
function cliCommandArgs(command: string): { bin: string; args: string[] } {
const cliPath = join(process.cwd(), "src/cli/qmd.ts");
if (process.versions.bun) {
return { bin: process.execPath, args: [cliPath, command] };
}
return {
bin: process.execPath,
args: [join(process.cwd(), "node_modules/tsx/dist/cli.mjs"), cliPath, command],
};
}
const roots: string[] = [];
function tempProject(): string {
@ -59,9 +70,8 @@ describe("local .qmd project config", () => {
writeFileSync(join(root, ".qmd", "index.yaml"), `collections:\n docs:\n path: ${JSON.stringify(join(root, "docs"))}\n pattern: "**/*.md"\n context:\n /: Local test docs\nmodels:\n embed: local-embed-model\n rerank: local-rerank-model\n generate: local-generate-model\n`);
const home = join(root, "home");
const tsxBin = join(process.cwd(), "node_modules", ".bin", "tsx");
const runner = existsSync(tsxBin) ? tsxBin : "bun";
const output = execFileSync(runner, [join(process.cwd(), "src/cli/qmd.ts"), "status"], {
const { bin, args } = cliCommandArgs("status");
const output = execFileSync(bin, args, {
cwd: root,
encoding: "utf-8",
env: {

View File

@ -186,7 +186,7 @@ function seedTestData(db: Database): void {
for (let i = 0; i < 768; i++) embedding[i] = Math.random();
for (const doc of docs.slice(0, 4)) { // Skip large file for embeddings
db.prepare(`INSERT INTO content_vectors (hash, seq, pos, model, embedded_at) VALUES (?, 0, 0, 'embeddinggemma', ?)`).run(doc.hash, now);
db.prepare(`INSERT INTO content_vectors (hash, seq, pos, model, embedded_at) VALUES (?, 0, 0, ?, ?)`).run(doc.hash, DEFAULT_EMBED_MODEL, now);
db.prepare(`INSERT INTO vectors_vec (hash_seq, embedding) VALUES (?, ?)`).run(`${doc.hash}_0`, embedding);
}
}

View File

@ -20,8 +20,8 @@ describe("package grammar distribution", () => {
expect(pkg.files, "published package files").toContain("scripts/check-package-grammars.mjs");
expect(pkg.files, "published package files").toContain("skills/");
const qmdSkill = readFileSync(new URL("skills/qmd/SKILL.md", root), "utf8");
expect(qmdSkill).toContain("# QMD - Quick Markdown Search");
expect(qmdSkill).toContain("## MCP: `query`");
expect(qmdSkill).toContain("# QMD - Query Markdown Documents");
expect(qmdSkill).toContain("## MCP Tool: `query`");
expect(qmdSkill).not.toContain("This file is a discovery stub");
const scriptPath = join(root.pathname, "scripts", "check-package-grammars.mjs");