- handle.go: stream writer emits a blank-line heartbeat every 25s while
the business sends nothing; invisible to NDJSON parsers but resets
NAT/CDN idle timers (mobile CGNAT ~60s, Bunny ~120s)
- template_ts.go: split stream() into retry loop + streamOnce()
- dto accepts a factory re-evaluated per attempt (cursor resume)
- retry only on transport failures (status 4/5); opt-in via
StreamOptions.retry, exponential backoff with jitter, abortable
- idle watchdog (idleTimeoutMs) built on AbortSignal.timeout; no
setTimeout in generated code (simplicity gate)
- docs: README.zh.md version table for v1.3.6