Skip to content

Commit 12bba7f

Browse files
authored
Merge pull request #98 from rohitg00/fix/openclaw-cleanup
refactor: deduplicate OpenClaw adapter, fix clawdbot config
2 parents 5324e45 + 02fe3f2 commit 12bba7f

6 files changed

Lines changed: 19 additions & 157 deletions

File tree

packages/agents/src/__tests__/adapters.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,10 @@ const ALL_AGENTS = AgentType.options;
3535

3636
describe('Agent Adapters', () => {
3737
describe('getAllAdapters', () => {
38-
it('should return all 44 registered adapters', () => {
38+
it('should return all 45 registered adapters', () => {
3939
const adapters = getAllAdapters();
4040
expect(adapters).toBeInstanceOf(Array);
41-
expect(adapters.length).toBe(44);
41+
expect(adapters.length).toBe(45);
4242
});
4343

4444
it('should include common agents', () => {

packages/agents/src/__tests__/clawdbot.test.ts

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -236,16 +236,6 @@ describe('ClawdbotAdapter', () => {
236236
});
237237

238238
describe('isDetected', () => {
239-
it('should detect Clawdbot from workspace skills directory', async () => {
240-
mockExistsSync.mockImplementation((path) => {
241-
return path === join(process.cwd(), 'skills');
242-
});
243-
244-
const detected = await adapter.isDetected();
245-
246-
expect(detected).toBe(true);
247-
});
248-
249239
it('should detect Clawdbot from global directory', async () => {
250240
mockExistsSync.mockImplementation((path) => {
251241
return path === join(homedir(), '.clawdbot');
@@ -287,7 +277,6 @@ describe('ClawdbotAdapter', () => {
287277

288278
await adapter.isDetected();
289279

290-
expect(mockExistsSync).toHaveBeenCalledWith(join(process.cwd(), 'skills'));
291280
expect(mockExistsSync).toHaveBeenCalledWith(join(homedir(), '.clawdbot'));
292281
expect(mockExistsSync).toHaveBeenCalledWith(join(process.cwd(), 'clawdbot.json'));
293282
});

packages/agents/src/clawdbot.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ const config = AGENT_CONFIG.clawdbot;
1010

1111
export class ClawdbotAdapter implements AgentAdapter {
1212
readonly type: AgentType = 'clawdbot';
13-
readonly name = 'Clawdbot';
14-
readonly skillsDir = config.skillsDir;
15-
readonly configFile = config.configFile;
13+
readonly name: string = 'Clawdbot';
14+
readonly skillsDir: string = config.skillsDir;
15+
readonly configFile: string = config.configFile;
1616

1717
generateConfig(skills: Skill[]): string {
1818
const enabledSkills = skills.filter(s => s.enabled);

packages/agents/src/openclaw.ts

Lines changed: 9 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1,99 +1,22 @@
11
import { existsSync } from 'node:fs';
22
import { join } from 'node:path';
33
import { homedir } from 'node:os';
4-
import type { AgentAdapter } from './base.js';
5-
import { createSkillXml } from './base.js';
6-
import type { Skill, AgentType } from '@skillkit/core';
4+
import { ClawdbotAdapter } from './clawdbot.js';
5+
import type { AgentType } from '@skillkit/core';
76
import { AGENT_CONFIG } from '@skillkit/core';
87

98
const config = AGENT_CONFIG.openclaw;
109

11-
/**
12-
* OpenClaw Agent Adapter
13-
*
14-
* OpenClaw (formerly Clawdbot) is a local-first AI agent framework with a
15-
* persistent gateway daemon. Skills use an extended YAML frontmatter schema
16-
* with `permissions`, `triggers`, and `metadata.openclaw.requires` fields.
17-
*
18-
* Key differences from Claude Code:
19-
* - Skills dir: `skills/` (not `.claude/skills/`)
20-
* - Global skills: `~/.openclaw/skills/`
21-
* - Config: `~/.openclaw/openclaw.json`
22-
* - SKILL.md frontmatter includes: permissions, triggers, metadata.openclaw
23-
* - Gateway loads skills contextually per-agent at runtime
24-
* - Skills are organized by department: skills/<dept>/<name>/SKILL.md
25-
*/
26-
export class OpenClawAdapter implements AgentAdapter {
27-
readonly type: AgentType = 'openclaw';
28-
readonly name = 'OpenClaw';
29-
readonly skillsDir = config.skillsDir;
30-
readonly configFile = config.configFile;
10+
export class OpenClawAdapter extends ClawdbotAdapter {
11+
override readonly type: AgentType = 'openclaw';
12+
override readonly name = 'OpenClaw';
13+
override readonly skillsDir = config.skillsDir;
14+
override readonly configFile = config.configFile;
3115

32-
generateConfig(skills: Skill[]): string {
33-
const enabledSkills = skills.filter(s => s.enabled);
34-
35-
if (enabledSkills.length === 0) {
36-
return '';
37-
}
38-
39-
const skillsXml = enabledSkills.map(createSkillXml).join('\n\n');
40-
41-
return `<skills_system priority="1">
42-
43-
## Available Skills
44-
45-
<!-- SKILLS_TABLE_START -->
46-
<usage>
47-
When users ask you to perform tasks, check if any of the available skills below can help complete the task more effectively. Skills provide specialized capabilities and domain knowledge.
48-
49-
How to use skills:
50-
- Invoke: \`skillkit read <skill-name>\` or \`npx skillkit read <skill-name>\`
51-
- The skill content will load with detailed instructions on how to complete the task
52-
- Base directory provided in output for resolving bundled resources (references/, scripts/, assets/)
53-
54-
Usage notes:
55-
- Only use skills listed in <available_skills> below
56-
- Do not invoke a skill that is already loaded in your context
57-
- Each skill invocation is stateless
58-
</usage>
59-
60-
<available_skills>
61-
62-
${skillsXml}
63-
64-
</available_skills>
65-
<!-- SKILLS_TABLE_END -->
66-
67-
</skills_system>`;
68-
}
69-
70-
parseConfig(content: string): string[] {
71-
const skillNames: string[] = [];
72-
const skillRegex = /<name>([^<]+)<\/name>/g;
73-
let match;
74-
75-
while ((match = skillRegex.exec(content)) !== null) {
76-
skillNames.push(match[1].trim());
77-
}
78-
79-
return skillNames;
80-
}
81-
82-
getInvokeCommand(skillName: string): string {
83-
return `skillkit read ${skillName}`;
84-
}
85-
86-
async isDetected(): Promise<boolean> {
87-
// OpenClaw workspace: skills/ dir at project root
88-
const projectSkills = join(process.cwd(), 'skills');
89-
// OpenClaw global config
16+
override async isDetected(): Promise<boolean> {
9017
const globalOpenClaw = join(homedir(), '.openclaw');
91-
// OpenClaw config file
9218
const openclawConfig = join(process.cwd(), 'openclaw.json');
9319

94-
return (
95-
(existsSync(projectSkills) && existsSync(globalOpenClaw)) ||
96-
existsSync(openclawConfig)
97-
);
20+
return existsSync(globalOpenClaw) || existsSync(openclawConfig);
9821
}
9922
}

packages/core/src/agent-config.ts

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -111,22 +111,15 @@ export const AGENT_CONFIG: Record<AgentType, AgentDirectoryConfig> = {
111111
supportsAutoDiscovery: true,
112112
},
113113

114-
// Clawdbot (legacy name for OpenClaw)
115114
clawdbot: {
116-
skillsDir: 'skills',
117-
configFile: 'CLAUDE.md',
118-
altSkillsDirs: ['.clawdbot/skills', '~/.openclaw/skills'],
119-
globalSkillsDir: '~/.openclaw/skills',
115+
skillsDir: '.clawdbot/skills',
116+
configFile: 'AGENTS.md',
117+
altSkillsDirs: ['skills', '~/.clawdbot/skills'],
120118
configFormat: 'xml',
121119
usesFrontmatter: true,
122-
frontmatterFields: [
123-
'name', 'description', 'version', 'scan_exempt',
124-
'permissions', 'triggers', 'metadata',
125-
],
126120
supportsAutoDiscovery: true,
127121
},
128122

129-
// OpenClaw (same as clawdbot — rebranded)
130123
openclaw: {
131124
skillsDir: 'skills',
132125
configFile: 'CLAUDE.md',

packages/tui/src/services/translator.service.ts

Lines changed: 2 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,5 @@
1-
export type AgentType =
2-
| 'claude-code'
3-
| 'cursor'
4-
| 'windsurf'
5-
| 'github-copilot'
6-
| 'codex'
7-
| 'gemini-cli'
8-
| 'opencode'
9-
| 'universal'
10-
| 'antigravity'
11-
| 'amp'
12-
| 'clawdbot'
13-
| 'droid'
14-
| 'goose'
15-
| 'kilo'
16-
| 'kiro-cli'
17-
| 'roo'
18-
| 'trae'
19-
| 'cline'
20-
| 'codebuddy'
21-
| 'commandcode'
22-
| 'continue'
23-
| 'crush'
24-
| 'factory'
25-
| 'mcpjam'
26-
| 'mux'
27-
| 'neovate'
28-
| 'openhands'
29-
| 'pi'
30-
| 'qoder'
31-
| 'qwen'
32-
| 'vercel'
33-
| 'zencoder'
34-
| 'devin'
35-
| 'aider'
36-
| 'sourcegraph-cody'
37-
| 'amazon-q'
38-
| 'augment-code'
39-
| 'replit-agent'
40-
| 'bolt'
41-
| 'lovable'
42-
| 'tabby'
43-
| 'tabnine'
44-
| 'codegpt'
45-
| 'playcode-agent';
1+
import type { AgentType } from '@skillkit/core';
2+
export type { AgentType };
463

474
export interface TranslationDisplay {
485
sourceFormat: string;

0 commit comments

Comments
 (0)