From 765f866af545c366e1b731161eaf0a92b7dcb0e5 Mon Sep 17 00:00:00 2001 From: zhuyouwei Date: Sat, 11 Jul 2026 22:15:06 +0800 Subject: [PATCH] fix(skills): skip plugin documentation files --- .changeset/skip-plugin-document-skills.md | 5 +++++ packages/agent-core/src/skill/scanner.ts | 15 +++++++++++++++ packages/agent-core/test/skill/scanner.test.ts | 18 ++++++++++++++++++ 3 files changed, 38 insertions(+) create mode 100644 .changeset/skip-plugin-document-skills.md diff --git a/.changeset/skip-plugin-document-skills.md b/.changeset/skip-plugin-document-skills.md new file mode 100644 index 0000000000..2fb304c4e4 --- /dev/null +++ b/.changeset/skip-plugin-document-skills.md @@ -0,0 +1,5 @@ +--- +"@moonshot-ai/kimi-code": patch +--- + +Prevent plugin documentation files from appearing as skills. diff --git a/packages/agent-core/src/skill/scanner.ts b/packages/agent-core/src/skill/scanner.ts index 6c1ddb462c..fb32b8e3e5 100644 --- a/packages/agent-core/src/skill/scanner.ts +++ b/packages/agent-core/src/skill/scanner.ts @@ -16,6 +16,18 @@ const PROJECT_GENERIC_DIRS = ['.agents/skills'] as const; // loop forever. Real skill trees are 1-3 levels deep. const MAX_SKILL_SCAN_DEPTH = 8; +// Plugin packages commonly keep release and repository documentation next to +// their skill entrypoints. These files are not skills, even though legacy flat +// skill discovery accepts arbitrary top-level Markdown files without +// frontmatter. +const PLUGIN_DOCUMENT_FILENAMES = new Set([ + 'changelog.md', + 'code_of_conduct.md', + 'contributing.md', + 'license.md', + 'readme.md', +]); + export interface SkillPathContext { readonly userHomeDir: string; /** @@ -215,6 +227,9 @@ export async function discoverSkills( for (const entry of entries) { if (!entry.endsWith('.md')) continue; if (entry === 'SKILL.md') continue; + if (root.plugin !== undefined && PLUGIN_DOCUMENT_FILENAMES.has(entry.toLowerCase())) { + continue; + } const skillName = entry.slice(0, -'.md'.length); if (directorySkills.has(skillName)) { warn( diff --git a/packages/agent-core/test/skill/scanner.test.ts b/packages/agent-core/test/skill/scanner.test.ts index 38377338ea..8bad1d539f 100644 --- a/packages/agent-core/test/skill/scanner.test.ts +++ b/packages/agent-core/test/skill/scanner.test.ts @@ -130,6 +130,24 @@ describe('skill discovery', () => { expect(warnings.some((message) => message.includes('Ignoring flat skill'))).toBe(true); }); + it('does not register conventional plugin documentation as flat skills', async () => { + const { repoDir } = await makeWorkspace(); + const pluginRoot = path.join(repoDir, 'plugin-skills'); + await mkdir(pluginRoot, { recursive: true }); + await writeFile(path.join(pluginRoot, 'CHANGELOG.md'), '# Changelog'); + await writeFile(path.join(pluginRoot, 'README.md'), '# Plugin readme'); + await writeFile( + path.join(pluginRoot, 'release-notes.md'), + ['---', 'name: release-notes', 'description: Release notes skill', '---'].join('\n'), + ); + + const skills = await discoverSkills({ + roots: [{ path: pluginRoot, source: 'extra', plugin: { id: 'example-plugin' } }], + }); + + expect(skills.map((skill) => skill.name)).toEqual(['release-notes']); + }); + it('keeps flow skills user-visible while excluding them from model invocation', async () => { const { repoDir } = await makeWorkspace(); const projectRoot = path.join(repoDir, '.kimi-code', 'skills');