Extracts all 9 convertClaudeAgentTo* functions together with their full dependency closure (claudeToCopilotTools, claudeToGeminiTools, convertCopilotToolName, convertGeminiToolName) from bin/install.js into src/runtime-artifact-conversion.cts and adds them to the module's export= block. Adds 6 regression tests in tests/copilot-install.test.cjs including a DEFECT.GENERATIVE-FIX parity guard that asserts claudeToCopilotTools is identical in module and bin/install.js. Inline copies in bin/install.js are retained (#1175 will remove them). This unblocks #1173 (descriptor-driven dispatch). Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1808,3 +1808,61 @@ describe('Claude uninstall preserves user-generated files (#1423)', () => {
|
||||
assert.ok(!fs.existsSync(cmdDir), 'commands/gsd/ should not exist after clean uninstall');
|
||||
});
|
||||
});
|
||||
|
||||
// ─── #1182 regression: agent converters accessible via module path ────────────
|
||||
// These tests require convertClaudeAgentToCopilotAgent and its dependency closure
|
||||
// (claudeToCopilotTools, convertCopilotToolName) THROUGH the runtime-artifact-conversion
|
||||
// module export — not via bin/install.js. Before the fix, the module returned
|
||||
// undefined for all three, causing ReferenceError when called.
|
||||
|
||||
describe('#1182 convertClaudeAgentToCopilotAgent exported from runtime-artifact-conversion module', () => {
|
||||
const _gsdLibDirModule = path.join(__dirname, '..', 'gsd-core', 'bin', 'lib');
|
||||
const conversionModule = require(path.join(_gsdLibDirModule, 'runtime-artifact-conversion.cjs'));
|
||||
|
||||
test('module exports claudeToCopilotTools table', () => {
|
||||
assert.strictEqual(typeof conversionModule.claudeToCopilotTools, 'object', 'claudeToCopilotTools must be exported');
|
||||
assert.ok(conversionModule.claudeToCopilotTools !== null, 'not null');
|
||||
assert.strictEqual(conversionModule.claudeToCopilotTools['Read'], 'read', 'Read maps to read');
|
||||
assert.strictEqual(conversionModule.claudeToCopilotTools['Bash'], 'execute', 'Bash maps to execute');
|
||||
});
|
||||
|
||||
test('module exports convertCopilotToolName function', () => {
|
||||
assert.strictEqual(typeof conversionModule.convertCopilotToolName, 'function', 'convertCopilotToolName must be exported');
|
||||
assert.strictEqual(conversionModule.convertCopilotToolName('Read'), 'read', 'maps Read -> read');
|
||||
assert.strictEqual(conversionModule.convertCopilotToolName('Bash'), 'execute', 'maps Bash -> execute');
|
||||
assert.strictEqual(conversionModule.convertCopilotToolName('mcp__context7__resolve-library-id'), 'io.github.upstash/context7/resolve-library-id', 'mcp__context7__ prefix mapped');
|
||||
});
|
||||
|
||||
test('module exports convertClaudeAgentToCopilotAgent function', () => {
|
||||
assert.strictEqual(typeof conversionModule.convertClaudeAgentToCopilotAgent, 'function', 'convertClaudeAgentToCopilotAgent must be exported');
|
||||
});
|
||||
|
||||
test('convertClaudeAgentToCopilotAgent via module produces correct output (local mode)', () => {
|
||||
const input = `---\nname: gsd-executor\ndescription: Executes GSD plans\ntools: Read, Write, Edit, Bash, Grep, Glob\ncolor: yellow\n---\n\nAgent body.`;
|
||||
const result = conversionModule.convertClaudeAgentToCopilotAgent(input);
|
||||
// Tools must be mapped and deduplicated
|
||||
assert.ok(result.includes("tools: ['read', 'edit', 'execute', 'search']"), `expected mapped tools in: ${result}`);
|
||||
assert.ok(result.includes('name: gsd-executor'), 'name preserved');
|
||||
assert.ok(result.includes('color: yellow'), 'color preserved');
|
||||
});
|
||||
|
||||
test('convertClaudeAgentToCopilotAgent via module applies path/command conversions (global mode)', () => {
|
||||
const input = `---\nname: gsd-test\ndescription: Test\ntools: Read\n---\n\nCheck ~/.claude/settings and run gsd:health.`;
|
||||
const result = conversionModule.convertClaudeAgentToCopilotAgent(input, true);
|
||||
assert.ok(result.includes('~/.copilot/settings'), 'CONV-06 applied in global mode');
|
||||
assert.ok(result.includes('gsd-health'), 'CONV-07 applied');
|
||||
});
|
||||
|
||||
// Parity assertion: claudeToCopilotTools in module matches the table in bin/install.js
|
||||
// Per DEFECT.GENERATIVE-FIX: shared constant across two surfaces needs a parity guard.
|
||||
test('claudeToCopilotTools parity: module table matches bin/install.js table', () => {
|
||||
const installJs = require('../bin/install.js');
|
||||
const moduleTable = conversionModule.claudeToCopilotTools;
|
||||
const installTable = installJs.claudeToCopilotTools;
|
||||
assert.deepStrictEqual(
|
||||
moduleTable,
|
||||
installTable,
|
||||
'claudeToCopilotTools must be identical in module and bin/install.js',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user