mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-06 19:32:58 +08:00
fix(qmd): normalize direct file collection paths
This commit is contained in:
@@ -154,6 +154,38 @@ describe("resolveMemoryBackendConfig", () => {
|
||||
expect(custom?.path).toBe(path.resolve(workspaceRoot, "notes"));
|
||||
});
|
||||
|
||||
it("normalizes direct file paths into parent-root collections", async () => {
|
||||
const tmpRoot = await fs.mkdtemp(path.join(os.tmpdir(), "qmd-backend-config-file-"));
|
||||
const workspaceDir = path.join(tmpRoot, "workspace");
|
||||
const sharedDir = path.join(tmpRoot, "shared");
|
||||
const sharedFile = path.join(sharedDir, "shared-memory.md");
|
||||
try {
|
||||
await fs.mkdir(workspaceDir, { recursive: true });
|
||||
await fs.mkdir(sharedDir, { recursive: true });
|
||||
await fs.writeFile(sharedFile, "# Shared memory\n", "utf8");
|
||||
const cfg = {
|
||||
agents: {
|
||||
defaults: { workspace: workspaceDir },
|
||||
list: [{ id: "main", default: true, workspace: workspaceDir }],
|
||||
},
|
||||
memory: {
|
||||
backend: "qmd",
|
||||
qmd: {
|
||||
includeDefaultMemory: false,
|
||||
paths: [{ path: sharedFile, name: "shared-memory" }],
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
const resolved = resolveMemoryBackendConfig({ cfg, agentId: "main" });
|
||||
const collection = resolved.qmd?.collections.find((entry) => entry.name === "shared-memory");
|
||||
expect(collection).toBeDefined();
|
||||
expect(collection?.path).toBe(sharedDir);
|
||||
expect(collection?.pattern).toBe("shared-memory.md");
|
||||
} finally {
|
||||
await fs.rm(tmpRoot, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
it("scopes qmd collection names per agent", () => {
|
||||
const cfg = qmdMultiAgentConfig([{ path: "notes", name: "workspace", pattern: "**/*.md" }]);
|
||||
const mainNames = resolveCollectionNamesForAgent(cfg, "main");
|
||||
|
||||
@@ -283,21 +283,31 @@ function resolveCustomPaths(
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
const pattern = normalizeOptionalString(entry.pattern) || "**/*.md";
|
||||
const dedupeKey = `${resolved}\u0000${pattern}`;
|
||||
let collectionPath = resolved;
|
||||
let pattern = normalizeOptionalString(entry.pattern) || "**/*.md";
|
||||
try {
|
||||
const stat = fs.statSync(resolved);
|
||||
if (stat.isFile()) {
|
||||
collectionPath = path.dirname(resolved);
|
||||
pattern = path.basename(resolved);
|
||||
}
|
||||
} catch {
|
||||
// Leave unresolved/missing paths as-is; downstream collection setup can decide how to handle them.
|
||||
}
|
||||
const dedupeKey = `${collectionPath}\u0000${pattern}`;
|
||||
if (seenRoots.has(dedupeKey)) {
|
||||
return;
|
||||
}
|
||||
seenRoots.add(dedupeKey);
|
||||
const explicitName = entry.name?.trim();
|
||||
const baseName =
|
||||
explicitName && !isPathInsideRoot(resolved, workspaceDir)
|
||||
explicitName && !isPathInsideRoot(collectionPath, workspaceDir)
|
||||
? explicitName
|
||||
: scopeCollectionBase(explicitName || `custom-${index + 1}`, agentId);
|
||||
const name = ensureUniqueName(baseName, existing);
|
||||
collections.push({
|
||||
name,
|
||||
path: resolved,
|
||||
path: collectionPath,
|
||||
pattern,
|
||||
kind: "custom",
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user