



























@@ -990,6 +990,129 @@ describe("QmdMemoryManager", () => {
990990);
991991});
992992993+it("recreates a managed collection when list fails but add reports the same name exists", async () => {
994+await fs.writeFile(path.join(workspaceDir, "MEMORY.md"), "# canonical root");
995+cfg = {
996+ ...cfg,
997+memory: {
998+backend: "qmd",
999+qmd: {
1000+includeDefaultMemory: true,
1001+update: { interval: "0s", debounceMs: 60_000, onBoot: false },
1002+paths: [],
1003+},
1004+},
1005+} as OpenClawConfig;
1006+1007+const removed: string[] = [];
1008+const added = new Map<string, string>();
1009+const addAttempts = new Map<string, number>();
1010+spawnMock.mockImplementation((_cmd: string, args: string[]) => {
1011+if (args[0] === "collection" && args[1] === "list") {
1012+const child = createMockChild({ autoClose: false });
1013+emitAndClose(child, "stderr", "temporary qmd list failure", 1);
1014+return child;
1015+}
1016+if (args[0] === "collection" && args[1] === "remove") {
1017+const child = createMockChild({ autoClose: false });
1018+const name = args[2] ?? "";
1019+removed.push(name);
1020+queueMicrotask(() => child.closeWith(0));
1021+return child;
1022+}
1023+if (args[0] === "collection" && args[1] === "add") {
1024+const child = createMockChild({ autoClose: false });
1025+const name = args[args.indexOf("--name") + 1] ?? "";
1026+const pattern = args[args.indexOf("--glob") + 1] ?? args[args.indexOf("--mask") + 1] ?? "";
1027+const attempts = addAttempts.get(name) ?? 0;
1028+addAttempts.set(name, attempts + 1);
1029+if (name === "memory-root-main" && attempts === 0) {
1030+emitAndClose(child, "stderr", "Collection 'memory-root-main' already exists.", 1);
1031+return child;
1032+}
1033+added.set(name, pattern);
1034+queueMicrotask(() => child.closeWith(0));
1035+return child;
1036+}
1037+return createMockChild();
1038+});
1039+1040+const { manager } = await createManager({ mode: "full" });
1041+await manager.close();
1042+1043+expect(removed).toContain("memory-root-main");
1044+expect(added.get("memory-root-main")).toBe("MEMORY.md");
1045+expect(logWarnMock).toHaveBeenCalledWith(
1046+expect.stringContaining(
1047+"qmd collection add conflict for memory-root-main: collection name already exists",
1048+),
1049+);
1050+expect(logWarnMock).not.toHaveBeenCalledWith(
1051+expect.stringContaining("qmd collection add skipped for memory-root-main"),
1052+);
1053+});
1054+1055+it("rebinds memory-root when qmd table output has a stale broad pattern", async () => {
1056+await fs.writeFile(path.join(workspaceDir, "MEMORY.md"), "# canonical root");
1057+cfg = {
1058+ ...cfg,
1059+memory: {
1060+backend: "qmd",
1061+qmd: {
1062+includeDefaultMemory: true,
1063+update: { interval: "0s", debounceMs: 60_000, onBoot: false },
1064+paths: [],
1065+},
1066+},
1067+} as OpenClawConfig;
1068+1069+const removed: string[] = [];
1070+const added = new Map<string, string>();
1071+spawnMock.mockImplementation((_cmd: string, args: string[]) => {
1072+if (args[0] === "collection" && args[1] === "list") {
1073+const child = createMockChild({ autoClose: false });
1074+emitAndClose(
1075+child,
1076+"stdout",
1077+[
1078+"Collections (2):",
1079+"",
1080+"memory-dir-main (qmd://memory-dir-main/)",
1081+" Pattern: **/*.md",
1082+"",
1083+"memory-root-main (qmd://memory-root-main/)",
1084+" Pattern: **/*.md",
1085+"",
1086+].join("\n"),
1087+);
1088+return child;
1089+}
1090+if (args[0] === "collection" && args[1] === "remove") {
1091+const child = createMockChild({ autoClose: false });
1092+const name = args[2] ?? "";
1093+removed.push(name);
1094+queueMicrotask(() => child.closeWith(0));
1095+return child;
1096+}
1097+if (args[0] === "collection" && args[1] === "add") {
1098+const child = createMockChild({ autoClose: false });
1099+const name = args[args.indexOf("--name") + 1] ?? "";
1100+const pattern = args[args.indexOf("--glob") + 1] ?? args[args.indexOf("--mask") + 1] ?? "";
1101+added.set(name, pattern);
1102+queueMicrotask(() => child.closeWith(0));
1103+return child;
1104+}
1105+return createMockChild();
1106+});
1107+1108+const { manager } = await createManager({ mode: "full" });
1109+await manager.close();
1110+1111+expect(removed).toContain("memory-root-main");
1112+expect(added.get("memory-root-main")).toBe("MEMORY.md");
1113+expect(removed).not.toContain("memory-dir-main");
1114+});
1115+9931116it("falls back to --mask when qmd collection add rejects --glob", async () => {
9941117cfg = {
9951118 ...cfg,
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。