























@@ -493,6 +493,7 @@ describe("QmdMemoryManager", () => {
493493const initialUpdateCalls = spawnMock.mock.calls.filter((call) => call[1]?.[0] === "update");
494494expect(initialUpdateCalls).toHaveLength(0);
495495const watchOptions = firstWatchOptions();
496+expect(watchOptions).not.toHaveProperty("awaitWriteFinish");
496497expect(watchOptions.ignored?.(path.join(workspaceDir, "node_modules", "pkg", "note.md"))).toBe(
497498true,
498499);
@@ -502,7 +503,14 @@ describe("QmdMemoryManager", () => {
502503expect(watchOptions.ignored?.(path.join(workspaceDir, "build", "note.md"))).toBe(true);
503504expect(watchOptions.ignored?.(path.join(workspaceDir, "notes.md"))).toBe(false);
504505505-watcher.emit("change", path.join(workspaceDir, "notes.md"));
506+const notesPath = path.join(workspaceDir, "notes.md");
507+await fs.writeFile(notesPath, "hello");
508+const initialStats = await fs.stat(notesPath);
509+watcher.emit("change", notesPath, {
510+size: initialStats.size,
511+mtimeMs: initialStats.mtimeMs,
512+isDirectory: () => false,
513+});
506514expect(manager.status().dirty).toBe(true);
507515508516await vi.advanceTimersByTimeAsync(25);
@@ -514,6 +522,55 @@ describe("QmdMemoryManager", () => {
514522await manager.close();
515523});
516524525+it("delays qmd watch sync until changed file stats settle", async () => {
526+vi.useFakeTimers();
527+cfg = {
528+agents: {
529+defaults: {
530+workspace: workspaceDir,
531+memorySearch: {
532+provider: "openai",
533+model: "mock-embed",
534+store: { path: path.join(workspaceDir, "index.sqlite"), vector: { enabled: false } },
535+sync: { watch: true, watchDebounceMs: 25, onSessionStart: false, onSearch: false },
536+},
537+},
538+list: [{ id: agentId, default: true, workspace: workspaceDir }],
539+},
540+memory: {
541+backend: "qmd",
542+qmd: {
543+includeDefaultMemory: false,
544+update: { interval: "0s", debounceMs: 0, onBoot: false },
545+paths: [{ path: workspaceDir, pattern: "**/*.md", name: "workspace" }],
546+},
547+},
548+} as OpenClawConfig;
549+550+const notesPath = path.join(workspaceDir, "notes.md");
551+await fs.writeFile(notesPath, "hello");
552+const initialStats = await fs.stat(notesPath);
553+const { manager } = await createManager({ mode: "full" });
554+const watcher = watchMock.mock.results[0]?.value as {
555+emit: (event: string, ...args: unknown[]) => boolean;
556+};
557+558+watcher.emit("change", notesPath, {
559+size: initialStats.size,
560+mtimeMs: initialStats.mtimeMs,
561+isDirectory: () => false,
562+});
563+await fs.writeFile(notesPath, "hello updated");
564+565+await vi.advanceTimersByTimeAsync(25);
566+expect(spawnMock.mock.calls.filter((call) => call[1]?.[0] === "update")).toHaveLength(0);
567+568+await vi.advanceTimersByTimeAsync(25);
569+expect(spawnMock.mock.calls.filter((call) => call[1]?.[0] === "update")).toHaveLength(1);
570+571+await manager.close();
572+});
573+517574it("runs boot update in background by default", async () => {
518575cfg = {
519576 ...cfg,
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。