-
Notifications
You must be signed in to change notification settings - Fork 4.6k
Expand file tree
/
Copy pathloadMarkdownSkills.test.ts
More file actions
161 lines (140 loc) · 4.8 KB
/
loadMarkdownSkills.test.ts
File metadata and controls
161 lines (140 loc) · 4.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
vi.mock("./loadMarkdownSkills.js", async (importOriginal) => {
const mod = await importOriginal<typeof import("./loadMarkdownSkills.js")>();
return {
...mod,
};
});
vi.mock("../env.js", () => ({
env: {
continueHome: "/mock/home/.continue",
},
}));
describe("loadMarkdownSkills", () => {
let tmpDir: string;
let originalCwd: string;
let fs: typeof import("fs");
let path: typeof import("path");
let loadMarkdownSkills: typeof import("./loadMarkdownSkills.js").loadMarkdownSkills;
beforeEach(async () => {
fs = await import("fs");
path = await import("path");
const mod = await import("./loadMarkdownSkills.js");
loadMarkdownSkills = mod.loadMarkdownSkills;
originalCwd = process.cwd();
const os = await import("os");
tmpDir = path.join(os.tmpdir(), "skills-test");
if (fs.existsSync(tmpDir)) {
fs.rmSync(tmpDir, { recursive: true, force: true });
}
fs.mkdirSync(tmpDir, { recursive: true });
process.chdir(tmpDir);
});
afterEach(() => {
process.chdir(originalCwd);
fs.rmSync(tmpDir, { recursive: true, force: true });
});
it("returns empty skills when no skills directories exist", async () => {
const result = await loadMarkdownSkills();
expect(result.skills).toEqual([]);
expect(result.errors).toEqual([]);
});
it("loads a valid skill with files from .continue/skills", async () => {
const skillDir = path.join(tmpDir, ".continue", "skills", "my-skill");
fs.mkdirSync(skillDir, { recursive: true });
fs.writeFileSync(
path.join(skillDir, "SKILL.md"),
`---
name: Test Skill
description: A test skill
---
# Test Skill Content
This is the skill body.
`,
);
fs.writeFileSync(path.join(skillDir, "helper.ts"), "// helper code");
fs.writeFileSync(path.join(skillDir, "data.json"), "{}");
const result = await loadMarkdownSkills();
expect(result.errors).toEqual([]);
expect(result.skills).toHaveLength(1);
expect(result.skills[0].name).toBe("Test Skill");
expect(result.skills[0].description).toBe("A test skill");
expect(result.skills[0].content).toContain("Test Skill Content");
expect(result.skills[0].files).toHaveLength(2);
expect(result.skills[0].files).not.toContain(
expect.stringContaining("SKILL.md"),
);
});
it("loads a skill from a symlinked project skill directory", async () => {
const targetSkillDir = path.join(tmpDir, "shared-skill-target");
fs.mkdirSync(targetSkillDir, { recursive: true });
fs.writeFileSync(
path.join(targetSkillDir, "SKILL.md"),
`---
name: Skill Creator
description: Creates skills
---
# Skill Creator
`,
);
fs.writeFileSync(path.join(targetSkillDir, "helper.ts"), "// helper code");
const skillsDir = path.join(tmpDir, ".continue", "skills");
fs.mkdirSync(skillsDir, { recursive: true });
const symlinkPath = path.join(skillsDir, "skill-creator");
fs.symlinkSync(
targetSkillDir,
symlinkPath,
process.platform === "win32" ? "junction" : "dir",
);
const result = await loadMarkdownSkills();
expect(result.errors).toEqual([]);
expect(result.skills).toHaveLength(1);
expect(result.skills[0].name).toBe("Skill Creator");
expect(result.skills[0].path).toBe(
path.join(".", ".continue", "skills", "skill-creator", "SKILL.md"),
);
expect(result.skills[0].files).toContain(
path.join(".", ".continue", "skills", "skill-creator", "helper.ts"),
);
});
it("returns error for invalid frontmatter", async () => {
const skillDir = path.join(tmpDir, ".continue", "skills", "bad-skill");
fs.mkdirSync(skillDir, { recursive: true });
fs.writeFileSync(
path.join(skillDir, "SKILL.md"),
`---
name: ""
---
Missing description
`,
);
const result = await loadMarkdownSkills();
expect(result.skills).toEqual([]);
expect(result.errors).toHaveLength(1);
expect(result.errors[0].fatal).toBe(false);
});
it("loads multiple skills from different directories", async () => {
const skill1Dir = path.join(tmpDir, ".continue", "skills", "skill-1");
const skill2Dir = path.join(tmpDir, ".continue", "skills", "skill-2");
fs.mkdirSync(skill1Dir, { recursive: true });
fs.mkdirSync(skill2Dir, { recursive: true });
const skillContent = (name: string) => `---
name: ${name}
description: Description for ${name}
---
Content
`;
fs.writeFileSync(
path.join(skill1Dir, "SKILL.md"),
skillContent("Skill One"),
);
fs.writeFileSync(
path.join(skill2Dir, "SKILL.md"),
skillContent("Skill Two"),
);
const result = await loadMarkdownSkills();
expect(result.skills).toHaveLength(2);
const names = result.skills.map((s) => s.name).sort();
expect(names).toEqual(["Skill One", "Skill Two"]);
});
});