```ts
/** 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 = "";
  let i = 0;
  while (i < buffer.length) {
    if (buffer[i] === marker && i + 1 < buffer.length && buffer[i + 1] === marker) {
      // Escaped marker, add to current frame
      frames.push(pending);
      pending = "";
      i += 2; // Skip over the doubled marker
    } else if (buffer[i] === marker) {
      // Lone marker, end current frame
      frames.push(pending);
      pending = "";
      i++; // Move to next character
    } else {
      // Regular character, add to current frame
      pending += buffer[i];
      i++;
    }
  }
  // Add any remaining text as pending
  if (buffer.length > 0) {
    pending += buffer.substring(i);
  }
  return { frames, pending };
}
```