Add remaining 13 IDE handlers for complete coverage

Roo, Trae, Crush, iFlow, Antigravity (flat markdown),
Codex, Rovo Dev, Auggie, OpenCode (YAML frontmatter),
Gemini, Qwen (TOML format), Kiro CLI (JSON+MD), Kilo (YAML modes).
All 18 IDEs now supported via dynamic handler discovery.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Mårten Angner 2026-02-24 20:08:00 +01:00
parent 4596fad5d6
commit f0546fe567
13 changed files with 584 additions and 0 deletions

View File

@ -0,0 +1,34 @@
const path = require('node:path');
const { BaseIdeSetup } = require('./_base-ide');
/**
* Antigravity IDE setup handler for WDS
*/
class AntigravitySetup extends BaseIdeSetup {
constructor() {
super('antigravity', 'Antigravity', false);
this.configDir = '.agent/workflows/wds';
}
async setup(projectDir, wdsDir, options = {}) {
const targetDir = path.join(projectDir, this.configDir);
await this.ensureDir(targetDir);
const agents = await this.getAgents(wdsDir);
if (agents.length === 0) throw new Error('No agents found in WDS installation');
for (const agent of agents) {
const launcher = this.formatAgentLauncher(agent.name, agent.path);
// Antigravity uses no frontmatter
await this.writeFile(path.join(targetDir, `${agent.slug}.md`), launcher);
}
return { success: true, agents: agents.length };
}
async detect(projectDir) {
return await this.exists(path.join(projectDir, '.agent'));
}
}
module.exports = { AntigravitySetup };

View File

@ -0,0 +1,42 @@
const path = require('node:path');
const { BaseIdeSetup } = require('./_base-ide');
/**
* Auggie CLI setup handler for WDS
*/
class AuggieSetup extends BaseIdeSetup {
constructor() {
super('auggie', 'Auggie CLI', false);
this.configDir = '.augment/commands/wds';
}
async setup(projectDir, wdsDir, options = {}) {
const targetDir = path.join(projectDir, this.configDir);
await this.ensureDir(targetDir);
const agents = await this.getAgents(wdsDir);
if (agents.length === 0) throw new Error('No agents found in WDS installation');
for (const agent of agents) {
const launcher = this.formatAgentLauncher(agent.name, agent.path);
const content = this.processContent(launcher, agent.metadata);
await this.writeFile(path.join(targetDir, `${agent.slug}.md`), content);
}
return { success: true, agents: agents.length };
}
processContent(content, metadata = {}) {
return `---
description: ${metadata.name || 'WDS Agent'} - ${metadata.description || 'Agent'}
---
${content}`;
}
async detect(projectDir) {
return await this.exists(path.join(projectDir, '.augment'));
}
}
module.exports = { AuggieSetup };

View File

@ -0,0 +1,43 @@
const path = require('node:path');
const { BaseIdeSetup } = require('./_base-ide');
/**
* Codex IDE setup handler for WDS
*/
class CodexSetup extends BaseIdeSetup {
constructor() {
super('codex', 'Codex', false);
this.configDir = '.codex/prompts/wds';
}
async setup(projectDir, wdsDir, options = {}) {
const targetDir = path.join(projectDir, this.configDir);
await this.ensureDir(targetDir);
const agents = await this.getAgents(wdsDir);
if (agents.length === 0) throw new Error('No agents found in WDS installation');
for (const agent of agents) {
const launcher = this.formatAgentLauncher(agent.name, agent.path);
const content = this.processContent(launcher, agent.metadata);
await this.writeFile(path.join(targetDir, `${agent.slug}.md`), content);
}
return { success: true, agents: agents.length };
}
processContent(content, metadata = {}) {
return `---
name: ${metadata.name || 'WDS Agent'}
description: ${metadata.description || 'Agent'}
---
${content}`;
}
async detect(projectDir) {
return await this.exists(path.join(projectDir, '.codex'));
}
}
module.exports = { CodexSetup };

View File

@ -0,0 +1,44 @@
const path = require('node:path');
const { BaseIdeSetup } = require('./_base-ide');
/**
* Crush IDE setup handler for WDS
*/
class CrushSetup extends BaseIdeSetup {
constructor() {
super('crush', 'Crush', false);
this.configDir = '.crush/commands/wds';
}
async setup(projectDir, wdsDir, options = {}) {
const targetDir = path.join(projectDir, this.configDir);
await this.ensureDir(targetDir);
const agents = await this.getAgents(wdsDir);
if (agents.length === 0) throw new Error('No agents found in WDS installation');
for (const agent of agents) {
const launcher = this.formatAgentLauncher(agent.name, agent.path);
const content = this.processContent(launcher, agent.metadata);
await this.writeFile(path.join(targetDir, `${agent.slug}.md`), content);
}
return { success: true, agents: agents.length };
}
processContent(content, metadata = {}) {
const title = metadata.name ?
`${metadata.name} - ${metadata.description}` :
metadata.description || 'WDS Agent';
return `# ${title}
${content}`;
}
async detect(projectDir) {
return await this.exists(path.join(projectDir, '.crush'));
}
}
module.exports = { CrushSetup };

View File

@ -0,0 +1,52 @@
const path = require('node:path');
const { BaseIdeSetup } = require('./_base-ide');
/**
* Gemini CLI setup handler for WDS
* Uses TOML format for commands
*/
class GeminiSetup extends BaseIdeSetup {
constructor() {
super('gemini', 'Gemini CLI', false);
this.configDir = '.gemini/commands/wds';
}
async setup(projectDir, wdsDir, options = {}) {
const targetDir = path.join(projectDir, this.configDir);
await this.ensureDir(targetDir);
const agents = await this.getAgents(wdsDir);
if (agents.length === 0) throw new Error('No agents found in WDS installation');
for (const agent of agents) {
const launcher = this.formatAgentLauncher(agent.name, agent.path);
const content = this.processContent(launcher, agent.metadata);
await this.writeFile(path.join(targetDir, `${agent.slug}.toml`), content);
}
return { success: true, agents: agents.length };
}
processContent(content, metadata = {}) {
const description = metadata.name ?
`${metadata.name} - ${metadata.description}` :
metadata.description || 'WDS Agent';
// Escape content for TOML multi-line string
const escapedContent = content.replace(/"""/g, '\\"\\"\\"');
return `description = "${description}"
[prompt]
text = """
${escapedContent}
"""
`;
}
async detect(projectDir) {
return await this.exists(path.join(projectDir, '.gemini'));
}
}
module.exports = { GeminiSetup };

View File

@ -0,0 +1,44 @@
const path = require('node:path');
const { BaseIdeSetup } = require('./_base-ide');
/**
* iFlow CLI setup handler for WDS
*/
class IFlowSetup extends BaseIdeSetup {
constructor() {
super('iflow', 'iFlow CLI', false);
this.configDir = '.iflow/commands/wds';
}
async setup(projectDir, wdsDir, options = {}) {
const targetDir = path.join(projectDir, this.configDir);
await this.ensureDir(targetDir);
const agents = await this.getAgents(wdsDir);
if (agents.length === 0) throw new Error('No agents found in WDS installation');
for (const agent of agents) {
const launcher = this.formatAgentLauncher(agent.name, agent.path);
const content = this.processContent(launcher, agent.metadata);
await this.writeFile(path.join(targetDir, `${agent.slug}.md`), content);
}
return { success: true, agents: agents.length };
}
processContent(content, metadata = {}) {
const title = metadata.name ?
`${metadata.name} - ${metadata.description}` :
metadata.description || 'WDS Agent';
return `# ${title}
${content}`;
}
async detect(projectDir) {
return await this.exists(path.join(projectDir, '.iflow'));
}
}
module.exports = { IFlowSetup };

View File

@ -0,0 +1,52 @@
const path = require('node:path');
const fs = require('fs-extra');
const { BaseIdeSetup } = require('./_base-ide');
/**
* Kilo Code setup handler for WDS
* Appends agent modes to .kilocodemodes YAML file
*/
class KiloSetup extends BaseIdeSetup {
constructor() {
super('kilo', 'Kilo Code', false);
this.configFile = '.kilocodemodes';
}
async setup(projectDir, wdsDir, options = {}) {
const agents = await this.getAgents(wdsDir);
if (agents.length === 0) throw new Error('No agents found in WDS installation');
const filePath = path.join(projectDir, this.configFile);
// Build modes content
let modesContent = '\n# WDS Agent Modes\n';
for (const agent of agents) {
const launcher = this.formatAgentLauncher(agent.name, agent.path);
modesContent += `\n- slug: wds-${agent.slug}`;
modesContent += `\n name: "${agent.metadata.name || agent.slug}"`;
modesContent += `\n roleDefinition: "${agent.metadata.description || 'WDS Agent'}"`;
modesContent += `\n customInstructions: |`;
// Indent launcher content for YAML block
const indented = launcher.split('\n').map(line => ` ${line}`).join('\n');
modesContent += `\n${indented}\n`;
}
if (await this.exists(filePath)) {
// Append to existing file
await fs.appendFile(filePath, modesContent);
} else {
// Create new file
await this.writeFile(filePath, modesContent);
}
return { success: true, agents: agents.length };
}
async detect(projectDir) {
return await this.exists(path.join(projectDir, this.configFile));
}
}
module.exports = { KiloSetup };

View File

@ -0,0 +1,47 @@
const path = require('node:path');
const { BaseIdeSetup } = require('./_base-ide');
/**
* Kiro CLI setup handler for WDS
* Creates JSON config + markdown prompt files
*/
class KiroCliSetup extends BaseIdeSetup {
constructor() {
super('kiro-cli', 'Kiro CLI', false);
this.configDir = '.kiro/agents/wds';
}
async setup(projectDir, wdsDir, options = {}) {
const targetDir = path.join(projectDir, this.configDir);
await this.ensureDir(targetDir);
const agents = await this.getAgents(wdsDir);
if (agents.length === 0) throw new Error('No agents found in WDS installation');
for (const agent of agents) {
const launcher = this.formatAgentLauncher(agent.name, agent.path);
// Write JSON config
const jsonConfig = {
name: agent.metadata.name || agent.slug,
description: agent.metadata.description || 'WDS Agent',
prompt: `./${agent.slug}-prompt.md`,
};
await this.writeFile(
path.join(targetDir, `${agent.slug}.json`),
JSON.stringify(jsonConfig, null, 2)
);
// Write markdown prompt
await this.writeFile(path.join(targetDir, `${agent.slug}-prompt.md`), launcher);
}
return { success: true, agents: agents.length };
}
async detect(projectDir) {
return await this.exists(path.join(projectDir, '.kiro'));
}
}
module.exports = { KiroCliSetup };

View File

@ -0,0 +1,44 @@
const path = require('node:path');
const { BaseIdeSetup } = require('./_base-ide');
/**
* OpenCode IDE setup handler for WDS
*/
class OpenCodeSetup extends BaseIdeSetup {
constructor() {
super('opencode', 'OpenCode', false);
this.configDir = '.opencode/agent/wds';
}
async setup(projectDir, wdsDir, options = {}) {
const targetDir = path.join(projectDir, this.configDir);
await this.ensureDir(targetDir);
const agents = await this.getAgents(wdsDir);
if (agents.length === 0) throw new Error('No agents found in WDS installation');
for (const agent of agents) {
const launcher = this.formatAgentLauncher(agent.name, agent.path);
const content = this.processContent(launcher, agent.metadata);
await this.writeFile(path.join(targetDir, `${agent.slug}.md`), content);
}
return { success: true, agents: agents.length };
}
processContent(content, metadata = {}) {
return `---
name: ${metadata.name || 'WDS Agent'}
description: ${metadata.description || 'Agent'}
mode: agent
---
${content}`;
}
async detect(projectDir) {
return await this.exists(path.join(projectDir, '.opencode'));
}
}
module.exports = { OpenCodeSetup };

View File

@ -0,0 +1,52 @@
const path = require('node:path');
const { BaseIdeSetup } = require('./_base-ide');
/**
* Qwen Code setup handler for WDS
* Uses TOML format for commands
*/
class QwenSetup extends BaseIdeSetup {
constructor() {
super('qwen', 'Qwen Code', false);
this.configDir = '.qwen/commands/wds';
}
async setup(projectDir, wdsDir, options = {}) {
const targetDir = path.join(projectDir, this.configDir);
await this.ensureDir(targetDir);
const agents = await this.getAgents(wdsDir);
if (agents.length === 0) throw new Error('No agents found in WDS installation');
for (const agent of agents) {
const launcher = this.formatAgentLauncher(agent.name, agent.path);
const content = this.processContent(launcher, agent.metadata);
await this.writeFile(path.join(targetDir, `${agent.slug}.toml`), content);
}
return { success: true, agents: agents.length };
}
processContent(content, metadata = {}) {
const description = metadata.name ?
`${metadata.name} - ${metadata.description}` :
metadata.description || 'WDS Agent';
// Escape content for TOML multi-line string
const escapedContent = content.replace(/"""/g, '\\"\\"\\"');
return `description = "${description}"
[prompt]
text = """
${escapedContent}
"""
`;
}
async detect(projectDir) {
return await this.exists(path.join(projectDir, '.qwen'));
}
}
module.exports = { QwenSetup };

View File

@ -0,0 +1,43 @@
const path = require('node:path');
const { BaseIdeSetup } = require('./_base-ide');
/**
* Roo Code IDE setup handler for WDS
*/
class RooSetup extends BaseIdeSetup {
constructor() {
super('roo', 'Roo Code', false);
this.configDir = '.roo/commands/wds';
}
async setup(projectDir, wdsDir, options = {}) {
const targetDir = path.join(projectDir, this.configDir);
await this.ensureDir(targetDir);
const agents = await this.getAgents(wdsDir);
if (agents.length === 0) throw new Error('No agents found in WDS installation');
for (const agent of agents) {
const launcher = this.formatAgentLauncher(agent.name, agent.path);
const content = this.processContent(launcher, agent.metadata);
await this.writeFile(path.join(targetDir, `${agent.slug}.md`), content);
}
return { success: true, agents: agents.length };
}
processContent(content, metadata = {}) {
return `---
name: ${metadata.name || 'WDS Agent'}
description: ${metadata.description || 'Agent'}
---
${content}`;
}
async detect(projectDir) {
return await this.exists(path.join(projectDir, '.roo'));
}
}
module.exports = { RooSetup };

View File

@ -0,0 +1,43 @@
const path = require('node:path');
const { BaseIdeSetup } = require('./_base-ide');
/**
* Atlassian Rovo Dev setup handler for WDS
*/
class RovoDevSetup extends BaseIdeSetup {
constructor() {
super('rovo-dev', 'Atlassian Rovo Dev', false);
this.configDir = '.rovodev/subagents/wds';
}
async setup(projectDir, wdsDir, options = {}) {
const targetDir = path.join(projectDir, this.configDir);
await this.ensureDir(targetDir);
const agents = await this.getAgents(wdsDir);
if (agents.length === 0) throw new Error('No agents found in WDS installation');
for (const agent of agents) {
const launcher = this.formatAgentLauncher(agent.name, agent.path);
const content = this.processContent(launcher, agent.metadata);
await this.writeFile(path.join(targetDir, `${agent.slug}.md`), content);
}
return { success: true, agents: agents.length };
}
processContent(content, metadata = {}) {
return `---
name: ${metadata.name || 'WDS Agent'}
description: ${metadata.description || 'Agent'}
---
${content}`;
}
async detect(projectDir) {
return await this.exists(path.join(projectDir, '.rovodev'));
}
}
module.exports = { RovoDevSetup };

View File

@ -0,0 +1,44 @@
const path = require('node:path');
const { BaseIdeSetup } = require('./_base-ide');
/**
* Trae IDE setup handler for WDS
*/
class TraeSetup extends BaseIdeSetup {
constructor() {
super('trae', 'Trae', false);
this.configDir = '.trae/rules/wds';
}
async setup(projectDir, wdsDir, options = {}) {
const targetDir = path.join(projectDir, this.configDir);
await this.ensureDir(targetDir);
const agents = await this.getAgents(wdsDir);
if (agents.length === 0) throw new Error('No agents found in WDS installation');
for (const agent of agents) {
const launcher = this.formatAgentLauncher(agent.name, agent.path);
const content = this.processContent(launcher, agent.metadata);
await this.writeFile(path.join(targetDir, `${agent.slug}.md`), content);
}
return { success: true, agents: agents.length };
}
processContent(content, metadata = {}) {
const title = metadata.name ?
`${metadata.name} - ${metadata.description}` :
metadata.description || 'WDS Agent';
return `# ${title}
${content}`;
}
async detect(projectDir) {
return await this.exists(path.join(projectDir, '.trae'));
}
}
module.exports = { TraeSetup };