mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-16 01:40:43 +00:00
fix(memory): rebind qmd path conflicts from add errors
This commit is contained in:
committed by
Peter Steinberger
parent
b6136e38a9
commit
e422bcfc2a
@@ -1049,6 +1049,76 @@ describe("QmdMemoryManager", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("rebinds a path-pattern conflict when qmd add reports the stale collection name", async () => {
|
||||
cfg = {
|
||||
...cfg,
|
||||
memory: {
|
||||
backend: "qmd",
|
||||
qmd: {
|
||||
includeDefaultMemory: false,
|
||||
update: { interval: "0s", debounceMs: 60_000, onBoot: false },
|
||||
paths: [{ path: workspaceDir, pattern: "**/*.md", name: "workspace" }],
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
|
||||
let staleCollectionExists = true;
|
||||
const removeCalls: string[] = [];
|
||||
const addCalls: string[] = [];
|
||||
|
||||
spawnMock.mockImplementation((_cmd: string, args: string[]) => {
|
||||
if (args[0] === "collection" && args[1] === "list") {
|
||||
const child = createMockChild({ autoClose: false });
|
||||
// Older qmd output may expose only names, so path/pattern matching cannot find this.
|
||||
emitAndClose(child, "stdout", JSON.stringify(["workspace-legacy"]));
|
||||
return child;
|
||||
}
|
||||
if (args[0] === "collection" && args[1] === "remove") {
|
||||
const child = createMockChild({ autoClose: false });
|
||||
const name = args[2] ?? "";
|
||||
removeCalls.push(name);
|
||||
if (name === "workspace-legacy") {
|
||||
staleCollectionExists = false;
|
||||
}
|
||||
queueMicrotask(() => child.closeWith(0));
|
||||
return child;
|
||||
}
|
||||
if (args[0] === "collection" && args[1] === "add") {
|
||||
const child = createMockChild({ autoClose: false });
|
||||
const name = args[args.indexOf("--name") + 1] ?? "";
|
||||
addCalls.push(name);
|
||||
if (staleCollectionExists && name === "workspace-main") {
|
||||
emitAndClose(
|
||||
child,
|
||||
"stderr",
|
||||
[
|
||||
"A collection already exists for this path and pattern:",
|
||||
" Name: workspace-legacy (qmd://workspace-legacy/)",
|
||||
" Pattern: **/*.md",
|
||||
"",
|
||||
"Use 'qmd update' to re-index it, or remove it first with 'qmd collection remove workspace-legacy'",
|
||||
].join("\n"),
|
||||
1,
|
||||
);
|
||||
return child;
|
||||
}
|
||||
queueMicrotask(() => child.closeWith(0));
|
||||
return child;
|
||||
}
|
||||
return createMockChild();
|
||||
});
|
||||
|
||||
const { manager } = await createManager({ mode: "full" });
|
||||
await manager.close();
|
||||
|
||||
expect(removeCalls).toEqual(["workspace-legacy"]);
|
||||
expect(addCalls).toEqual(["workspace-main", "workspace-main"]);
|
||||
expect(logWarnMock).toHaveBeenCalledWith(expect.stringContaining("rebinding"));
|
||||
expect(logWarnMock).not.toHaveBeenCalledWith(
|
||||
expect.stringContaining("qmd collection add skipped for workspace-main"),
|
||||
);
|
||||
});
|
||||
|
||||
it("recreates a managed collection when list fails but add reports the same name exists", async () => {
|
||||
await fs.writeFile(path.join(workspaceDir, "MEMORY.md"), "# canonical root");
|
||||
cfg = {
|
||||
|
||||
@@ -643,6 +643,18 @@ export class QmdMemoryManager implements MemorySearchManager {
|
||||
return null;
|
||||
}
|
||||
|
||||
private parseConflictingCollectionNameFromAddError(message: string): string | null {
|
||||
if (
|
||||
!normalizeLowercaseStringOrEmpty(message).includes(
|
||||
"a collection already exists for this path and pattern",
|
||||
)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
const match = /^\s*Name:\s*([a-z0-9._-]+)\s*\(qmd:\/\/[^)\s]+\/?\)\s*$/im.exec(message);
|
||||
return match?.[1] ?? null;
|
||||
}
|
||||
|
||||
private async tryRebindConflictingCollection(params: {
|
||||
collection: ManagedCollection;
|
||||
existing: Map<string, ListedCollection>;
|
||||
@@ -659,6 +671,8 @@ export class QmdMemoryManager implements MemorySearchManager {
|
||||
conflictName = this.findCollectionByPathPattern(collection, existing);
|
||||
}
|
||||
|
||||
conflictName ??= this.parseConflictingCollectionNameFromAddError(addErrorMessage);
|
||||
|
||||
if (!conflictName) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user