mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-08 15:48:28 +00:00
perf(test): remove fs skill scanning from skill-commands tests
This commit is contained in:
@@ -1,48 +1,65 @@
|
|||||||
import fsSync from "node:fs";
|
|
||||||
import fs from "node:fs/promises";
|
import fs from "node:fs/promises";
|
||||||
import os from "node:os";
|
import os from "node:os";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import { beforeAll, describe, expect, it, vi } from "vitest";
|
import { beforeAll, describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
// Avoid importing/parsing the full skills loader + user home skills during unit tests.
|
|
||||||
vi.mock("@mariozechner/pi-coding-agent", () => ({
|
|
||||||
formatSkillsForPrompt: () => "",
|
|
||||||
loadSkillsFromDir: ({ dir, source }: { dir: string; source: string }) => {
|
|
||||||
try {
|
|
||||||
const entries = fsSync.readdirSync(dir, { withFileTypes: true });
|
|
||||||
const skills = entries
|
|
||||||
.filter((entry) => entry.isDirectory() && !entry.name.startsWith("."))
|
|
||||||
.map((entry) => {
|
|
||||||
const baseDir = path.join(dir, entry.name);
|
|
||||||
const filePath = path.join(baseDir, "SKILL.md");
|
|
||||||
if (!fsSync.existsSync(filePath)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
let raw = "";
|
|
||||||
try {
|
|
||||||
raw = fsSync.readFileSync(filePath, "utf-8");
|
|
||||||
} catch {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const nameMatch = raw.match(/^\s*name:\s*(.+)\s*$/m);
|
|
||||||
const descriptionMatch = raw.match(/^\s*description:\s*(.+)\s*$/m);
|
|
||||||
const name = (nameMatch?.[1] ?? entry.name).trim();
|
|
||||||
const description = (descriptionMatch?.[1] ?? "").trim();
|
|
||||||
return { name, description, source, filePath, baseDir };
|
|
||||||
})
|
|
||||||
.filter(Boolean);
|
|
||||||
return { skills };
|
|
||||||
} catch {
|
|
||||||
return { skills: [] };
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
// Avoid importing the full chat command registry for reserved-name calculation.
|
// Avoid importing the full chat command registry for reserved-name calculation.
|
||||||
vi.mock("./commands-registry.js", () => ({
|
vi.mock("./commands-registry.js", () => ({
|
||||||
listChatCommands: () => [],
|
listChatCommands: () => [],
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
vi.mock("../infra/skills-remote.js", () => ({
|
||||||
|
getRemoteSkillEligibility: () => ({}),
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Avoid filesystem-driven skill scanning for these unit tests; we only need command naming semantics.
|
||||||
|
vi.mock("../agents/skills.js", () => {
|
||||||
|
function resolveUniqueName(base: string, used: Set<string>): string {
|
||||||
|
let name = base;
|
||||||
|
let suffix = 2;
|
||||||
|
while (used.has(name.toLowerCase())) {
|
||||||
|
name = `${base}_${suffix}`;
|
||||||
|
suffix += 1;
|
||||||
|
}
|
||||||
|
used.add(name.toLowerCase());
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveWorkspaceSkills(
|
||||||
|
workspaceDir: string,
|
||||||
|
): Array<{ skillName: string; description: string }> {
|
||||||
|
const dirName = path.basename(workspaceDir);
|
||||||
|
if (dirName === "main") {
|
||||||
|
return [{ skillName: "demo-skill", description: "Demo skill" }];
|
||||||
|
}
|
||||||
|
if (dirName === "research") {
|
||||||
|
return [
|
||||||
|
{ skillName: "demo-skill", description: "Demo skill 2" },
|
||||||
|
{ skillName: "extra-skill", description: "Extra skill" },
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
buildWorkspaceSkillCommandSpecs: (
|
||||||
|
workspaceDir: string,
|
||||||
|
opts?: { reservedNames?: Set<string> },
|
||||||
|
) => {
|
||||||
|
const used = new Set<string>();
|
||||||
|
for (const reserved of opts?.reservedNames ?? []) {
|
||||||
|
used.add(String(reserved).toLowerCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolveWorkspaceSkills(workspaceDir).map((entry) => {
|
||||||
|
const base = entry.skillName.replace(/-/g, "_");
|
||||||
|
const name = resolveUniqueName(base, used);
|
||||||
|
return { name, skillName: entry.skillName, description: entry.description };
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
let listSkillCommandsForAgents: typeof import("./skill-commands.js").listSkillCommandsForAgents;
|
let listSkillCommandsForAgents: typeof import("./skill-commands.js").listSkillCommandsForAgents;
|
||||||
let resolveSkillCommandInvocation: typeof import("./skill-commands.js").resolveSkillCommandInvocation;
|
let resolveSkillCommandInvocation: typeof import("./skill-commands.js").resolveSkillCommandInvocation;
|
||||||
|
|
||||||
@@ -51,22 +68,6 @@ beforeAll(async () => {
|
|||||||
await import("./skill-commands.js"));
|
await import("./skill-commands.js"));
|
||||||
});
|
});
|
||||||
|
|
||||||
async function writeSkill(params: {
|
|
||||||
workspaceDir: string;
|
|
||||||
dirName: string;
|
|
||||||
name: string;
|
|
||||||
description: string;
|
|
||||||
}) {
|
|
||||||
const { workspaceDir, dirName, name, description } = params;
|
|
||||||
const skillDir = path.join(workspaceDir, "skills", dirName);
|
|
||||||
await fs.mkdir(skillDir, { recursive: true });
|
|
||||||
await fs.writeFile(
|
|
||||||
path.join(skillDir, "SKILL.md"),
|
|
||||||
`---\nname: ${name}\ndescription: ${description}\n---\n\n# ${name}\n`,
|
|
||||||
"utf-8",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
describe("resolveSkillCommandInvocation", () => {
|
describe("resolveSkillCommandInvocation", () => {
|
||||||
it("matches skill commands and parses args", () => {
|
it("matches skill commands and parses args", () => {
|
||||||
const invocation = resolveSkillCommandInvocation({
|
const invocation = resolveSkillCommandInvocation({
|
||||||
@@ -109,24 +110,8 @@ describe("listSkillCommandsForAgents", () => {
|
|||||||
const baseDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-skills-"));
|
const baseDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-skills-"));
|
||||||
const mainWorkspace = path.join(baseDir, "main");
|
const mainWorkspace = path.join(baseDir, "main");
|
||||||
const researchWorkspace = path.join(baseDir, "research");
|
const researchWorkspace = path.join(baseDir, "research");
|
||||||
await writeSkill({
|
await fs.mkdir(mainWorkspace, { recursive: true });
|
||||||
workspaceDir: mainWorkspace,
|
await fs.mkdir(researchWorkspace, { recursive: true });
|
||||||
dirName: "demo",
|
|
||||||
name: "demo-skill",
|
|
||||||
description: "Demo skill",
|
|
||||||
});
|
|
||||||
await writeSkill({
|
|
||||||
workspaceDir: researchWorkspace,
|
|
||||||
dirName: "demo2",
|
|
||||||
name: "demo-skill",
|
|
||||||
description: "Demo skill 2",
|
|
||||||
});
|
|
||||||
await writeSkill({
|
|
||||||
workspaceDir: researchWorkspace,
|
|
||||||
dirName: "extra",
|
|
||||||
name: "extra-skill",
|
|
||||||
description: "Extra skill",
|
|
||||||
});
|
|
||||||
|
|
||||||
const commands = listSkillCommandsForAgents({
|
const commands = listSkillCommandsForAgents({
|
||||||
cfg: {
|
cfg: {
|
||||||
|
|||||||
Reference in New Issue
Block a user