From 040df4b11f40a0a6f30d5174e11d08dc43be7d22 Mon Sep 17 00:00:00 2001 From: Tony Coder <407243179@qq.com> Date: Mon, 17 Aug 2026 11:04:32 +0000 Subject: [PATCH] fix(rules): write rule name into markdown frontmatter createRuleMarkdown accepted a name argument but never emitted it. The name used to be rendered as an H1 in the rule body and was dropped when the body was simplified, so rules created via create_rule_block or the "New Rule" workspace block had no name and fell back to their file path. --- core/tools/implementations/createRuleBlock.test.ts | 4 ++++ .../config-yaml/src/markdown/createMarkdownRule.test.ts | 9 +++++++++ packages/config-yaml/src/markdown/createMarkdownRule.ts | 4 +++- 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/core/tools/implementations/createRuleBlock.test.ts b/core/tools/implementations/createRuleBlock.test.ts index 4808037b48b..1aaa6dc9121 100644 --- a/core/tools/implementations/createRuleBlock.test.ts +++ b/core/tools/implementations/createRuleBlock.test.ts @@ -36,6 +36,7 @@ test("createRuleBlockImpl should create a rule with glob pattern", async () => { const { frontmatter, markdown } = parseMarkdownRule(fileContent); expect(frontmatter).toEqual({ + name: "TypeScript Rule", alwaysApply: true, description: "Always use interfaces", globs: "**/*.{ts,tsx}", @@ -73,6 +74,7 @@ test("createRuleBlockImpl should create a rule with description pattern", async const { frontmatter, markdown } = parseMarkdownRule(fileContent); expect(frontmatter).toEqual({ + name: "Description Test", alwaysApply: true, description: "This is a detailed explanation of the rule", }); @@ -96,6 +98,7 @@ test("createRuleBlockImpl should include both globs and description in frontmatt const { frontmatter, markdown } = parseMarkdownRule(fileContent); expect(frontmatter).toEqual({ + name: "Complete Rule", alwaysApply: false, description: "This rule enforces our team standards", globs: "**/*.js", @@ -119,6 +122,7 @@ test("createRuleBlockImpl should create a rule with alwaysApply set to false", a const { frontmatter } = parseMarkdownRule(fileContent); expect(frontmatter).toEqual({ + name: "Conditional Rule", alwaysApply: false, description: "Optional rule", }); diff --git a/packages/config-yaml/src/markdown/createMarkdownRule.test.ts b/packages/config-yaml/src/markdown/createMarkdownRule.test.ts index 7a88c165eb6..9d48a42f175 100644 --- a/packages/config-yaml/src/markdown/createMarkdownRule.test.ts +++ b/packages/config-yaml/src/markdown/createMarkdownRule.test.ts @@ -101,6 +101,7 @@ describe("createRuleMarkdown", () => { const parsed = markdownToRule(result, mockPackageId); + expect(parsed.name).toBe("Test Rule"); expect(parsed.description).toBe("Test description"); expect(parsed.globs).toEqual(["*.ts", "*.js"]); expect(parsed.alwaysApply).toBe(true); @@ -112,12 +113,20 @@ describe("createRuleMarkdown", () => { const parsed = markdownToRule(result, mockPackageId); + expect(parsed.name).toBe("Simple Rule"); expect(parsed.description).toBeUndefined(); expect(parsed.globs).toBeUndefined(); expect(parsed.alwaysApply).toBeUndefined(); expect(parsed.rule).toBe("Simple content"); }); + it("should trim the name", () => { + const result = createRuleMarkdown(" Padded Name ", "Content"); + + const parsed = markdownToRule(result, mockPackageId); + expect(parsed.name).toBe("Padded Name"); + }); + it("should handle string globs", () => { const result = createRuleMarkdown("String Glob Rule", "Content", { globs: "*.py", diff --git a/packages/config-yaml/src/markdown/createMarkdownRule.ts b/packages/config-yaml/src/markdown/createMarkdownRule.ts index b868bbb51fa..8327a28a220 100644 --- a/packages/config-yaml/src/markdown/createMarkdownRule.ts +++ b/packages/config-yaml/src/markdown/createMarkdownRule.ts @@ -39,7 +39,9 @@ export function createRuleMarkdown( invokable?: boolean; } = {}, ): string { - const frontmatter: RuleFrontmatter = {}; + const frontmatter: RuleFrontmatter = { + name: name.trim(), + }; if (options.globs) { frontmatter.globs =