问题与复现
packages/skill-hub 的 SKILL.md frontmatter 解析器(parseFrontmatter,packages/skill-hub/src/index.ts:347)只处理内联标量,不支持 YAML 块标量。而仓库自带的 13 个 skill 里有 12 个把描述写成块标量:
- 11 个用字面块标量
description: |(例如 skills/longbridge-market-data/SKILL.md:3)
- 1 个用折叠块标量
description: >(skills/longbridge-earnings/SKILL.md:3)
- 只有
skills/longbridge/SKILL.md 用引号标量,不受影响
根因有两步。第一,description: | 的行内取值是 "|"(非空),于是 parseFrontmatter 第 358 行的嵌套块判定(要求 rawValue.length === 0)不成立,直接落到 result[key] = parseScalar("|"),把指示符本身当成了取值。第二,紧接着的块正文行 Triggers: "新闻", … 含冒号,被当作新的 frontmatter 键写入。
用真实文件实测(输入 skills/longbridge-market-data/SKILL.md):
frontmatter.description = "|"
frontmatter keys = ["name","description","Triggers","license","metadata"]
折叠块更严重——longbridge-earnings 的块正文里有 3 行含冒号,全部变成伪造键:
frontmatter.description = ">"
frontmatter keys = ["name","description",
"Earnings analysis — pre- and post-earnings. Pre-earnings preview",
"release. Post-earnings",
"post-earnings / quarterly-results writeup. Triggers"]
预期与修复方向
description 应当是块正文本身:字面块(|)按换行连接,折叠块(>)按空格连接;块正文里的 Key: value 行属于描述,不应成为 frontmatter 键。|- / |+ 等截断修饰也应按 YAML 语义处理。
影响(生产路径)
apps/electron/src/main/kernelHost.ts:313 以 new SkillHub({ skillsDirectory: getSkillsDir() }) 加载 skills/ 目录,metadata.description 随后经 buildSkillIndexSection(packages/shared/src/agent/pi-runtime-adapter.ts:576-588)拼进 Agent 的系统提示,实际渲染为:
Available skills (load them with read_skill_resource when relevant):
- longbridge-content: |
- longbridge-derivatives: |
- longbridge-earnings: >
...
此外 loadSkills(index.ts:109-112)用 extractTriggerKeywords(frontmatter.description) 提取触发词;取值为 "|" 时抽不到任何引用短语,而触发词只写在描述块内、没有独立的 keywords: 键 ⇒ 13 个 skill 的 keywords 全为空,SkillHub.search() 只能靠名称匹配。
复现证据
- OS:Windows 11;Bun 1.4.2;上游 main
3a17eca6
- 聚焦测试
bun test packages/skill-hub --isolate:修复前 21 pass / 7 fail(其中 6 条为本 issue 新增用例),修复后 27 pass / 1 fail
- 唯一残留失败
SkillHub V2 > blocks symlink escapes outside the skill directory 在 main 原始字节下同样失败(bun test packages/skill-hub/src/index.v2.test.ts --isolate = 8 pass / 1 fail,已还原字节并逐文件 cmp 校验),属 Windows symlink 平台差异,与本次改动无关
bun x tsc --noEmit -p packages/skill-hub/tsconfig.json:exit 0;bun run typecheck:core / i18n / shared / ui / electron 五工作区 exit 0
范围
只改 frontmatter 解析(新增 | / > 及其 - / + 修饰的识别)。不改任何 SKILL.md 文件,不改 toDescription / extractTriggerKeywords 的既有行为,不改内置 skill 的触发词清单。内联标量、嵌套块(metadata:)与引号标量的行为保持不变,均有用例守护。
问题与复现
packages/skill-hub的SKILL.mdfrontmatter 解析器(parseFrontmatter,packages/skill-hub/src/index.ts:347)只处理内联标量,不支持 YAML 块标量。而仓库自带的 13 个 skill 里有 12 个把描述写成块标量:description: |(例如skills/longbridge-market-data/SKILL.md:3)description: >(skills/longbridge-earnings/SKILL.md:3)skills/longbridge/SKILL.md用引号标量,不受影响根因有两步。第一,
description: |的行内取值是"|"(非空),于是parseFrontmatter第 358 行的嵌套块判定(要求rawValue.length === 0)不成立,直接落到result[key] = parseScalar("|"),把指示符本身当成了取值。第二,紧接着的块正文行Triggers: "新闻", …含冒号,被当作新的 frontmatter 键写入。用真实文件实测(输入
skills/longbridge-market-data/SKILL.md):折叠块更严重——
longbridge-earnings的块正文里有 3 行含冒号,全部变成伪造键:预期与修复方向
description应当是块正文本身:字面块(|)按换行连接,折叠块(>)按空格连接;块正文里的Key: value行属于描述,不应成为 frontmatter 键。|-/|+等截断修饰也应按 YAML 语义处理。影响(生产路径)
apps/electron/src/main/kernelHost.ts:313以new SkillHub({ skillsDirectory: getSkillsDir() })加载skills/目录,metadata.description随后经buildSkillIndexSection(packages/shared/src/agent/pi-runtime-adapter.ts:576-588)拼进 Agent 的系统提示,实际渲染为:此外
loadSkills(index.ts:109-112)用extractTriggerKeywords(frontmatter.description)提取触发词;取值为"|"时抽不到任何引用短语,而触发词只写在描述块内、没有独立的keywords:键 ⇒ 13 个 skill 的keywords全为空,SkillHub.search()只能靠名称匹配。复现证据
3a17eca6bun test packages/skill-hub --isolate:修复前 21 pass / 7 fail(其中 6 条为本 issue 新增用例),修复后 27 pass / 1 failSkillHub V2 > blocks symlink escapes outside the skill directory在 main 原始字节下同样失败(bun test packages/skill-hub/src/index.v2.test.ts --isolate= 8 pass / 1 fail,已还原字节并逐文件cmp校验),属 Windows symlink 平台差异,与本次改动无关bun x tsc --noEmit -p packages/skill-hub/tsconfig.json:exit 0;bun run typecheck:core / i18n / shared / ui / electron 五工作区 exit 0范围
只改 frontmatter 解析(新增
|/>及其-/+修饰的识别)。不改任何SKILL.md文件,不改toDescription/extractTriggerKeywords的既有行为,不改内置 skill 的触发词清单。内联标量、嵌套块(metadata:)与引号标量的行为保持不变,均有用例守护。