fix(#1615): install Windsurf slash workflows
This commit is contained in:
@@ -941,20 +941,18 @@ function convertClaudeToWindsurfMarkdown(content) {
|
||||
// Replace subagent_type from Claude to Windsurf format
|
||||
converted = converted.replace(/subagent_type="general-purpose"/g, 'subagent_type="generalPurpose"');
|
||||
converted = converted.replace(/\$ARGUMENTS\b/g, '{{GSD_ARGS}}');
|
||||
// Replace project-level Claude conventions with Windsurf/Devin equivalents
|
||||
// Workspace skills install to .devin/ (Devin Desktop preferred dir, #1085).
|
||||
// Legacy .windsurf/ is still recognized on read but new installs use .devin/.
|
||||
converted = converted.replace(/`\.\/CLAUDE\.md`/g, '`.devin/rules`');
|
||||
converted = converted.replace(/\.\/CLAUDE\.md/g, '.devin/rules');
|
||||
converted = converted.replace(/`CLAUDE\.md`/g, '`.devin/rules`');
|
||||
converted = converted.replace(/\bCLAUDE\.md\b/g, '.devin/rules');
|
||||
converted = converted.replace(/\.claude\/skills\//g, '.devin/skills/');
|
||||
converted = converted.replace(/\.\/\.claude\//g, './.devin/');
|
||||
converted = converted.replace(/\.claude\//g, '.devin/');
|
||||
// Replace project-level Claude conventions with Windsurf equivalents.
|
||||
converted = converted.replace(/`\.\/CLAUDE\.md`/g, '`.windsurf/rules`');
|
||||
converted = converted.replace(/\.\/CLAUDE\.md/g, '.windsurf/rules');
|
||||
converted = converted.replace(/`CLAUDE\.md`/g, '`.windsurf/rules`');
|
||||
converted = converted.replace(/\bCLAUDE\.md\b/g, '.windsurf/rules');
|
||||
converted = converted.replace(/\.claude\/skills\//g, '.windsurf/skills/');
|
||||
converted = converted.replace(/\.\/\.claude\//g, './.windsurf/');
|
||||
converted = converted.replace(/\.claude\//g, '.windsurf/');
|
||||
// Bare forms (no trailing slash) — after slash forms to avoid double-rewrite.
|
||||
// Use negative lookahead (?![\w-]) to preserve .claude-plugin and .claudeignore.
|
||||
converted = converted.replace(/~\/\.claude(?![\w-])/g, '~/.devin');
|
||||
converted = converted.replace(/\$HOME\/\.claude(?![\w-])/g, '$HOME/.devin');
|
||||
converted = converted.replace(/~\/\.claude(?![\w-])/g, '~/.windsurf');
|
||||
converted = converted.replace(/\$HOME\/\.claude(?![\w-])/g, '$HOME/.windsurf');
|
||||
// Environment variable name rewrite
|
||||
converted = converted.replace(/\bCLAUDE_CONFIG_DIR\b/g, 'WINDSURF_CONFIG_DIR');
|
||||
// Remove Claude Code-specific bug workarounds before brand replacement
|
||||
@@ -1008,6 +1006,19 @@ function convertClaudeCommandToWindsurfSkill(content, skillName) {
|
||||
return `---\nname: ${yamlIdentifier(skillName)}\ndescription: ${yamlQuote(shortDescription)}\n---\n\n${adapter}\n\n${body.trimStart()}`;
|
||||
}
|
||||
|
||||
function convertClaudeCommandToWindsurfWorkflow(content, commandName) {
|
||||
const converted = convertClaudeToWindsurfMarkdown(content);
|
||||
const { frontmatter } = extractFrontmatterAndBody(converted);
|
||||
const description = frontmatter ? extractFrontmatterField(frontmatter, 'description') : '';
|
||||
const stem = commandName.startsWith('gsd-') ? commandName.slice(4) : commandName;
|
||||
const workflow = `# ${commandName}\n\n${toSingleLine(description || `Run ${commandName}.`)}\n\nRead and execute the GSD command at @~/.claude/gsd-core/commands/gsd/${stem}.md end-to-end. Treat the user's message after /${commandName} as the command arguments.`;
|
||||
const byteLength = Buffer.byteLength(workflow, 'utf8');
|
||||
if (byteLength > 12000) {
|
||||
throw new Error(`Windsurf workflow ${commandName} exceeds 12000 bytes (${byteLength}); extract references before installing`);
|
||||
}
|
||||
return workflow;
|
||||
}
|
||||
|
||||
// --- Augment converters ---
|
||||
// Augment uses a tool set similar to Cursor/Windsurf.
|
||||
// Config lives in .augment/ (local) and ~/.augment/ (global).
|
||||
@@ -2568,6 +2579,7 @@ export = {
|
||||
convertClaudeCommandToCursorCommand,
|
||||
convertClaudeToWindsurfMarkdown,
|
||||
convertClaudeCommandToWindsurfSkill,
|
||||
convertClaudeCommandToWindsurfWorkflow,
|
||||
convertClaudeToAugmentMarkdown,
|
||||
convertClaudeCommandToAugmentSkill,
|
||||
convertClaudeToTraeMarkdown,
|
||||
|
||||
@@ -133,7 +133,7 @@ export function getProjectInstructionFile(runtime: unknown): string {
|
||||
|
||||
/**
|
||||
* Map a canonical runtime id to its on-disk local config directory name
|
||||
* (e.g. `cursor` -> `.cursor`, `windsurf` -> `.devin`). Unknown/empty inputs
|
||||
* (e.g. `cursor` -> `.cursor`, `windsurf` -> `.windsurf`). Unknown/empty inputs
|
||||
* fall back to `.claude`.
|
||||
*
|
||||
* Pure runtime-identity projection. Relocated from `bin/install.js` per
|
||||
@@ -149,7 +149,7 @@ export function getDirName(runtime: string): string {
|
||||
if (runtime === 'codex') return '.codex';
|
||||
if (runtime === 'antigravity') return '.agents';
|
||||
if (runtime === 'cursor') return '.cursor';
|
||||
if (runtime === 'windsurf') return '.devin';
|
||||
if (runtime === 'windsurf') return '.windsurf';
|
||||
if (runtime === 'augment') return '.augment';
|
||||
if (runtime === 'trae') return '.trae';
|
||||
if (runtime === 'qwen') return '.qwen';
|
||||
|
||||
@@ -26,8 +26,8 @@ export const RUNTIME_DIRS: RuntimeDirEntry[] = [
|
||||
['antigravity', '.gemini/antigravity'],
|
||||
['antigravity', '.agents'], // local Antigravity install dir canonical (#791; bin/install.js getDirName('antigravity'))
|
||||
['antigravity', '.agent'], // local Antigravity install dir legacy (#503; backward-compat with pre-#791 installs)
|
||||
['windsurf', '.devin'], // local Windsurf/Devin Desktop install dir canonical (#1085; bin/install.js getDirName('windsurf'))
|
||||
['windsurf', '.windsurf'], // local Windsurf install dir legacy (#1085; backward-compat with pre-#1085 installs)
|
||||
['windsurf', '.windsurf'], // local Windsurf workflow dir canonical (#1615; bin/install.js getDirName('windsurf'))
|
||||
['windsurf', '.devin'], // local Devin Desktop install dir legacy (#1085; backward-compat)
|
||||
['gemini', '.gemini'],
|
||||
['kilo', '.config/kilo'],
|
||||
['kilo', '.kilo'],
|
||||
|
||||
Reference in New Issue
Block a user