```
/** Cut a chunked stream into frames at a marker, doubled to escape it. */
export function drainFrames(chunks: string[], marker: string): { frames: string[]; pending: string } {
  if (typeof marker !== "string" || marker.length !== 1) {
    throw new Error("marker must be a single character");
  }
  
  const buffer = chunks.join("");
  let frames: string[] = [];
  let pending: string = "";
  let i = 0;
  let len = buffer.length;

  while (i < len) {
    if (i === len - 1 && marker === buffer[i]) {
      // If the last character is a single marker, it's part of a dangling frame
      pending += marker;
      break;
    }

    const nextChar = buffer[i + 1];
    if (nextChar === marker) {
      // Escaped marker: skip both markers and continue
      i += 2;
    } else if (buffer[i] === marker && marker !== nextChar) {
      // Single marker: end the current frame
      frames.push(buffer.substring(i, i + 1));
      pending = "";
      i += 1;
    } else {
      // Normal character: continue scanning
      i++;
    }
  }

  return { frames, pending };
}
```