From 3fbce9dafbee61771c28230e5e74b50a1dbf4d21 Mon Sep 17 00:00:00 2001 From: Andrew Yim Date: Sun, 24 May 2026 22:33:39 +0900 Subject: [PATCH] fix(notion-writer): paginate clear_page_content to handle >100 blocks notion.blocks.children.list returns at most 100 blocks per call. Without pagination, --replace only cleared the first 100 blocks of a page, leaving the rest behind and producing surprising partial-replace behavior. Loop with next_cursor until has_more is false so the entire page is cleared. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../code/scripts/notion_writer.py | 28 +++++++++++++------ 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/custom-skills/32-notion-writer/code/scripts/notion_writer.py b/custom-skills/32-notion-writer/code/scripts/notion_writer.py index 139102a..e423adf 100644 --- a/custom-skills/32-notion-writer/code/scripts/notion_writer.py +++ b/custom-skills/32-notion-writer/code/scripts/notion_writer.py @@ -671,18 +671,30 @@ def append_to_page(notion: Client, page_id: str, blocks: List[Dict]) -> bool: def clear_page_content(notion: Client, page_id: str) -> bool: - """Clear all content from a page.""" + """Clear all content from a page (paginates through all children).""" try: formatted_id = format_id_with_dashes(page_id) - # Get all child blocks - children = notion.blocks.children.list(block_id=formatted_id) + # Notion's blocks.children.list returns at most 100 blocks per call. + # Paginate via next_cursor so --replace clears the entire page, not + # just the first 100 blocks. + cursor = None + while True: + kwargs = {'block_id': formatted_id, 'page_size': 100} + if cursor: + kwargs['start_cursor'] = cursor + children = notion.blocks.children.list(**kwargs) - # Delete each block (skip already archived blocks) - for block in children.get('results', []): - if block.get('archived'): - continue - notion.blocks.delete(block_id=block['id']) + for block in children.get('results', []): + if block.get('archived'): + continue + notion.blocks.delete(block_id=block['id']) + + if not children.get('has_more'): + break + cursor = children.get('next_cursor') + if not cursor: + break return True except Exception as e: