Skip to content

Commit e7afa07

Browse files
committed
feat(skills): fan out to WorkBuddy, Trae CLI, and DSH agents
1 parent e53ef23 commit e7afa07

2 files changed

Lines changed: 41 additions & 3 deletions

File tree

‎packages/core/src/skills/agents.ts‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,8 @@ export function getAgentTargets(): AgentTarget[] {
152152
detectDirs: [join(xdgConfig, "devin")],
153153
},
154154
simple("droid", "Droid", ".factory"),
155+
// DeepSeek DSH reads global skills from <dshHome>/skills; DSH_HOME relocates the home
156+
fromBase("dsh", "DeepSeek DSH", envBase(process.env.DSH_HOME, ".dsh")),
155157
simple("forgecode", "ForgeCode", ".forge"),
156158
simple("gemini-cli", "Gemini CLI", ".gemini"),
157159
simple("github-copilot", "GitHub Copilot", ".copilot"),
@@ -224,8 +226,12 @@ export function getAgentTargets(): AgentTarget[] {
224226
simple("terramind", "Terramind", ".terramind"),
225227
simple("tinycloud", "Tinycloud", ".tinycloud"),
226228
simple("trae", "Trae", ".trae"),
229+
// Trae CLI reads global skills from ~/.traecli/skills (project-level .trae/skills stays project-only)
230+
simple("trae-cli", "Trae CLI", ".traecli"),
227231
simple("trae-cn", "Trae CN", ".trae-cn"),
228232
simple("windsurf", "Windsurf", ".codeium/windsurf"),
233+
// Tencent WorkBuddy reads global skills from ~/.workbuddy/skills
234+
simple("workbuddy", "Tencent WorkBuddy", ".workbuddy"),
229235
{
230236
id: "zcode",
231237
displayName: "ZCode",

‎packages/core/tests/skills-agents.test.ts‎

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ async function inFakeHome(fn: (home: string) => Promise<void>): Promise<void> {
3535
HERMES_HOME: process.env.HERMES_HOME,
3636
AUTOHAND_HOME: process.env.AUTOHAND_HOME,
3737
GROK_HOME: process.env.GROK_HOME,
38+
DSH_HOME: process.env.DSH_HOME,
3839
APPDATA: process.env.APPDATA,
3940
FLATPAK_XDG_CONFIG_HOME: process.env.FLATPAK_XDG_CONFIG_HOME,
4041
};
@@ -50,6 +51,7 @@ async function inFakeHome(fn: (home: string) => Promise<void>): Promise<void> {
5051
"HERMES_HOME",
5152
"AUTOHAND_HOME",
5253
"GROK_HOME",
54+
"DSH_HOME",
5355
"APPDATA",
5456
"FLATPAK_XDG_CONFIG_HOME",
5557
]) {
@@ -79,7 +81,7 @@ test("agents: registry mirrors upstream agent list minus non-symlinkable agents"
7981
const ids = getAgentTargets().map((agent) => agent.id);
8082
expect(ids).toContain("universal");
8183
expect(ids).toContain("universal-xdg");
82-
expect(getAgentTargets()).toHaveLength(65);
84+
expect(getAgentTargets()).toHaveLength(68);
8385
// eve (no global dir, upstream forces direct writes) and promptscript (project-only)
8486
// cannot participate in global symlink fan-out
8587
expect(ids).not.toContain("eve");
@@ -100,12 +102,13 @@ test("agents: expanded registry detects per-agent config dirs", async () => {
100102
await inFakeHome(async (home) => {
101103
mkdirSync(join(home, ".roo"), { recursive: true });
102104
mkdirSync(join(home, ".trae"), { recursive: true });
105+
mkdirSync(join(home, ".traecli"), { recursive: true });
103106
mkdirSync(join(home, ".gemini"), { recursive: true });
104107
mkdirSync(join(home, ".codeium", "windsurf"), { recursive: true });
105108
mkdirSync(join(home, ".snowflake", "cortex"), { recursive: true });
106109

107110
const detected = detectInstalledAgents().map((agent) => agent.id);
108-
expect(detected).toEqual(["cortex", "gemini-cli", "roo", "trae", "windsurf"]);
111+
expect(detected).toEqual(["cortex", "gemini-cli", "roo", "trae", "trae-cli", "windsurf"]);
109112

110113
// skills dirs follow each agent's own convention
111114
const targets = getAgentTargets();
@@ -118,6 +121,33 @@ test("agents: expanded registry detects per-agent config dirs", async () => {
118121
});
119122
});
120123

124+
test("agents: WorkBuddy/Trae CLI/DSH use their official global skills dirs", async () => {
125+
await inFakeHome(async (home) => {
126+
mkdirSync(join(home, ".workbuddy"), { recursive: true });
127+
mkdirSync(join(home, ".traecli"), { recursive: true });
128+
mkdirSync(join(home, ".dsh"), { recursive: true });
129+
130+
const detected = detectInstalledAgents();
131+
expect(detected.map((agent) => agent.id)).toEqual(["dsh", "trae-cli", "workbuddy"]);
132+
expect(detected.find((agent) => agent.id === "workbuddy")?.skillsDir).toBe(
133+
join(home, ".workbuddy", "skills"),
134+
);
135+
expect(detected.find((agent) => agent.id === "trae-cli")?.skillsDir).toBe(
136+
join(home, ".traecli", "skills"),
137+
);
138+
expect(detected.find((agent) => agent.id === "dsh")?.skillsDir).toBe(
139+
join(home, ".dsh", "skills"),
140+
);
141+
142+
seedCanonicalSkill("demo");
143+
const results = linkSkillToAgents("demo");
144+
expect(results.map((result) => result.agent)).toEqual(["dsh", "trae-cli", "workbuddy"]);
145+
expect(lstatSync(join(home, ".workbuddy", "skills", "demo")).isSymbolicLink()).toBe(true);
146+
expect(lstatSync(join(home, ".traecli", "skills", "demo")).isSymbolicLink()).toBe(true);
147+
expect(lstatSync(join(home, ".dsh", "skills", "demo")).isSymbolicLink()).toBe(true);
148+
});
149+
});
150+
121151
test("agents: shared-dir agents (Warp/Zed/Kimi/…) light up the universal target", async () => {
122152
await inFakeHome(async (home) => {
123153
mkdirSync(join(home, ".warp"), { recursive: true });
@@ -165,18 +195,20 @@ test("agents: OpenClaw historical alias dirs are detected and link into the exis
165195
});
166196
});
167197

168-
test("agents: VIBE_HOME/HERMES_HOME/AUTOHAND_HOME/GROK_HOME relocate their agents", async () => {
198+
test("agents: VIBE_HOME/HERMES_HOME/AUTOHAND_HOME/GROK_HOME/DSH_HOME relocate their agents", async () => {
169199
await inFakeHome(async (home) => {
170200
const customDirs = {
171201
"mistral-vibe": join(home, "custom-vibe"),
172202
hermes: join(home, "custom-hermes"),
173203
"autohand-code": join(home, "custom-autohand"),
174204
grok: join(home, "custom-grok"),
205+
dsh: join(home, "custom-dsh"),
175206
};
176207
process.env.VIBE_HOME = customDirs["mistral-vibe"];
177208
process.env.HERMES_HOME = customDirs.hermes;
178209
process.env.AUTOHAND_HOME = customDirs["autohand-code"];
179210
process.env.GROK_HOME = customDirs.grok;
211+
process.env.DSH_HOME = customDirs.dsh;
180212
for (const dir of Object.values(customDirs)) {
181213
mkdirSync(dir, { recursive: true });
182214
}

0 commit comments

Comments
 (0)