From 69cfae2011ff1b3fdf31f468f9e6c891e0790f8a Mon Sep 17 00:00:00 2001 From: mitchelladam <17411882+mitchelladam@users.noreply.github.com> Date: Wed, 18 Mar 2026 18:49:28 +0000 Subject: [PATCH] fix(cursor): preserve slash-prefixed gsd commands in converted markdown Keep `/gsd-*` command examples slash-prefixed during Cursor conversion while still normalizing legacy `gsd:` syntax, and add regression coverage for Next Up markdown output. Made-with: Cursor --- bin/install.js | 10 ++++------ tests/cursor-conversion.test.cjs | 20 ++++++++++++++++++++ 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/bin/install.js b/bin/install.js index fe30e5df2..ffc71fedf 100755 --- a/bin/install.js +++ b/bin/install.js @@ -766,11 +766,9 @@ function convertCursorToolName(claudeTool) { } function convertSlashCommandsToCursorSkillMentions(content) { - let converted = content.replace(/\/gsd:([a-z0-9-]+)/gi, (_, commandName) => { - return `gsd-${String(commandName).toLowerCase()}`; - }); - converted = converted.replace(/\/gsd-help\b/g, 'gsd-help'); - return converted; + // Keep leading "/" for slash commands; only normalize gsd: -> gsd-. + // This preserves rendered "next step" commands like "/gsd-execute-phase 17". + return content.replace(/gsd:/gi, 'gsd-'); } function convertClaudeToCursorMarkdown(content) { @@ -1831,7 +1829,7 @@ function copyWithPathReplacement(srcDir, destDir, pathPrefix, runtime, isCommand } else if (isCursor && (entry.name.endsWith('.cjs') || entry.name.endsWith('.js'))) { // For Cursor, also convert Claude references in JS/CJS utility scripts let jsContent = fs.readFileSync(srcPath, 'utf8'); - jsContent = jsContent.replace(/\/gsd:([a-z0-9-]+)/gi, (_, cmd) => `gsd-${cmd.toLowerCase()}`); + jsContent = jsContent.replace(/gsd:/gi, 'gsd-'); jsContent = jsContent.replace(/\.claude\/skills\//g, '.cursor/skills/'); jsContent = jsContent.replace(/CLAUDE\.md/g, '.cursor/rules/'); jsContent = jsContent.replace(/\bClaude Code\b/g, 'Cursor'); diff --git a/tests/cursor-conversion.test.cjs b/tests/cursor-conversion.test.cjs index 87652ab96..2c7c79d52 100644 --- a/tests/cursor-conversion.test.cjs +++ b/tests/cursor-conversion.test.cjs @@ -35,6 +35,26 @@ Test body assert.equal(nameMatch[1], 'gsd-quick', 'skill name is plain scalar'); assert.ok(!result.includes('name: "gsd-quick"'), 'quoted skill name is not emitted'); }); + + test('preserves slash for slash commands in markdown body', () => { + const input = `--- +name: gsd:plan-phase +description: Plan a phase +--- + +Next: +/gsd:execute-phase 17 +/gsd-help +gsd:progress +`; + + const result = convertClaudeCommandToCursorSkill(input, 'gsd-plan-phase'); + + assert.ok(result.includes('/gsd-execute-phase 17'), 'slash command remains slash-prefixed'); + assert.ok(result.includes('/gsd-help'), 'existing slash command is preserved'); + assert.ok(result.includes('gsd-progress'), 'non-slash gsd: references still normalize'); + assert.ok(!result.includes('/gsd:execute-phase'), 'legacy colon command form is removed'); + }); }); describe('convertClaudeAgentToCursorAgent', () => {