feat(02-02): install Kimi global skills only

- Wire Kimi global layout to convertClaudeCommandToKimiSkill
- Keep --kimi --local guarded as a no-op
- Add Kimi self-invocation hint without agent or tool artifacts
This commit is contained in:
Viktorplus
2026-06-06 14:03:07 +02:00
parent da1b6111e7
commit cc447fcd66
3 changed files with 36 additions and 16 deletions

View File

@@ -2179,7 +2179,7 @@ function convertClaudeCommandToKimiSkill(content, skillName, _runtime = null, cm
names
);
return `---\nname: ${kimiSkillName}\ndescription: ${yamlQuote(toSingleLine(description))}\n---\n${normalizedBody}`;
return `---\nname: ${kimiSkillName}\ndescription: ${yamlQuote(toSingleLine(description))}\n---\nInvoke this Kimi skill with \`/skill:${kimiSkillName}\`.\n\n${normalizedBody}`;
}
/**
@@ -8291,19 +8291,14 @@ function install(isGlobal, runtime = 'claude', options = {}) {
const dirName = getDirName(runtime);
const src = path.join(__dirname, '..');
if (isKimi) {
const scopeLabel = isGlobal ? 'global' : 'local';
console.log(` ${yellow}⚠${reset} Kimi ${scopeLabel} install is deferred for Phase 1.`);
if (isGlobal) {
console.log(` No Kimi skills, agents, hooks, or workflow payload artifacts were written.`);
} else {
console.log(` No .kimi/skills or .agents/skills project artifacts were written.`);
}
console.log(` Phase 1 only registers Kimi selection, paths, and layout guards.`);
if (isKimi && !isGlobal) {
console.log(` ${yellow}⚠${reset} Kimi local install is deferred for Phase 2.`);
console.log(` No .kimi/skills or .agents/skills project artifacts were written.`);
console.log(` Project-level Kimi install semantics remain deferred.`);
return {
runtime,
skipped: true,
reason: isGlobal ? 'kimi_global_deferred' : 'kimi_local_deferred',
reason: 'kimi_local_deferred',
configDir: null,
settingsPath: null,
settings: null,
@@ -8455,6 +8450,31 @@ function install(isGlobal, runtime = 'claude', options = {}) {
rollback();
};
if (isKimi && isGlobal) {
installRuntimeArtifacts(runtime, targetDir, 'global', _resolvedProfile);
const skillsDir = path.join(targetDir, 'skills');
const count = fs.existsSync(skillsDir)
? fs.readdirSync(skillsDir, { withFileTypes: true })
.filter(e => e.isDirectory() && e.name.startsWith('gsd-')).length
: 0;
if (count > 0) {
console.log(` ${green}✓${reset} Installed ${count} skills to skills/`);
} else {
throw new Error('Kimi global install produced no skills/gsd-* entries');
}
return {
runtime,
skipped: true,
reason: 'kimi_global_skills_only',
configDir: targetDir,
settingsPath: null,
settings: null,
statuslineCommand: null,
updateBannerCommand: null,
rollbackInstallerMigrations,
};
}
// Save any locally modified GSD files before they get wiped.
// The pristine context lets saveLocalPatches populate gsd-pristine/ via
// the install transform pipeline, giving the reapply-patches Step 5

View File

@@ -305,9 +305,9 @@ function resolveRuntimeArtifactLayout(runtime: string, configDir: string, scope:
break;
case 'kimi':
// Phase 1 skeleton only: Kimi is recognized by the layout seam, but
// SKILL.md conversion and local project semantics are deferred.
kinds = [];
kinds = scope === 'global'
? [skillsKind('skills', 'gsd-', 'convertClaudeCommandToKimiSkill', 'kimi', configDir)]
: [];
break;
case 'opencode':

View File

@@ -71,8 +71,8 @@ describe('convertClaudeCommandToKimiSkill', () => {
assert.equal(
(result.match(/\/skill:gsd-new-project/g) || []).length,
4,
'all supported source invocation forms are rewritten'
5,
'self invocation hint and all supported source invocation forms are emitted'
);
assert.ok(!result.includes('/gsd:new-project'), 'slash colon form is removed');
assert.ok(!result.includes('gsd:new-project'), 'bare colon form is removed');