From 3980a008b3f3e5f708f3c2a06e6a58df1fe94ec3 Mon Sep 17 00:00:00 2001 From: Austin Traver Date: Tue, 14 Jul 2026 12:48:07 +0800 Subject: [PATCH] fix(mcp): harden code-rationale git-grep for macOS and color configs grep_comment_candidates() shells out to `git grep -E` and parses the output. The invocation was fragile in two environment-dependent ways, both invisible on Linux CI: 1. The pattern anchored on `\s`, a GNU regex extension. macOS/BSD git's ERE engine does not honor it, so `^\s*(#|//|--|\*)...` matched nothing and the function returned an empty list, silently disabling concept-anchoring on macOS. 2. The command did not pass `--no-color`, so a user with `color.ui=always` got ANSI escapes wrapping every path (`\x1b[35m...enrichment.py\x1b[m`), which the `line.split(":")[0]` path parse then captured verbatim. Use the POSIX class `[[:space:]]` (portable across BSD/macOS and GNU/Linux) and pass `--no-color` so parsed output is stable regardless of git config. The two existing tests already covered this behavior but failed only off Linux; both now pass on macOS. --- .../repowise/server/mcp_server/_code_rationale.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/server/src/repowise/server/mcp_server/_code_rationale.py b/packages/server/src/repowise/server/mcp_server/_code_rationale.py index 971ce0a9c..7df2e0e31 100644 --- a/packages/server/src/repowise/server/mcp_server/_code_rationale.py +++ b/packages/server/src/repowise/server/mcp_server/_code_rationale.py @@ -366,10 +366,14 @@ def grep_comment_candidates( noun_alt = "|".join(re.escape(n) for n in nouns) anchor_alt = "|".join(re.escape(a) for a in anchors) # A comment-leading line containing an anchor AND a content noun, in either - # order. ``git grep`` keeps the scan inside tracked files only. + # order. ``git grep`` keeps the scan inside tracked files only. Use the + # POSIX class ``[[:space:]]`` instead of ``\s``: ``\s`` is a GNU regex + # extension that git's ERE engine does not honor on macOS/BSD, so the + # pattern would silently match nothing there (and concept-anchoring would + # quietly disable itself). pat = ( - rf"^\s*(#|//|--|\*).*({anchor_alt}).*({noun_alt})" - rf"|^\s*(#|//|--|\*).*({noun_alt}).*({anchor_alt})" + rf"^[[:space:]]*(#|//|--|\*).*({anchor_alt}).*({noun_alt})" + rf"|^[[:space:]]*(#|//|--|\*).*({noun_alt}).*({anchor_alt})" ) try: proc = subprocess.run( @@ -382,6 +386,10 @@ def grep_comment_candidates( "git", "--no-pager", "grep", + # --no-color: this output is parsed, so a user's + # ``color.ui=always`` git config must not wrap paths in ANSI + # escapes (which would corrupt the path split below). + "--no-color", "-n", "-I", "-i",