From f0546fe56755575bec31077f10b2b035c62cd9d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Angner?= Date: Tue, 24 Feb 2026 20:08:00 +0100 Subject: [PATCH] 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 --- tools/cli/installers/lib/ide/antigravity.js | 34 ++++++++++++++ tools/cli/installers/lib/ide/auggie.js | 42 +++++++++++++++++ tools/cli/installers/lib/ide/codex.js | 43 +++++++++++++++++ tools/cli/installers/lib/ide/crush.js | 44 +++++++++++++++++ tools/cli/installers/lib/ide/gemini.js | 52 +++++++++++++++++++++ tools/cli/installers/lib/ide/iflow.js | 44 +++++++++++++++++ tools/cli/installers/lib/ide/kilo.js | 52 +++++++++++++++++++++ tools/cli/installers/lib/ide/kiro-cli.js | 47 +++++++++++++++++++ tools/cli/installers/lib/ide/opencode.js | 44 +++++++++++++++++ tools/cli/installers/lib/ide/qwen.js | 52 +++++++++++++++++++++ tools/cli/installers/lib/ide/roo.js | 43 +++++++++++++++++ tools/cli/installers/lib/ide/rovo-dev.js | 43 +++++++++++++++++ tools/cli/installers/lib/ide/trae.js | 44 +++++++++++++++++ 13 files changed, 584 insertions(+) create mode 100644 tools/cli/installers/lib/ide/antigravity.js create mode 100644 tools/cli/installers/lib/ide/auggie.js create mode 100644 tools/cli/installers/lib/ide/codex.js create mode 100644 tools/cli/installers/lib/ide/crush.js create mode 100644 tools/cli/installers/lib/ide/gemini.js create mode 100644 tools/cli/installers/lib/ide/iflow.js create mode 100644 tools/cli/installers/lib/ide/kilo.js create mode 100644 tools/cli/installers/lib/ide/kiro-cli.js create mode 100644 tools/cli/installers/lib/ide/opencode.js create mode 100644 tools/cli/installers/lib/ide/qwen.js create mode 100644 tools/cli/installers/lib/ide/roo.js create mode 100644 tools/cli/installers/lib/ide/rovo-dev.js create mode 100644 tools/cli/installers/lib/ide/trae.js diff --git a/tools/cli/installers/lib/ide/antigravity.js b/tools/cli/installers/lib/ide/antigravity.js new file mode 100644 index 000000000..b3b5cf22a --- /dev/null +++ b/tools/cli/installers/lib/ide/antigravity.js @@ -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 }; diff --git a/tools/cli/installers/lib/ide/auggie.js b/tools/cli/installers/lib/ide/auggie.js new file mode 100644 index 000000000..7047149c6 --- /dev/null +++ b/tools/cli/installers/lib/ide/auggie.js @@ -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 }; diff --git a/tools/cli/installers/lib/ide/codex.js b/tools/cli/installers/lib/ide/codex.js new file mode 100644 index 000000000..2b157caa8 --- /dev/null +++ b/tools/cli/installers/lib/ide/codex.js @@ -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 }; diff --git a/tools/cli/installers/lib/ide/crush.js b/tools/cli/installers/lib/ide/crush.js new file mode 100644 index 000000000..ffe8280ea --- /dev/null +++ b/tools/cli/installers/lib/ide/crush.js @@ -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 }; diff --git a/tools/cli/installers/lib/ide/gemini.js b/tools/cli/installers/lib/ide/gemini.js new file mode 100644 index 000000000..fc94ade98 --- /dev/null +++ b/tools/cli/installers/lib/ide/gemini.js @@ -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 }; diff --git a/tools/cli/installers/lib/ide/iflow.js b/tools/cli/installers/lib/ide/iflow.js new file mode 100644 index 000000000..de42b2de4 --- /dev/null +++ b/tools/cli/installers/lib/ide/iflow.js @@ -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 }; diff --git a/tools/cli/installers/lib/ide/kilo.js b/tools/cli/installers/lib/ide/kilo.js new file mode 100644 index 000000000..9fef11da7 --- /dev/null +++ b/tools/cli/installers/lib/ide/kilo.js @@ -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 }; diff --git a/tools/cli/installers/lib/ide/kiro-cli.js b/tools/cli/installers/lib/ide/kiro-cli.js new file mode 100644 index 000000000..c89815b15 --- /dev/null +++ b/tools/cli/installers/lib/ide/kiro-cli.js @@ -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 }; diff --git a/tools/cli/installers/lib/ide/opencode.js b/tools/cli/installers/lib/ide/opencode.js new file mode 100644 index 000000000..29997e82f --- /dev/null +++ b/tools/cli/installers/lib/ide/opencode.js @@ -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 }; diff --git a/tools/cli/installers/lib/ide/qwen.js b/tools/cli/installers/lib/ide/qwen.js new file mode 100644 index 000000000..b21103e20 --- /dev/null +++ b/tools/cli/installers/lib/ide/qwen.js @@ -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 }; diff --git a/tools/cli/installers/lib/ide/roo.js b/tools/cli/installers/lib/ide/roo.js new file mode 100644 index 000000000..aa4f89c09 --- /dev/null +++ b/tools/cli/installers/lib/ide/roo.js @@ -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 }; diff --git a/tools/cli/installers/lib/ide/rovo-dev.js b/tools/cli/installers/lib/ide/rovo-dev.js new file mode 100644 index 000000000..ee58d86bd --- /dev/null +++ b/tools/cli/installers/lib/ide/rovo-dev.js @@ -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 }; diff --git a/tools/cli/installers/lib/ide/trae.js b/tools/cli/installers/lib/ide/trae.js new file mode 100644 index 000000000..d92f92e44 --- /dev/null +++ b/tools/cli/installers/lib/ide/trae.js @@ -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 };