fix (memory/qmd): verify qmd index artifact after manual reindex

This commit is contained in:
Vignesh Natarajan
2026-02-14 20:16:28 -08:00
parent 93dd9f697e
commit 17b6809517
2 changed files with 99 additions and 0 deletions

View File

@@ -1,4 +1,7 @@
import { Command } from "commander";
import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { afterEach, describe, expect, it, vi } from "vitest";
const getMemorySearchManager = vi.fn();
@@ -273,6 +276,70 @@ describe("memory cli", () => {
expect(log).toHaveBeenCalledWith("Memory index updated (main).");
});
it("logs qmd index file path and size after index", async () => {
const { registerMemoryCli } = await import("./memory-cli.js");
const { defaultRuntime } = await import("../runtime.js");
const close = vi.fn(async () => {});
const sync = vi.fn(async () => {});
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "memory-cli-qmd-index-"));
const dbPath = path.join(tmpDir, "index.sqlite");
await fs.writeFile(dbPath, "sqlite-bytes", "utf-8");
getMemorySearchManager.mockResolvedValueOnce({
manager: {
sync,
status: () => ({ backend: "qmd", dbPath }),
close,
},
});
const log = vi.spyOn(defaultRuntime, "log").mockImplementation(() => {});
const program = new Command();
program.name("test");
registerMemoryCli(program);
await program.parseAsync(["memory", "index"], { from: "user" });
expect(sync).toHaveBeenCalledWith(
expect.objectContaining({ reason: "cli", force: false, progress: expect.any(Function) }),
);
expect(log).toHaveBeenCalledWith(expect.stringContaining("QMD index: "));
expect(log).toHaveBeenCalledWith("Memory index updated (main).");
expect(close).toHaveBeenCalled();
await fs.rm(tmpDir, { recursive: true, force: true });
});
it("fails index when qmd db file is empty", async () => {
const { registerMemoryCli } = await import("./memory-cli.js");
const { defaultRuntime } = await import("../runtime.js");
const close = vi.fn(async () => {});
const sync = vi.fn(async () => {});
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "memory-cli-qmd-index-"));
const dbPath = path.join(tmpDir, "index.sqlite");
await fs.writeFile(dbPath, "", "utf-8");
getMemorySearchManager.mockResolvedValueOnce({
manager: {
sync,
status: () => ({ backend: "qmd", dbPath }),
close,
},
});
const error = vi.spyOn(defaultRuntime, "error").mockImplementation(() => {});
const program = new Command();
program.name("test");
registerMemoryCli(program);
await program.parseAsync(["memory", "index"], { from: "user" });
expect(sync).toHaveBeenCalledWith(
expect.objectContaining({ reason: "cli", force: false, progress: expect.any(Function) }),
);
expect(error).toHaveBeenCalledWith(
expect.stringContaining("Memory index failed (main): QMD index file is empty"),
);
expect(close).toHaveBeenCalled();
expect(process.exitCode).toBe(1);
await fs.rm(tmpDir, { recursive: true, force: true });
});
it("logs close failures without failing the command", async () => {
const { registerMemoryCli } = await import("./memory-cli.js");
const { defaultRuntime } = await import("../runtime.js");

View File

@@ -215,6 +215,34 @@ async function scanMemoryFiles(
return { source: "memory", totalFiles, issues };
}
async function summarizeQmdIndexArtifact(manager: MemoryManager): Promise<string | null> {
const status = manager.status?.();
if (!status || status.backend !== "qmd") {
return null;
}
const dbPath = status.dbPath?.trim();
if (!dbPath) {
return null;
}
let stat: fsSync.Stats;
try {
stat = await fs.stat(dbPath);
} catch (err) {
const code = (err as NodeJS.ErrnoException).code;
if (code === "ENOENT") {
throw new Error(`QMD index file not found: ${shortenHomePath(dbPath)}`, { cause: err });
}
throw new Error(
`QMD index file check failed: ${shortenHomePath(dbPath)} (${code ?? "error"})`,
{ cause: err },
);
}
if (!stat.isFile() || stat.size <= 0) {
throw new Error(`QMD index file is empty: ${shortenHomePath(dbPath)}`);
}
return `QMD index: ${shortenHomePath(dbPath)} (${stat.size} bytes)`;
}
async function scanMemorySources(params: {
workspaceDir: string;
agentId: string;
@@ -633,6 +661,10 @@ export function registerMemoryCli(program: Command) {
}
},
);
const qmdIndexSummary = await summarizeQmdIndexArtifact(manager);
if (qmdIndexSummary) {
defaultRuntime.log(qmdIndexSummary);
}
defaultRuntime.log(`Memory index updated (${agentId}).`);
} catch (err) {
const message = formatErrorMessage(err);