( output: string, command: string, )
| 70 | * whitespace-separated token is recorded as `sourceCommand`. |
| 71 | */ |
| 72 | export function extractClaudeCodeHints( |
| 73 | output: string, |
| 74 | command: string, |
| 75 | ): { hints: ClaudeCodeHint[]; stripped: string } { |
| 76 | // Fast path: no tag open sequence → no work, no allocation. |
| 77 | if (!output.includes('<claude-code-hint')) { |
| 78 | return { hints: [], stripped: output } |
| 79 | } |
| 80 | |
| 81 | const sourceCommand = firstCommandToken(command) |
| 82 | const hints: ClaudeCodeHint[] = [] |
| 83 | |
| 84 | const stripped = output.replace(HINT_TAG_RE, rawLine => { |
| 85 | const attrs = parseAttrs(rawLine) |
| 86 | const v = Number(attrs.v) |
| 87 | const type = attrs.type |
| 88 | const value = attrs.value |
| 89 | |
| 90 | if (!SUPPORTED_VERSIONS.has(v)) { |
| 91 | logForDebugging( |
| 92 | `[claudeCodeHints] dropped hint with unsupported v=${attrs.v}`, |
| 93 | ) |
| 94 | return '' |
| 95 | } |
| 96 | if (!type || !SUPPORTED_TYPES.has(type)) { |
| 97 | logForDebugging( |
| 98 | `[claudeCodeHints] dropped hint with unsupported type=${type}`, |
| 99 | ) |
| 100 | return '' |
| 101 | } |
| 102 | if (!value) { |
| 103 | logForDebugging('[claudeCodeHints] dropped hint with empty value') |
| 104 | return '' |
| 105 | } |
| 106 | |
| 107 | hints.push({ v, type: type as ClaudeCodeHintType, value, sourceCommand }) |
| 108 | return '' |
| 109 | }) |
| 110 | |
| 111 | // Dropping a matched line leaves a blank line (the surrounding newlines |
| 112 | // remain). Collapse runs of blank lines introduced by the replace so the |
| 113 | // model-visible output doesn't grow vertical whitespace. |
| 114 | const collapsed = |
| 115 | hints.length > 0 || stripped !== output |
| 116 | ? stripped.replace(/\n{3,}/g, '\n\n') |
| 117 | : stripped |
| 118 | |
| 119 | return { hints, stripped: collapsed } |
| 120 | } |
| 121 | |
| 122 | function parseAttrs(tagBody: string): Record<string, string> { |
| 123 | const attrs: Record<string, string> = {} |
no test coverage detected