fix: strip unsupported Gemini agent skills frontmatter (#971)

This commit is contained in:
Frank
2026-03-12 10:36:43 -07:00
committed by GitHub
parent 14f9637538
commit 0f38e3467e
2 changed files with 63 additions and 0 deletions

View File

@@ -757,6 +757,7 @@ function stripSubTags(content) {
* - tools: must be a YAML array (not comma-separated string)
* - tool names: must use Gemini built-in names (read_file, not Read)
* - color: must be removed (causes validation error)
* - skills: must be removed (causes validation error)
* - mcp__* tools: must be excluded (auto-discovered at runtime)
*/
function convertClaudeToGeminiAgent(content) {
@@ -771,11 +772,19 @@ function convertClaudeToGeminiAgent(content) {
const lines = frontmatter.split('\n');
const newLines = [];
let inAllowedTools = false;
let inSkippedArrayField = false;
const tools = [];
for (const line of lines) {
const trimmed = line.trim();
if (inSkippedArrayField) {
if (!trimmed || trimmed.startsWith('- ')) {
continue;
}
inSkippedArrayField = false;
}
// Convert allowed-tools YAML array to tools list
if (trimmed.startsWith('allowed-tools:')) {
inAllowedTools = true;
@@ -801,6 +810,12 @@ function convertClaudeToGeminiAgent(content) {
// Strip color field (not supported by Gemini CLI, causes validation error)
if (trimmed.startsWith('color:')) continue;
// Strip skills field (not supported by Gemini CLI, causes validation error)
if (trimmed.startsWith('skills:')) {
inSkippedArrayField = true;
continue;
}
// Collect allowed-tools/tools array items
if (inAllowedTools) {
if (trimmed.startsWith('- ')) {
@@ -2414,6 +2429,7 @@ function installAllRuntimes(runtimes, isGlobal, isInteractive) {
if (process.env.GSD_TEST_MODE) {
module.exports = {
getCodexSkillAdapterHeader,
convertClaudeToGeminiAgent,
convertClaudeAgentToCodexAgent,
generateCodexAgentToml,
generateCodexConfigBlock,

View File

@@ -0,0 +1,47 @@
/**
* GSD Tools Tests - Gemini agent conversion
*
* Verifies Gemini-specific agent frontmatter conversion removes
* unsupported fields while preserving converted tools and body text.
*/
process.env.GSD_TEST_MODE = '1';
const { test, describe } = require('node:test');
const assert = require('node:assert');
const { convertClaudeToGeminiAgent } = require('../bin/install.js');
describe('convertClaudeToGeminiAgent', () => {
test('drops unsupported skills frontmatter while keeping converted tools', () => {
const input = `---
name: gsd-codebase-mapper
description: Explores codebase and writes structured analysis documents.
tools: Read, Bash, Grep, Glob, Write
color: cyan
skills:
- gsd-mapper-workflow
---
<role>
Use \${PHASE} in shell examples.
</role>`;
const result = convertClaudeToGeminiAgent(input);
const frontmatter = result.split('---')[1] || '';
assert.ok(frontmatter.includes('name: gsd-codebase-mapper'), 'keeps name');
assert.ok(frontmatter.includes('description: Explores codebase and writes structured analysis documents.'), 'keeps description');
assert.ok(frontmatter.includes('tools:'), 'adds Gemini tools array');
assert.ok(frontmatter.includes(' - read_file'), 'maps Read -> read_file');
assert.ok(frontmatter.includes(' - run_shell_command'), 'maps Bash -> run_shell_command');
assert.ok(frontmatter.includes(' - search_file_content'), 'maps Grep -> search_file_content');
assert.ok(frontmatter.includes(' - glob'), 'maps Glob -> glob');
assert.ok(frontmatter.includes(' - write_file'), 'maps Write -> write_file');
assert.ok(!frontmatter.includes('color:'), 'drops unsupported color field');
assert.ok(!frontmatter.includes('skills:'), 'drops unsupported skills field');
assert.ok(!frontmatter.includes('gsd-mapper-workflow'), 'drops skills list items');
assert.ok(result.includes('$PHASE'), 'escapes ${PHASE} shell variable for Gemini');
assert.ok(!result.includes('${PHASE}'), 'removes Gemini template-string pattern');
});
});