| 145 | let sentAny = false; |
| 146 | |
| 147 | const tryUnlock = (): boolean => { |
| 148 | if (unlocked) return true; |
| 149 | |
| 150 | const preview = transform(rawText); |
| 151 | if (!preview.trim()) return false; |
| 152 | |
| 153 | const hasBoundary = STREAM_START_BOUNDARY_RE.test(preview); |
| 154 | const enoughChars = preview.length >= warmupChars; |
| 155 | if (!hasBoundary && !enoughChars) { |
| 156 | return false; |
| 157 | } |
| 158 | |
| 159 | if (isBlockedPrefix(preview.trim())) { |
| 160 | return false; |
| 161 | } |
| 162 | |
| 163 | // ★ HTML 内容有效性检查:防止 <br>、</s>、 等纯 HTML token 连续重复时提前 unlock |
| 164 | // 超过 guardChars(256)后强制放行,此时 cursor-client 的 htmlRepeatAborted 早已触发重试 |
| 165 | if (preview.length < guardChars) { |
| 166 | const noSpace = preview.replace(/\s/g, ''); |
| 167 | const stripped = noSpace.replace(HTML_TOKEN_STRIP_RE, ''); |
| 168 | const ratio = noSpace.length === 0 ? 0 : stripped.length / noSpace.length; |
| 169 | if (ratio < HTML_VALID_RATIO_MIN) { |
| 170 | return false; |
| 171 | } |
| 172 | } |
| 173 | |
| 174 | unlocked = true; |
| 175 | return true; |
| 176 | }; |
| 177 | |
| 178 | const emitFromRawLength = (rawLength: number): string => { |
| 179 | const transformed = transform(rawText.slice(0, rawLength)); |