From 6a6243331e54599edcceb4e4998379daec6c9e57 Mon Sep 17 00:00:00 2001 From: Viktorplus <36795799+viktorplus@users.noreply.github.com> Date: Sat, 6 Jun 2026 13:49:06 +0200 Subject: [PATCH] test(02-01): add failing Kimi skill converter tests - Cover Kimi SKILL.md frontmatter shape - Cover /skill:gsd-new-project invocation rewrites - Assert Phase 3 agent/tool artifacts are absent --- tests/kimi-skill-converter.test.cjs | 94 +++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 tests/kimi-skill-converter.test.cjs diff --git a/tests/kimi-skill-converter.test.cjs b/tests/kimi-skill-converter.test.cjs new file mode 100644 index 000000000..3d07f6b96 --- /dev/null +++ b/tests/kimi-skill-converter.test.cjs @@ -0,0 +1,94 @@ +/** + * Kimi CLI skill converter tests. + * + * Kimi Agent Skills use gsd-/SKILL.md directories with lowercase + * hyphenated frontmatter names and /skill: invocation syntax. + */ + +process.env.GSD_TEST_MODE = '1'; + +const { test, describe } = require('node:test'); +const assert = require('node:assert/strict'); + +const { + convertClaudeCommandToKimiSkill, +} = require('../bin/install.js'); + +function sampleCommand() { + return [ + '---', + 'name: gsd:new-project', + 'description: Create a new GSD project', + 'allowed-tools:', + ' - Read', + ' - Bash', + 'agent: gsd-planner', + 'tools: Read, Bash', + 'model: opus', + 'color: blue', + 'skills:', + ' - gsd-planner-workflow', + 'hooks:', + ' PostToolUse:', + ' - matcher: "Write|Edit"', + '---', + '', + 'Invoke /gsd:new-project from slash form.', + 'Invoke gsd:new-project from bare colon form.', + 'Invoke /gsd-new-project from hyphen slash form.', + 'Invoke $gsd-new-project from shell-style form.', + 'Do not rewrite /gsd-tools, gsd-new-projector, or $gsd-planets.', + ].join('\n'); +} + +describe('convertClaudeCommandToKimiSkill', () => { + test('emits Kimi SKILL.md frontmatter with name and description only', () => { + const result = convertClaudeCommandToKimiSkill(sampleCommand(), 'gsd-new-project'); + + assert.ok(result.startsWith('---\n'), 'frontmatter starts with ---'); + assert.ok(result.includes('\n---\n'), 'frontmatter closes with ---'); + assert.ok(result.includes('name: gsd-new-project'), 'frontmatter name uses Kimi-safe hyphen form'); + assert.ok( + result.includes('description: "Create a new GSD project"'), + 'description is preserved from source frontmatter' + ); + + for (const unsupported of [ + 'allowed-tools', + 'agent', + 'tools', + 'model', + 'color', + 'skills', + 'hooks', + ]) { + assert.ok(!result.includes(`${unsupported}:`), `${unsupported}: is stripped from Kimi frontmatter`); + } + }); + + test('rewrites GSD command references to Kimi skill invocation syntax', () => { + const result = convertClaudeCommandToKimiSkill(sampleCommand(), 'gsd-new-project'); + + assert.equal( + (result.match(/\/skill:gsd-new-project/g) || []).length, + 4, + 'all supported source invocation forms are rewritten' + ); + assert.ok(!result.includes('/gsd:new-project'), 'slash colon form is removed'); + assert.ok(!result.includes('gsd:new-project'), 'bare colon form is removed'); + assert.ok(!result.includes('/gsd-new-project'), 'slash hyphen form is removed'); + assert.ok(!result.includes('$gsd-new-project'), 'shell-style form is removed'); + }); + + test('does not rewrite unrelated words or introduce Phase 3 artifacts', () => { + const result = convertClaudeCommandToKimiSkill(sampleCommand(), 'gsd-new-project'); + + assert.ok(result.includes('/gsd-tools'), 'non-command slash token is preserved'); + assert.ok(result.includes('gsd-new-projector'), 'longer hyphenated word is preserved'); + assert.ok(result.includes('$gsd-planets'), 'unrelated shell-style token is preserved'); + assert.ok(!result.includes('type: flow'), 'Phase 2 does not create Kimi flow skills'); + assert.ok(!result.includes('kimi_cli.tools'), 'Phase 2 does not emit Kimi tool module paths'); + assert.ok(!result.includes('system_prompt_path'), 'Phase 2 does not emit custom agent YAML'); + assert.ok(!result.includes('version: 1'), 'Phase 2 does not emit Kimi agent YAML markers'); + }); +});