From c5bdd17f3f77c6d9db6735568fbaa281974e815e Mon Sep 17 00:00:00 2001 From: chuenchen309 <48723787+chuenchen309@users.noreply.github.com> Date: Sun, 19 Jul 2026 16:09:03 +0800 Subject: [PATCH] fix(agents): parse frontmatter on the --- delimiter line, not any --- substring MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CommandRegistrar.parse_frontmatter located the closing delimiter with content.find("---", 3), a raw substring search. It stopped at the first "---" anywhere after the opening — including one embedded in a frontmatter value (e.g. a description "Separate sections with --- markers") or inside an indented literal block — which truncated the frontmatter and spilled the remainder into the body, silently corrupting both the parsed metadata and the rendered command body. Match the closing "---" on line boundaries, mirroring the line-anchored scan already used by VibeIntegration._inject_frontmatter_flag. --- src/specify_cli/agents.py | 21 ++++++++++++++++----- tests/test_extensions.py | 15 +++++++++++++++ 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/src/specify_cli/agents.py b/src/specify_cli/agents.py index e4d09ffe99..00d5088594 100644 --- a/src/specify_cli/agents.py +++ b/src/specify_cli/agents.py @@ -114,13 +114,24 @@ def parse_frontmatter(content: str) -> tuple[dict, str]: if not content.startswith("---"): return {}, content - # Find second --- - end_marker = content.find("---", 3) - if end_marker == -1: + # The closing delimiter is a line that is exactly ``---`` (a YAML + # document separator), not any ``---`` substring. Scanning with + # ``content.find("---", 3)`` stops at the first ``---`` *anywhere* — + # including one embedded in a frontmatter value (e.g. a description like + # "Separate sections with ---") or inside an indented literal block — + # which truncates the frontmatter and spills the remainder into the + # body. Match on line boundaries instead, mirroring the line-anchored + # scan in ``VibeIntegration._inject_frontmatter_flag``. + lines = content.splitlines(keepends=True) + end_line = next( + (i for i in range(1, len(lines)) if lines[i].rstrip() == "---"), + None, + ) + if end_line is None: return {}, content - frontmatter_str = content[3:end_marker].strip() - body = content[end_marker + 3 :].strip() + frontmatter_str = "".join(lines[1:end_line]).strip() + body = "".join(lines[end_line + 1 :]).strip() try: frontmatter = yaml.safe_load(frontmatter_str) or {} diff --git a/tests/test_extensions.py b/tests/test_extensions.py index 652540d1be..f45125da6e 100644 --- a/tests/test_extensions.py +++ b/tests/test_extensions.py @@ -1638,6 +1638,21 @@ def test_parse_frontmatter_non_mapping_returns_empty_dict(self): assert frontmatter == {} assert "Command body" in body + def test_parse_frontmatter_dash_in_value(self): + """A ``---`` inside a frontmatter value must not close the block early.""" + content = """--- +description: Separate sections with --- markers +argument-hint: "[name]" +--- +Real body starts here. +""" + registrar = CommandRegistrar() + frontmatter, body = registrar.parse_frontmatter(content) + + assert frontmatter["description"] == "Separate sections with --- markers" + assert frontmatter["argument-hint"] == "[name]" + assert body == "Real body starts here." + def test_render_frontmatter(self): """Test rendering frontmatter to YAML.""" frontmatter = {