(head: string)
| 133 | * Truncates to 200 chars. |
| 134 | */ |
| 135 | export function extractFirstPromptFromHead(head: string): string { |
| 136 | let start = 0 |
| 137 | let commandFallback = '' |
| 138 | while (start < head.length) { |
| 139 | const newlineIdx = head.indexOf('\n', start) |
| 140 | const line = |
| 141 | newlineIdx >= 0 ? head.slice(start, newlineIdx) : head.slice(start) |
| 142 | start = newlineIdx >= 0 ? newlineIdx + 1 : head.length |
| 143 | |
| 144 | if (!line.includes('"type":"user"') && !line.includes('"type": "user"')) |
| 145 | continue |
| 146 | if (line.includes('"tool_result"')) continue |
| 147 | if (line.includes('"isMeta":true') || line.includes('"isMeta": true')) |
| 148 | continue |
| 149 | if ( |
| 150 | line.includes('"isCompactSummary":true') || |
| 151 | line.includes('"isCompactSummary": true') |
| 152 | ) |
| 153 | continue |
| 154 | |
| 155 | try { |
| 156 | const entry = JSON.parse(line) as Record<string, unknown> |
| 157 | if (entry.type !== 'user') continue |
| 158 | |
| 159 | const message = entry.message as Record<string, unknown> | undefined |
| 160 | if (!message) continue |
| 161 | |
| 162 | const content = message.content |
| 163 | const texts: string[] = [] |
| 164 | if (typeof content === 'string') { |
| 165 | texts.push(content) |
| 166 | } else if (Array.isArray(content)) { |
| 167 | for (const block of content as Record<string, unknown>[]) { |
| 168 | if (block.type === 'text' && typeof block.text === 'string') { |
| 169 | texts.push(block.text as string) |
| 170 | } |
| 171 | } |
| 172 | } |
| 173 | |
| 174 | for (const raw of texts) { |
| 175 | let result = raw.replace(/\n/g, ' ').trim() |
| 176 | if (!result) continue |
| 177 | |
| 178 | // Skip slash-command messages but remember first as fallback |
| 179 | const cmdMatch = COMMAND_NAME_RE.exec(result) |
| 180 | if (cmdMatch) { |
| 181 | if (!commandFallback) commandFallback = cmdMatch[1]! |
| 182 | continue |
| 183 | } |
| 184 | |
| 185 | // Format bash input with ! prefix before the generic XML skip |
| 186 | const bashMatch = /<bash-input>([\s\S]*?)<\/bash-input>/.exec(result) |
| 187 | if (bashMatch) return `! ${bashMatch[1]!.trim()}` |
| 188 | |
| 189 | if (SKIP_FIRST_PROMPT_PATTERN.test(result)) continue |
| 190 | |
| 191 | if (result.length > 200) { |
| 192 | result = result.slice(0, 200).trim() + '\u2026' |
no test coverage detected