feat(03-02): install Kimi global agent artifacts

- stage generated Kimi root and subagent YAML/prompt files under agents/
- copy and remove only GSD-owned Kimi agent files while preserving user files
- print explicit kimi --agent-file launch hint
This commit is contained in:
Viktorplus
2026-06-06 14:57:48 +02:00
parent de5c57c685
commit fba6cfe63d
2 changed files with 80 additions and 3 deletions

View File

@@ -64,6 +64,7 @@ function getInstallExports(): InstallExports {
// ---------------------------------------------------------------------------
type ArtifactKindName = 'commands' | 'agents' | 'skills';
type KimiArtifactKindName = ArtifactKindName | 'kimi-agents';
// Mirrors the (unexported) ResolvedProfile in install-profiles.cts.
// Must stay in sync if that shape changes.
@@ -74,7 +75,7 @@ interface ResolvedProfile {
}
interface ArtifactKind {
kind: ArtifactKindName;
kind: KimiArtifactKindName;
destSubpath: string;
prefix: string;
stage: (resolvedProfile: ResolvedProfile) => string;
@@ -192,6 +193,50 @@ function agentsKind(destSubpath: string, prefix: string, configDir: string): Art
};
}
function kimiAgentsKind(destSubpath: string, prefix: string, configDir: string): ArtifactKind {
return {
kind: 'kimi-agents',
destSubpath,
prefix,
stage: (resolved) => {
const installExports = getInstallExports();
const buildKimiAgentArtifacts = installExports['buildKimiAgentArtifacts'] as (opts: {
rootAgent?: string;
subagents?: Array<{ path: string; content: string }>;
}) => {
root: { yaml: string; prompt: string };
subagents: Array<{ name: string; yaml: string; prompt: string }>;
};
const stagedAgents = stageAgentsForProfile(findAgentsSourceRoot(configDir), resolved);
const subagents: Array<{ path: string; content: string }> = [];
if (fs.existsSync(stagedAgents)) {
for (const entry of fs.readdirSync(stagedAgents, { withFileTypes: true })) {
if (!entry.isFile() || !entry.name.endsWith('.md')) continue;
const agentPath = path.join(stagedAgents, entry.name);
subagents.push({
path: path.join('agents', entry.name).replace(/\\/g, '/'),
content: fs.readFileSync(agentPath, 'utf8'),
});
}
}
const rootAgent = `---\nname: gsd\ndescription: Run GSD workflows in Kimi CLI.\ntools: Agent\n---\n\n# GSD for Kimi CLI\n\nCoordinate installed /skill:gsd-* workflows and route work to generated GSD subagents when a workflow requires an agent handoff.\n`;
const artifacts = buildKimiAgentArtifacts({ rootAgent, subagents });
const stageDir = fs.mkdtempSync(path.join(require('node:os').tmpdir(), 'gsd-kimi-agents-'));
fs.writeFileSync(path.join(stageDir, 'gsd.yaml'), artifacts.root.yaml);
fs.writeFileSync(path.join(stageDir, 'gsd.md'), artifacts.root.prompt);
const subagentsDir = path.join(stageDir, 'subagents');
fs.mkdirSync(subagentsDir, { recursive: true });
for (const artifact of artifacts.subagents) {
fs.writeFileSync(path.join(subagentsDir, `${artifact.name}.yaml`), artifact.yaml);
fs.writeFileSync(path.join(subagentsDir, `${artifact.name}.md`), artifact.prompt);
}
installProfiles.STAGED_DIRS.add(stageDir);
return stageDir;
},
};
}
/**
* Build a skills kind descriptor.
*
@@ -306,7 +351,10 @@ function resolveRuntimeArtifactLayout(runtime: string, configDir: string, scope:
case 'kimi':
kinds = scope === 'global'
? [skillsKind('skills', 'gsd-', 'convertClaudeCommandToKimiSkill', 'kimi', configDir)]
? [
skillsKind('skills', 'gsd-', 'convertClaudeCommandToKimiSkill', 'kimi', configDir),
kimiAgentsKind('agents', 'gsd', configDir),
]
: [];
break;