diff --git a/plugin/src/claude_smart/context_format.py b/plugin/src/claude_smart/context_format.py index 09b5b9f..629e6a0 100644 --- a/plugin/src/claude_smart/context_format.py +++ b/plugin/src/claude_smart/context_format.py @@ -264,42 +264,24 @@ def render_inline_compact_with_registry( def _compact_citation_instruction(marker_parts: list[str] | None = None) -> str: + del marker_parts # compact guidance must not scale with injected memory count. if os.environ.get("CLAUDE_SMART_CITATIONS", "on") == "off": return "" gate = cs_cite.WHEN_TO_CITE_COMPACT link_style = os.environ.get(_CITATION_LINK_STYLE_ENV, "markdown") - if link_style == "osc8" and marker_parts: - marker = cs_cite.build_marker(" | ".join(marker_parts), "osc8") - separator_instruction = ( - " Separate multiple linked memories with the visible ` | ` separator." - if len(marker_parts) > 1 - else "" - ) - return _remoteize_citation_instruction( - f"{gate} If you do, copy this final marker exactly, preserving its " - f"hidden OSC 8 terminal link: `{marker}`.{separator_instruction}" - ) if link_style == "osc8": return _remoteize_citation_instruction( - f"{gate} If you do, end with `{cs_cite.MARKER_PREFIX}` " - "followed by the same linked memory text, then " - f"`{cs_cite.marker_attribution('osc8')}` linking to the reflexio " - "repo; keep the links, but do not show the URL." - ) - if marker_parts: - marker = cs_cite.build_marker(" | ".join(marker_parts), "markdown") - separator_instruction = ( - " Separate multiple linked memories with the visible ` | ` separator." - if len(marker_parts) > 1 - else "" - ) - return _remoteize_citation_instruction( - f"{gate} If you do, copy this final marker exactly with markdown " - f"links: `{marker}`.{separator_instruction}" + f"{gate} If you do, end with a final marker like " + f"`{cs_cite.build_marker(_osc8_link('http://localhost:3001/rules/s1-123', 'verify process state'), 'osc8')}` " + "using the linked title and shown rule URL for each memory you actually used; " + "preserve hidden OSC 8 terminal links, do not show raw URLs, and separate multiple " + "linked memories with the visible ` | ` separator." ) return _remoteize_citation_instruction( - f"{gate} If you do, end with one final marker like " - f"`{cs_cite.MARKDOWN_EXAMPLE_ONE}` using the shown rule URL." + f"{gate} If you do, end with a final marker like " + f"`{cs_cite.MARKDOWN_EXAMPLE_ONE}` using the title and shown rule URL " + "for each memory you actually used; separate multiple linked memories " + "with the visible ` | ` separator." ) diff --git a/tests/test_context_format.py b/tests/test_context_format.py index 4aa6a9c..38c2819 100644 --- a/tests/test_context_format.py +++ b/tests/test_context_format.py @@ -283,17 +283,43 @@ def test_render_inline_compact_with_registry_is_one_logical_line( assert "prefers concise answers" in md assert "✨ claude-smart rule applied:" in md assert md.count("✨ claude-smart rule applied:") == 1 - assert "copy this final marker exactly with markdown links" in md + assert "copy this final marker exactly with markdown links" not in md assert ( "✨ claude-smart rule applied: " "[Run uv sync after pyproject edits](http://localhost:3001/rules/s1-17) | " "[prefers concise answers](http://localhost:3001/rules/p1-pref)" - ) in md + ) not in md + assert cs_cite.MARKDOWN_EXAMPLE_ONE in md + assert "for each memory you actually used" in md assert "visible ` | ` separator" in md assert "\x1b]8;;" not in md assert {entry["id"] for entry in registry} == {"s1-17", "p1-pref"} +def test_render_inline_compact_with_registry_does_not_prebuild_all_markdown_citations( + monkeypatch, +) -> None: + monkeypatch.delenv("CLAUDE_SMART_CITATION_LINK_STYLE", raising=False) + + md, registry = context_format.render_inline_compact_with_registry( + project_id="demo", + user_playbooks=[ + {"content": "used rule", "user_playbook_id": 1}, + {"content": "unused rule", "user_playbook_id": 2}, + ], + agent_playbooks=[], + profiles=[], + ) + + assert {entry["id"] for entry in registry} == {"s1-1", "s2-2"} + assert "copy this final marker exactly" not in md + assert "[used rule](http://localhost:3001/rules/s1-1)" not in md + assert "[unused rule](http://localhost:3001/rules/s2-2)" not in md + assert cs_cite.MARKDOWN_EXAMPLE_ONE in md + assert "shown rule URL for each memory you actually used" in md + assert "visible ` | ` separator" in md + + def test_render_inline_compact_with_registry_can_emit_osc8_when_requested( monkeypatch, ) -> None: @@ -313,9 +339,12 @@ def test_render_inline_compact_with_registry_can_emit_osc8_when_requested( profiles=[{"content": "prefers concise answers", "profile_id": "pref"}], ) + assert "\x1b]8;;http://localhost:3001/rules/s1-123\x1b\\" in md assert "\x1b]8;;http://localhost:3001/rules/s1-17\x1b\\" in md assert "\x1b]8;;http://localhost:3001/rules/p1-pref\x1b\\" in md - assert "preserving its hidden OSC 8 terminal link" in md + assert "final marker like" in md + assert "for each memory you actually used" in md + assert "preserve hidden OSC 8 terminal links" in md assert "open: http://localhost:3001/rules/s1-17" not in md assert {entry["id"] for entry in registry} == {"s1-17", "p1-pref"} @@ -414,16 +443,16 @@ def test_render_inline_compact_uses_remote_reflexio_item_pages(monkeypatch) -> N profiles=[{"content": "prefers concise answers", "profile_id": "pref/one"}], ) + assert "use shared flow (title: use shared flow; open: https://www.reflexio.ai/playbooks?agent_playbook_id=42)" in md assert ( - "[use shared flow](https://www.reflexio.ai/playbooks?agent_playbook_id=42)" - ) in md - assert ( - "[use safe git flow](https://www.reflexio.ai/playbooks?" + "use safe git flow (title: use safe git flow; open: https://www.reflexio.ai/playbooks?" "resource=user_playbook&user_playbook_id=17)" ) in md assert ( - "[prefers concise answers](https://www.reflexio.ai/profiles?profile_id=pref%2Fone)" + "prefers concise answers (title: prefers concise answers; open: " + "https://www.reflexio.ai/profiles?profile_id=pref%2Fone)" ) in md + assert "[use shared flow](https://www.reflexio.ai/playbooks?agent_playbook_id=42)" not in md assert "http://localhost:3001/rules/" not in md diff --git a/tests/test_events.py b/tests/test_events.py index e529024..bd0872d 100644 --- a/tests/test_events.py +++ b/tests/test_events.py @@ -8,7 +8,7 @@ from typing import Any import pytest -from claude_smart import state +from claude_smart import cs_cite, state from claude_smart.events import post_tool, session_start, stop, user_prompt # ----------------------------------------------------------------------------- @@ -1061,12 +1061,15 @@ def test_user_prompt_injects_compact_context_for_codex( assert "Run uv sync after pyproject edits: Run uv sync" not in markdown assert "prefers anyio over asyncio" in markdown assert "✨ claude-smart rule applied:" in markdown - assert "copy this final marker exactly with markdown links" in markdown + assert "copy this final marker exactly with markdown links" not in markdown assert ( "✨ claude-smart rule applied: " "[Run uv sync after pyproject edits](http://localhost:3001/rules/s1) | " "[prefers anyio over asyncio](http://localhost:3001/rules/p1)" - ) in markdown + ) not in markdown + assert cs_cite.MARKDOWN_EXAMPLE_ONE in markdown + assert "for each memory you actually used" in markdown + assert "visible ` | ` separator" in markdown assert "\x1b]8;;" not in markdown