From cab4bf10d0c7b7a529f284e5e85dc1bf6e9a366f Mon Sep 17 00:00:00 2001 From: Drew Cain Date: Fri, 12 Jun 2026 11:14:08 -0500 Subject: [PATCH] fix(cli): emit only the literal file for plain read-note with --include-frontmatter The file's own frontmatter carries title/permalink, so the header line duplicated it. Plain without the flag keeps the header. Co-Authored-By: Claude Signed-off-by: Drew Cain --- src/basic_memory/cli/commands/tool.py | 17 +++++++++-------- tests/cli/test_cli_tool_rich_output.py | 7 ++++--- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/basic_memory/cli/commands/tool.py b/src/basic_memory/cli/commands/tool.py index 256f2a92..54fc51fa 100644 --- a/src/basic_memory/cli/commands/tool.py +++ b/src/basic_memory/cli/commands/tool.py @@ -395,16 +395,17 @@ def _plain_read_note(result: dict[str, Any], *, include_frontmatter: bool = Fals permalink = result.get("permalink", "") content = result.get("content", "") - header = f"{title} [{permalink}]" if permalink else title - print(header) - - print() # Trigger: --include-frontmatter makes the API return the literal file # (frontmatter block included) as content. - # Why: plain mode should show that file verbatim -- synthesizing a separate - # key/value block would print the frontmatter twice. - # Outcome: with the flag, the body IS the frontmatter view; either way trim - # surrounding newlines so the header gap stays a single blank line. + # Why: plain mode should show that file verbatim -- the file's own + # frontmatter already carries title/permalink, so a header line and a + # synthesized key/value block would both duplicate it. + # Outcome: with the flag, emit ONLY the file; without it, a title/permalink + # header then the body, trimmed to keep the gap a single blank line. + if not include_frontmatter: + header = f"{title} [{permalink}]" if permalink else title + print(header) + print() body = content.strip("\n") if content else "" if body: print(body) diff --git a/tests/cli/test_cli_tool_rich_output.py b/tests/cli/test_cli_tool_rich_output.py index 8443c876..dfbb2b2c 100644 --- a/tests/cli/test_cli_tool_rich_output.py +++ b/tests/cli/test_cli_tool_rich_output.py @@ -784,10 +784,11 @@ def test_read_note_plain_include_frontmatter(mock_mcp): result = _tty_runner(["tool", "read-note", "test-note", "--plain", "--include-frontmatter"]) assert result.exit_code == 0, f"CLI failed: {result.output}" - # The literal file: fences and YAML lines exactly as stored - assert "---\ntitle: Test Note\ntags:\n- test\n---" in result.output + # ONLY the literal file: no header line, output starts at the fence + assert "Test Note [notes/test-note]" not in result.output + assert result.output.startswith("---\ntitle: Test Note\ntags:\n- test\n---") assert "hello world" in result.output - # No duplicated frontmatter from a synthesized block + # No duplicated frontmatter from a synthesized block or header assert result.output.count("title: Test Note") == 1