diff --git a/packages/agents/README.md b/packages/agents/README.md index e6adf75c..6a92a8bf 100644 --- a/packages/agents/README.md +++ b/packages/agents/README.md @@ -23,7 +23,7 @@ npm install @skillkit/agents | Antigravity | SKILL.md | `.antigravity/skills/` | - | | Amp | SKILL.md | `.amp/skills/` | - | | Clawdbot | SKILL.md | `.clawdbot/skills/` | - | -| OpenClaw | SKILL.md | `skills/` | - | +| OpenClaw | SKILL.md | `.openclaw/skills/` | `~/.openclaw/workspace/skills/` | | Cline | SKILL.md | `.cline/skills/` | - | | CodeBuddy | SKILL.md | `.codebuddy/skills/` | - | | CodeGPT | SKILL.md | `.codegpt/skills/` | - | diff --git a/packages/agents/src/openclaw.ts b/packages/agents/src/openclaw.ts index b8ee7d8f..aed2904c 100644 --- a/packages/agents/src/openclaw.ts +++ b/packages/agents/src/openclaw.ts @@ -14,9 +14,12 @@ export class OpenClawAdapter extends ClawdbotAdapter { override readonly configFile = config.configFile; override async isDetected(): Promise { + const projectOpenClaw = join(process.cwd(), '.openclaw'); const globalOpenClaw = join(homedir(), '.openclaw'); + const globalWorkspace = join(homedir(), '.openclaw', 'workspace'); const openclawConfig = join(process.cwd(), 'openclaw.json'); - return existsSync(globalOpenClaw) || existsSync(openclawConfig); + return existsSync(projectOpenClaw) || existsSync(globalOpenClaw) || + existsSync(globalWorkspace) || existsSync(openclawConfig); } } diff --git a/packages/core/src/agent-config.ts b/packages/core/src/agent-config.ts index 4c5e7fe5..41579b96 100644 --- a/packages/core/src/agent-config.ts +++ b/packages/core/src/agent-config.ts @@ -15,6 +15,8 @@ export interface AgentDirectoryConfig { skillsDir: string; /** Config file that references skills */ configFile: string; + /** Alternative config files that also mark this agent as present */ + altConfigFiles?: string[]; /** Alternative skills directories */ altSkillsDirs?: string[]; /** Global skills directory */ @@ -121,10 +123,11 @@ export const AGENT_CONFIG: Record = { }, openclaw: { - skillsDir: 'skills', - configFile: 'CLAUDE.md', - altSkillsDirs: ['~/.openclaw/skills'], - globalSkillsDir: '~/.openclaw/skills', + skillsDir: '.openclaw/skills', + configFile: 'AGENTS.md', + altConfigFiles: ['openclaw.json'], + altSkillsDirs: ['skills', '~/.openclaw/workspace/skills'], + globalSkillsDir: '~/.openclaw/workspace/skills', configFormat: 'xml', usesFrontmatter: true, frontmatterFields: [ diff --git a/packages/core/src/config.ts b/packages/core/src/config.ts index 3ba97802..cdb6ece9 100644 --- a/packages/core/src/config.ts +++ b/packages/core/src/config.ts @@ -4,6 +4,7 @@ import { homedir } from 'node:os'; import { createHash } from 'node:crypto'; import { parse as parseYaml, stringify as stringifyYaml } from 'yaml'; import { SkillkitConfig, LockFile, type AgentType, type SkillMetadata, type AgentAdapterInfo, type LockEntry } from './types.js'; +import { AGENT_CONFIG } from './agent-config.js'; const CONFIG_FILE = 'skillkit.yaml'; const METADATA_FILE = '.skillkit.json'; @@ -99,7 +100,16 @@ export function getSearchDirs(adapter: AgentAdapterInfo): string[] { dirs.push(join(process.cwd(), adapter.skillsDir)); dirs.push(join(process.cwd(), '.agent', 'skills')); - dirs.push(join(homedir(), adapter.skillsDir)); + + const globalDir = AGENT_CONFIG[adapter.type]?.globalSkillsDir; + if (globalDir) { + const resolved = globalDir.startsWith('~/') + ? join(homedir(), globalDir.slice(2)) + : globalDir; + dirs.push(resolved); + } else { + dirs.push(join(homedir(), adapter.skillsDir)); + } dirs.push(join(homedir(), '.agent', 'skills')); return dirs; diff --git a/packages/core/src/context/sync.ts b/packages/core/src/context/sync.ts index 8e76c195..9eb1a715 100644 --- a/packages/core/src/context/sync.ts +++ b/packages/core/src/context/sync.ts @@ -55,8 +55,11 @@ export class ContextSync { const skillsPath = join(this.projectPath, config.skillsDir); const configPath = join(this.projectPath, config.configFile); - // Check if either skills directory or config file exists - if (existsSync(skillsPath) || existsSync(configPath)) { + const altConfigExists = (config.altConfigFiles ?? []).some((alt) => + existsSync(join(this.projectPath, alt)) + ); + + if (existsSync(skillsPath) || existsSync(configPath) || altConfigExists) { detected.push(agent as AgentType); } } diff --git a/packages/core/src/skills.ts b/packages/core/src/skills.ts index f1dd64ba..b312ccd5 100644 --- a/packages/core/src/skills.ts +++ b/packages/core/src/skills.ts @@ -41,6 +41,7 @@ export const SKILL_DISCOVERY_PATHS = [ '.mux/skills', '.neovate/skills', '.opencode/skills', + '.openclaw/skills', '.openhands/skills', '.pi/skills', '.playcode/skills', diff --git a/packages/mcp/src/tools.ts b/packages/mcp/src/tools.ts index d67c447d..7c8df4d7 100644 --- a/packages/mcp/src/tools.ts +++ b/packages/mcp/src/tools.ts @@ -185,7 +185,7 @@ const AGENT_DIR_MAP: Record = { 'claude-code': ['.claude/skills'], 'cursor': ['.cursor/skills'], 'codex': ['.codex/skills'], 'gemini-cli': ['.gemini/skills'], 'opencode': ['.opencode/skills', '.config/opencode/skills'], 'antigravity': ['.antigravity/skills'], 'amp': ['.amp/skills'], 'clawdbot': ['.clawdbot/skills'], - 'openclaw': ['skills'], 'github-copilot': ['.github/skills'], 'goose': ['.goose/skills'], + 'openclaw': ['.openclaw/skills', '.openclaw/workspace/skills', 'skills'], 'github-copilot': ['.github/skills'], 'goose': ['.goose/skills'], 'kilo': ['.kilocode/skills'], 'kiro-cli': ['.kiro/skills'], 'roo': ['.roo/skills'], 'trae': ['.trae/skills'], 'windsurf': ['.windsurf/skills', '.codeium/windsurf/skills'], 'universal': ['skills'], 'droid': ['.factory/skills'], 'factory': ['.factory/skills'],