



















@@ -285,6 +285,10 @@ describe("QmdMemoryManager", () => {
285285throw new Error(`expected missing path ${targetPath}`);
286286}
287287288+function qmdIndexConfigPath(selectedAgentId = agentId): string {
289+return path.join(stateDir, "agents", selectedAgentId, "qmd", "xdg-config", "qmd", "index.yml");
290+}
291+288292async function createManager(params?: {
289293mode?: "full" | "status" | "cli";
290294cfg?: OpenClawConfig;
@@ -1966,6 +1970,121 @@ describe("QmdMemoryManager", () => {
19661970await manager.close();
19671971});
196819721973+it("refreshes qmd index config with quoted collection values during update repair", async () => {
1974+const notesDir = path.join(workspaceDir, "Notes #1: blue");
1975+await fs.mkdir(notesDir, { recursive: true });
1976+cfg = {
1977+ ...cfg,
1978+memory: {
1979+backend: "qmd",
1980+qmd: {
1981+includeDefaultMemory: false,
1982+update: { interval: "0s", debounceMs: 0, onBoot: false },
1983+paths: [{ path: notesDir, pattern: "**/* #tag: [draft].md", name: "notes" }],
1984+},
1985+},
1986+} as OpenClawConfig;
1987+1988+let updateCalls = 0;
1989+spawnMock.mockImplementation((_cmd: string, args: string[]) => {
1990+if (args[0] === "update") {
1991+updateCalls += 1;
1992+const child = createMockChild({ autoClose: false });
1993+if (updateCalls === 1) {
1994+emitAndClose(
1995+child,
1996+"stderr",
1997+"SQLiteError: UNIQUE constraint failed: documents.collection, documents.path",
1998+1,
1999+);
2000+return child;
2001+}
2002+queueMicrotask(() => {
2003+child.closeWith(0);
2004+});
2005+return child;
2006+}
2007+return createMockChild();
2008+});
2009+2010+const { manager } = await createManager({ mode: "status" });
2011+await expect(manager.sync({ reason: "manual" })).resolves.toBeUndefined();
2012+2013+const indexConfig = await fs.readFile(qmdIndexConfigPath(), "utf8");
2014+expect(indexConfig).toContain(' "notes-main":');
2015+expect(indexConfig).toContain(` path: ${JSON.stringify(notesDir)}`);
2016+expect(indexConfig).toContain(' pattern: "**/* #tag: [draft].md"');
2017+expect(updateCalls).toBe(2);
2018+2019+await manager.close();
2020+});
2021+2022+it("forces repair remove/add even when managed collections are still listed", async () => {
2023+cfg = {
2024+ ...cfg,
2025+memory: {
2026+backend: "qmd",
2027+qmd: {
2028+includeDefaultMemory: true,
2029+update: { interval: "0s", debounceMs: 0, onBoot: false },
2030+paths: [],
2031+},
2032+},
2033+} as OpenClawConfig;
2034+2035+let updateCalls = 0;
2036+spawnMock.mockImplementation((_cmd: string, args: string[]) => {
2037+if (args[0] === "collection" && args[1] === "list") {
2038+const child = createMockChild({ autoClose: false });
2039+emitAndClose(
2040+child,
2041+"stdout",
2042+JSON.stringify([
2043+{ name: "memory-root-main", path: workspaceDir, mask: "MEMORY.md" },
2044+{ name: "memory-dir-main", path: path.join(workspaceDir, "memory"), mask: "**/*.md" },
2045+]),
2046+);
2047+return child;
2048+}
2049+if (args[0] === "update") {
2050+updateCalls += 1;
2051+const child = createMockChild({ autoClose: false });
2052+if (updateCalls === 1) {
2053+emitAndClose(
2054+child,
2055+"stderr",
2056+"SQLiteError: UNIQUE constraint failed: documents.collection, documents.path",
2057+1,
2058+);
2059+return child;
2060+}
2061+queueMicrotask(() => {
2062+child.closeWith(0);
2063+});
2064+return child;
2065+}
2066+return createMockChild();
2067+});
2068+2069+const { manager } = await createManager({ mode: "full" });
2070+await expect(manager.sync({ reason: "manual" })).resolves.toBeUndefined();
2071+2072+const removeCalls = spawnMock.mock.calls
2073+.map((call: unknown[]) => call[1] as string[])
2074+.filter((args: string[]) => args[0] === "collection" && args[1] === "remove")
2075+.map((args) => args[2]);
2076+const addCalls = spawnMock.mock.calls
2077+.map((call: unknown[]) => call[1] as string[])
2078+.filter((args: string[]) => args[0] === "collection" && args[1] === "add")
2079+.map((args) => args[args.indexOf("--name") + 1]);
2080+2081+expect(updateCalls).toBe(2);
2082+expect(removeCalls).toEqual(["memory-root-main", "memory-dir-main"]);
2083+expect(addCalls).toEqual(["memory-root-main", "memory-dir-main"]);
2084+2085+await manager.close();
2086+});
2087+19692088it("does not rebuild collections for unrelated unique constraint failures", async () => {
19702089cfg = {
19712090 ...cfg,
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。