Skip to content

Commit 74d74c8

Browse files
committed
Fix hunk anchor link generation
1 parent bb8a8d3 commit 74d74c8

1 file changed

Lines changed: 27 additions & 5 deletions

File tree

  • plugins/mcp-spec/skills/spec-render/scripts

plugins/mcp-spec/skills/spec-render/scripts/render.py

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -103,12 +103,27 @@ def make_hunk_id(file_index: int, hunk_index: int) -> str:
103103
return f"hunk-{file_index}-{hunk_index}"
104104

105105

106+
def _normalize_hunk_header(header: str) -> str:
107+
"""Extract just the @@ ... @@ numeric portion, stripping trailing context."""
108+
m = re.match(r'(@@\s*[^@]+@@)', header)
109+
return m.group(1).rstrip() if m else header.strip()
110+
111+
106112
def build_hunk_id_map(files: list) -> dict:
107-
"""Build a map from (file, hunk_header) -> hunk DOM id."""
113+
"""Build a map from (file, hunk_header) -> hunk DOM id.
114+
115+
Indexes both the full header and the normalized (numbers-only) form
116+
so that annotation hunks missing the trailing context line still match.
117+
"""
108118
result = {}
109119
for fi, f in enumerate(files):
110120
for hi, h in enumerate(f["hunks"]):
111-
result[(f["file"], h["hunk_header"])] = make_hunk_id(fi, hi)
121+
hid = make_hunk_id(fi, hi)
122+
full_header = h["hunk_header"]
123+
result[(f["file"], full_header)] = hid
124+
norm = _normalize_hunk_header(full_header)
125+
if norm != full_header:
126+
result[(f["file"], norm)] = hid
112127
return result
113128

114129

@@ -127,10 +142,17 @@ def build_annotation_cards(ann_dict: dict, hunk_id_map: dict, req_lookup: dict,
127142
continue
128143

129144
hunk_ids = []
145+
hunk_labels = []
130146
for h in ann.get("hunks", []):
131147
key = (h["file"], h["hunk_header"])
132-
if key in hunk_id_map:
133-
hunk_ids.append(hunk_id_map[key])
148+
hid = hunk_id_map.get(key)
149+
if hid is None:
150+
# Try normalized header (strip trailing context after @@)
151+
norm_key = (h["file"], _normalize_hunk_header(h["hunk_header"]))
152+
hid = hunk_id_map.get(norm_key)
153+
if hid is not None:
154+
hunk_ids.append(hid)
155+
hunk_labels.append(f"{h['file']}:{h['hunk_header'][:40]}")
134156

135157
req = req_lookup.get(req_id, {})
136158
fmt = format_annotation_text(
@@ -146,7 +168,7 @@ def build_annotation_cards(ann_dict: dict, hunk_id_map: dict, req_lookup: dict,
146168
"has_detail": fmt["has_detail"],
147169
"hunk_ids": hunk_ids,
148170
"hunk_ids_json": json.dumps(hunk_ids),
149-
"hunk_labels": [f"{h['file']}:{h['hunk_header'][:40]}" for h in ann.get("hunks", [])],
171+
"hunk_labels": hunk_labels,
150172
})
151173

152174
return cards

0 commit comments

Comments
 (0)