test(03-02): add failing Kimi agent install tests
- assert Kimi global layout stages agent YAML and prompts - expect global install to write agents/gsd.yaml while local guard stays no-op
This commit is contained in:
@@ -94,15 +94,19 @@ describe('Kimi runtime homes', () => {
|
||||
});
|
||||
|
||||
describe('Kimi runtime artifact layout', () => {
|
||||
test('global layout stages Kimi skills while local layout remains guarded', () => {
|
||||
test('global layout stages Kimi skills and agents while local layout remains guarded', () => {
|
||||
const globalLayout = resolveRuntimeArtifactLayout('kimi', '/tmp/kimi-config', 'global');
|
||||
assert.strictEqual(globalLayout.runtime, 'kimi');
|
||||
assert.strictEqual(globalLayout.configDir, '/tmp/kimi-config');
|
||||
assert.strictEqual(globalLayout.kinds.length, 1);
|
||||
assert.strictEqual(globalLayout.kinds.length, 2);
|
||||
assert.strictEqual(globalLayout.kinds[0].kind, 'skills');
|
||||
assert.strictEqual(globalLayout.kinds[0].destSubpath, 'skills');
|
||||
assert.strictEqual(globalLayout.kinds[0].prefix, 'gsd-');
|
||||
assert.strictEqual(typeof globalLayout.kinds[0].stage, 'function');
|
||||
assert.strictEqual(globalLayout.kinds[1].kind, 'kimi-agents');
|
||||
assert.strictEqual(globalLayout.kinds[1].destSubpath, 'agents');
|
||||
assert.strictEqual(globalLayout.kinds[1].prefix, 'gsd');
|
||||
assert.strictEqual(typeof globalLayout.kinds[1].stage, 'function');
|
||||
|
||||
const localLayout = resolveRuntimeArtifactLayout('kimi', '/tmp/kimi-config', 'local');
|
||||
assert.strictEqual(localLayout.runtime, 'kimi');
|
||||
@@ -143,7 +147,7 @@ describe('Kimi local install guard', () => {
|
||||
}
|
||||
});
|
||||
|
||||
test('--kimi --global writes converted Kimi skills only', () => {
|
||||
test('--kimi --global writes converted Kimi skills and agent artifacts', () => {
|
||||
const tmpProject = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-kimi-global-project-'));
|
||||
const tmpConfig = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-kimi-global-config-'));
|
||||
const tmpHome = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-kimi-global-home-'));
|
||||
@@ -166,6 +170,8 @@ describe('Kimi local install guard', () => {
|
||||
const combined = `${result.stdout}\n${result.stderr}`;
|
||||
assert.match(combined, /Installing for .*Kimi/i);
|
||||
assert.match(combined, /Installed \d+ skills to skills\//i);
|
||||
assert.match(combined, /Generated Kimi root agent: .*agents.*gsd\.yaml/i);
|
||||
assert.match(combined, /kimi --agent-file/i);
|
||||
|
||||
const skillFile = path.join(tmpConfig, 'skills', 'gsd-new-project', 'SKILL.md');
|
||||
assert.ok(fs.existsSync(skillFile), 'must write gsd-new-project/SKILL.md');
|
||||
@@ -174,7 +180,30 @@ describe('Kimi local install guard', () => {
|
||||
assert.match(skillContent, /\/skill:gsd-new-project/);
|
||||
assert.doesNotMatch(skillContent, /kimi_cli\.tools|system_prompt_path|^version: 1$/m);
|
||||
|
||||
assert.ok(!fs.existsSync(path.join(tmpConfig, 'agents')), 'must not write Kimi agents');
|
||||
const rootYaml = path.join(tmpConfig, 'agents', 'gsd.yaml');
|
||||
const rootPrompt = path.join(tmpConfig, 'agents', 'gsd.md');
|
||||
const executorYaml = path.join(tmpConfig, 'agents', 'subagents', 'gsd-executor.yaml');
|
||||
const executorPrompt = path.join(tmpConfig, 'agents', 'subagents', 'gsd-executor.md');
|
||||
assert.ok(fs.existsSync(rootYaml), 'must write agents/gsd.yaml');
|
||||
assert.ok(fs.existsSync(rootPrompt), 'must write agents/gsd.md');
|
||||
assert.ok(fs.existsSync(executorYaml), 'must write agents/subagents/gsd-executor.yaml');
|
||||
assert.ok(fs.existsSync(executorPrompt), 'must write agents/subagents/gsd-executor.md');
|
||||
|
||||
const rootYamlContent = fs.readFileSync(rootYaml, 'utf8');
|
||||
assert.match(rootYamlContent, /^version: 1$/m);
|
||||
assert.match(rootYamlContent, /^agent:$/m);
|
||||
assert.match(rootYamlContent, /extend: default/);
|
||||
assert.match(rootYamlContent, /system_prompt_path: \.\/gsd\.md/);
|
||||
assert.match(rootYamlContent, /tools:/);
|
||||
assert.match(rootYamlContent, /subagents:/);
|
||||
assert.match(rootYamlContent, /kimi_cli\.tools\./);
|
||||
assert.doesNotMatch(rootYamlContent, /mcp__/);
|
||||
|
||||
const executorYamlContent = fs.readFileSync(executorYaml, 'utf8');
|
||||
assert.match(executorYamlContent, /system_prompt_path: \.\/gsd-executor\.md/);
|
||||
assert.match(executorYamlContent, /kimi_cli\.tools\./);
|
||||
assert.doesNotMatch(executorYamlContent, /mcp__/);
|
||||
|
||||
assert.ok(!fs.existsSync(path.join(tmpConfig, 'gsd-core')), 'must not write workflow payloads as Kimi artifacts');
|
||||
assert.ok(!fs.existsSync(path.join(tmpConfig, 'hooks')), 'must not write hooks under the Kimi root');
|
||||
} finally {
|
||||
|
||||
@@ -101,6 +101,31 @@ describe('installRuntimeArtifacts — skills runtimes write gsd-prefixed skill d
|
||||
assert.match(content, /^name: gsd-new-project$/m);
|
||||
assert.match(content, /\/skill:gsd-new-project/);
|
||||
assert.doesNotMatch(content, /kimi_cli\.tools|system_prompt_path|^version: 1$/m);
|
||||
|
||||
const agentsDir = path.join(configDir, 'agents');
|
||||
const rootYaml = path.join(agentsDir, 'gsd.yaml');
|
||||
const rootPrompt = path.join(agentsDir, 'gsd.md');
|
||||
const executorYaml = path.join(agentsDir, 'subagents', 'gsd-executor.yaml');
|
||||
const executorPrompt = path.join(agentsDir, 'subagents', 'gsd-executor.md');
|
||||
assert.ok(fs.existsSync(rootYaml), 'kimi: agents/gsd.yaml must exist');
|
||||
assert.ok(fs.existsSync(rootPrompt), 'kimi: agents/gsd.md must exist');
|
||||
assert.ok(fs.existsSync(executorYaml), 'kimi: agents/subagents/gsd-executor.yaml must exist');
|
||||
assert.ok(fs.existsSync(executorPrompt), 'kimi: agents/subagents/gsd-executor.md must exist');
|
||||
|
||||
const rootYamlContent = fs.readFileSync(rootYaml, 'utf8');
|
||||
assert.match(rootYamlContent, /^version: 1$/m);
|
||||
assert.match(rootYamlContent, /^agent:$/m);
|
||||
assert.match(rootYamlContent, /extend: default/);
|
||||
assert.match(rootYamlContent, /system_prompt_path: \.\/gsd\.md/);
|
||||
assert.match(rootYamlContent, /tools:/);
|
||||
assert.match(rootYamlContent, /subagents:/);
|
||||
assert.match(rootYamlContent, /kimi_cli\.tools\./);
|
||||
assert.doesNotMatch(rootYamlContent, /mcp__/);
|
||||
|
||||
const executorYamlContent = fs.readFileSync(executorYaml, 'utf8');
|
||||
assert.match(executorYamlContent, /system_prompt_path: \.\/gsd-executor\.md/);
|
||||
assert.match(executorYamlContent, /kimi_cli\.tools\./);
|
||||
assert.doesNotMatch(executorYamlContent, /mcp__/);
|
||||
}
|
||||
|
||||
if (RESOLVED_CORE.skills !== '*') {
|
||||
@@ -213,6 +238,14 @@ describe('uninstallRuntimeArtifacts — removes gsd-owned entries, preserves for
|
||||
const foreignDir = path.join(destDir, 'user-custom-skill');
|
||||
fs.mkdirSync(foreignDir, { recursive: true });
|
||||
fs.writeFileSync(path.join(foreignDir, 'SKILL.md'), '# user\n');
|
||||
} else if (kind.kind === 'kimi-agents') {
|
||||
fs.mkdirSync(path.join(destDir, 'subagents'), { recursive: true });
|
||||
fs.writeFileSync(path.join(destDir, 'gsd.yaml'), 'version: 1\n');
|
||||
fs.writeFileSync(path.join(destDir, 'gsd.md'), '# gsd\n');
|
||||
fs.writeFileSync(path.join(destDir, 'subagents', 'gsd-executor.yaml'), 'version: 1\n');
|
||||
fs.writeFileSync(path.join(destDir, 'subagents', 'gsd-executor.md'), '# executor\n');
|
||||
fs.writeFileSync(path.join(destDir, 'user-agent.yaml'), 'version: 1\n');
|
||||
fs.writeFileSync(path.join(destDir, 'subagents', 'user-agent.yaml'), 'version: 1\n');
|
||||
} else {
|
||||
writeCommandEntry(destDir, kind.prefix, 'help');
|
||||
writeCommandEntry(destDir, kind.prefix, 'phase');
|
||||
@@ -228,6 +261,13 @@ describe('uninstallRuntimeArtifacts — removes gsd-owned entries, preserves for
|
||||
assert.ok(!fs.existsSync(path.join(destDir, `${kind.prefix}help`)));
|
||||
assert.ok(!fs.existsSync(path.join(destDir, `${kind.prefix}phase`)));
|
||||
assert.ok(fs.existsSync(path.join(destDir, 'user-custom-skill', 'SKILL.md')));
|
||||
} else if (kind.kind === 'kimi-agents') {
|
||||
assert.ok(!fs.existsSync(path.join(destDir, 'gsd.yaml')));
|
||||
assert.ok(!fs.existsSync(path.join(destDir, 'gsd.md')));
|
||||
assert.ok(!fs.existsSync(path.join(destDir, 'subagents', 'gsd-executor.yaml')));
|
||||
assert.ok(!fs.existsSync(path.join(destDir, 'subagents', 'gsd-executor.md')));
|
||||
assert.ok(fs.existsSync(path.join(destDir, 'user-agent.yaml')));
|
||||
assert.ok(fs.existsSync(path.join(destDir, 'subagents', 'user-agent.yaml')));
|
||||
} else {
|
||||
assert.ok(!fs.existsSync(path.join(destDir, `${kind.prefix}help.md`)));
|
||||
assert.ok(!fs.existsSync(path.join(destDir, `${kind.prefix}phase.md`)));
|
||||
|
||||
@@ -180,11 +180,15 @@ describe('resolveRuntimeArtifactLayout — kimi', () => {
|
||||
const globalLayout = resolveRuntimeArtifactLayout('kimi', FAKE_DIR, 'global');
|
||||
assert.strictEqual(globalLayout.runtime, 'kimi');
|
||||
assert.strictEqual(globalLayout.configDir, FAKE_DIR);
|
||||
assert.strictEqual(globalLayout.kinds.length, 1);
|
||||
assert.strictEqual(globalLayout.kinds.length, 2);
|
||||
assert.strictEqual(globalLayout.kinds[0].kind, 'skills');
|
||||
assert.strictEqual(globalLayout.kinds[0].destSubpath, 'skills');
|
||||
assert.strictEqual(globalLayout.kinds[0].prefix, 'gsd-');
|
||||
assert.strictEqual(typeof globalLayout.kinds[0].stage, 'function');
|
||||
assert.strictEqual(globalLayout.kinds[1].kind, 'kimi-agents');
|
||||
assert.strictEqual(globalLayout.kinds[1].destSubpath, 'agents');
|
||||
assert.strictEqual(globalLayout.kinds[1].prefix, 'gsd');
|
||||
assert.strictEqual(typeof globalLayout.kinds[1].stage, 'function');
|
||||
|
||||
const localLayout = resolveRuntimeArtifactLayout('kimi', FAKE_DIR, 'local');
|
||||
assert.strictEqual(localLayout.runtime, 'kimi');
|
||||
@@ -398,7 +402,7 @@ describe('stage — skills kind (claude global)', () => {
|
||||
});
|
||||
|
||||
describe('stage — skills kind (kimi global)', () => {
|
||||
test('stage returns Kimi SKILL.md dirs with /skill:gsd-* invocations', () => {
|
||||
test('stage returns Kimi SKILL.md dirs and agent YAML/prompt artifacts', () => {
|
||||
const layout = resolveRuntimeArtifactLayout('kimi', FAKE_STAGE_DIR, 'global');
|
||||
const skillsKind = layout.kinds.find(k => k.kind === 'skills');
|
||||
assert.ok(skillsKind, 'should have a skills kind');
|
||||
@@ -411,6 +415,34 @@ describe('stage — skills kind (kimi global)', () => {
|
||||
assert.match(content, /^name: gsd-new-project$/m);
|
||||
assert.match(content, /\/skill:gsd-new-project/);
|
||||
assert.doesNotMatch(content, /kimi_cli\.tools|system_prompt_path|^version: 1$/m);
|
||||
|
||||
const agentsKind = layout.kinds.find(k => k.kind === 'kimi-agents');
|
||||
assert.ok(agentsKind, 'should have a kimi-agents kind');
|
||||
|
||||
const stagedAgentsDir = agentsKind.stage(PROFILE_FULL);
|
||||
const rootYamlPath = path.join(stagedAgentsDir, 'gsd.yaml');
|
||||
const rootPromptPath = path.join(stagedAgentsDir, 'gsd.md');
|
||||
const executorYamlPath = path.join(stagedAgentsDir, 'subagents', 'gsd-executor.yaml');
|
||||
const executorPromptPath = path.join(stagedAgentsDir, 'subagents', 'gsd-executor.md');
|
||||
assert.ok(fs.existsSync(rootYamlPath), 'agents/gsd.yaml must be staged');
|
||||
assert.ok(fs.existsSync(rootPromptPath), 'agents/gsd.md must be staged');
|
||||
assert.ok(fs.existsSync(executorYamlPath), 'agents/subagents/gsd-executor.yaml must be staged');
|
||||
assert.ok(fs.existsSync(executorPromptPath), 'agents/subagents/gsd-executor.md must be staged');
|
||||
|
||||
const rootYaml = fs.readFileSync(rootYamlPath, 'utf8');
|
||||
assert.match(rootYaml, /^version: 1$/m);
|
||||
assert.match(rootYaml, /^agent:$/m);
|
||||
assert.match(rootYaml, /extend: default/);
|
||||
assert.match(rootYaml, /system_prompt_path: \.\/gsd\.md/);
|
||||
assert.match(rootYaml, /tools:/);
|
||||
assert.match(rootYaml, /subagents:/);
|
||||
assert.match(rootYaml, /kimi_cli\.tools\./);
|
||||
assert.doesNotMatch(rootYaml, /mcp__/);
|
||||
|
||||
const executorYaml = fs.readFileSync(executorYamlPath, 'utf8');
|
||||
assert.match(executorYaml, /system_prompt_path: \.\/gsd-executor\.md/);
|
||||
assert.match(executorYaml, /kimi_cli\.tools\./);
|
||||
assert.doesNotMatch(executorYaml, /mcp__/);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user