* fix: universal agent name replacement for non-Claude runtimes (#766) Adds neutralizeAgentReferences() shared function that all non-Claude runtime converters call to replace Claude-specific references: - 'Claude' (standalone agent name) → 'the agent' - 'CLAUDE.md' → runtime-specific file (AGENTS.md, GEMINI.md, COPILOT.md) - Removes 'Do NOT load full AGENTS.md' (harmful for AGENTS.md runtimes) Preserves: 'Claude Code' (product), 'Claude Opus/Sonnet/Haiku' (models), 'claude-' prefixes (packages, CSS classes). Integrated into: OpenCode, Gemini, Copilot, Antigravity, and Codex converters. Claude Code converter unchanged (references are correct). Includes 7 new tests covering all replacement rules. Closes #766 * fix: use copilot-instructions.md instead of COPILOT.md for Copilot runtime Addresses review from Solvely-Colin: Copilot's actual instruction file is copilot-instructions.md, not COPILOT.md. The neutralizer was mapping CLAUDE.md -> COPILOT.md which would reference a non-existent file. - install.js: pass 'copilot-instructions.md' to neutralizeAgentReferences - runtime-converters.test.cjs: update test to validate correct filename
This commit is contained in:
@@ -17,6 +17,7 @@ process.env.GSD_TEST_MODE = '1';
|
||||
const {
|
||||
convertClaudeToOpencodeFrontmatter,
|
||||
convertClaudeToGeminiAgent,
|
||||
neutralizeAgentReferences,
|
||||
} = require('../bin/install.js');
|
||||
|
||||
// Sample Claude agent frontmatter (matches actual GSD agent format)
|
||||
@@ -183,3 +184,56 @@ Use \${PHASE} in shell examples.
|
||||
assert.ok(!result.includes('${PHASE}'), 'removes Gemini template-string pattern');
|
||||
});
|
||||
});
|
||||
|
||||
// ─── neutralizeAgentReferences (#766) ─────────────────────────────────────────
|
||||
|
||||
describe('neutralizeAgentReferences', () => {
|
||||
test('replaces standalone Claude with "the agent"', () => {
|
||||
const input = 'Claude handles these decisions. Claude should read the file.';
|
||||
const result = neutralizeAgentReferences(input, 'AGENTS.md');
|
||||
assert.ok(!result.includes('Claude handles'), 'standalone Claude replaced');
|
||||
assert.ok(result.includes('the agent handles'), 'replaced with "the agent"');
|
||||
});
|
||||
|
||||
test('preserves Claude Code (product name)', () => {
|
||||
const input = 'This is a Claude Code bug. Use Claude Code settings.';
|
||||
const result = neutralizeAgentReferences(input, 'AGENTS.md');
|
||||
assert.ok(result.includes('Claude Code bug'), 'Claude Code preserved');
|
||||
assert.ok(result.includes('Claude Code settings'), 'Claude Code preserved');
|
||||
});
|
||||
|
||||
test('preserves Claude model names', () => {
|
||||
const input = 'Use Claude Opus for planning. Claude Sonnet for execution. Claude Haiku for research.';
|
||||
const result = neutralizeAgentReferences(input, 'AGENTS.md');
|
||||
assert.ok(result.includes('Claude Opus'), 'Opus preserved');
|
||||
assert.ok(result.includes('Claude Sonnet'), 'Sonnet preserved');
|
||||
assert.ok(result.includes('Claude Haiku'), 'Haiku preserved');
|
||||
});
|
||||
|
||||
test('replaces CLAUDE.md with runtime instruction file', () => {
|
||||
const input = 'Read CLAUDE.md for project instructions. Check ./CLAUDE.md if exists.';
|
||||
const result = neutralizeAgentReferences(input, 'AGENTS.md');
|
||||
assert.ok(result.includes('AGENTS.md'), 'CLAUDE.md -> AGENTS.md');
|
||||
assert.ok(!result.includes('CLAUDE.md'), 'no CLAUDE.md remains');
|
||||
});
|
||||
|
||||
test('uses different instruction file per runtime', () => {
|
||||
const input = 'Read CLAUDE.md for instructions.';
|
||||
assert.ok(neutralizeAgentReferences(input, 'GEMINI.md').includes('GEMINI.md'));
|
||||
assert.ok(neutralizeAgentReferences(input, 'copilot-instructions.md').includes('copilot-instructions.md'));
|
||||
assert.ok(neutralizeAgentReferences(input, 'AGENTS.md').includes('AGENTS.md'));
|
||||
});
|
||||
|
||||
test('removes AGENTS.md load-blocking instruction', () => {
|
||||
const input = 'Do NOT load full `AGENTS.md` files — they contain agent definitions.';
|
||||
const result = neutralizeAgentReferences(input, 'AGENTS.md');
|
||||
assert.ok(!result.includes('Do NOT load full'), 'blocking instruction removed');
|
||||
});
|
||||
|
||||
test('preserves claude- prefixes (CSS classes, package names)', () => {
|
||||
const input = 'The claude-ctx session and claude-code package.';
|
||||
const result = neutralizeAgentReferences(input, 'AGENTS.md');
|
||||
assert.ok(result.includes('claude-ctx'), 'claude- prefix preserved');
|
||||
assert.ok(result.includes('claude-code'), 'claude-code preserved');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user