* Returns a sorted list of [start, end) offset ranges (in normalized text) that * sit inside a tool-attributed fenced code block. Credential findings inside * these ranges degrade to WARN (unless the doc-example heuristic says the span * is live-format and must still block).
(normalized: string)
| 186 | * is live-format and must still block). |
| 187 | */ |
| 188 | function toolFenceRanges(normalized: string): Array<[number, number]> { |
| 189 | const ranges: Array<[number, number]> = []; |
| 190 | const lines = normalized.split("\n"); |
| 191 | let offset = 0; |
| 192 | let inFence = false; |
| 193 | let fenceStart = 0; |
| 194 | for (const ln of lines) { |
| 195 | const isFenceMarker = ln.startsWith("```"); |
| 196 | if (isFenceMarker) { |
| 197 | if (!inFence && TOOL_FENCE_INFO.test(ln)) { |
| 198 | inFence = true; |
| 199 | fenceStart = offset + ln.length + 1; // content starts after this line |
| 200 | } else if (inFence) { |
| 201 | ranges.push([fenceStart, offset]); // up to start of closing fence |
| 202 | inFence = false; |
| 203 | } |
| 204 | } |
| 205 | offset += ln.length + 1; // +1 for the \n |
| 206 | } |
| 207 | if (inFence) ranges.push([fenceStart, normalized.length]); // unterminated → still degrade its own body |
| 208 | return ranges; |
| 209 | } |
| 210 | |
| 211 | function inRanges(offset: number, ranges: Array<[number, number]>): boolean { |
| 212 | for (const [s, e] of ranges) if (offset >= s && offset < e) return true; |