Skill: henryjing96/feishu-folder-summary (version 1.0.0)

--- name: feishu-folder-summary description: Extract summaries from all documents in a Feishu folder. Use when the user needs to recursively scan a Feishu wiki space or drive folder, read all documents and sub-documents, and generate a comprehensive summary report in Markdown format. Triggers on requests like "extract summaries from Feishu folder", "generate document summary report", "recursively scan Feishu documents", or when given a feishu.cn/wiki/ or feishu.cn/drive/ URL. --- # Feishu Folder Summary This skill extracts summaries from all documents in a Feishu folder (wiki or drive), recursively scanning sub-folders and generating a comprehensive Markdown report. ## Overview The skill performs the following operations: 1. Parses the Feishu folder URL to extract space_id and node_token 2. Recursively traverses the folder structure using feishu_wiki API 3. Reads each document's content using feishu_doc API 4. Generates structured summaries for each document 5. Compiles a comprehensive Markdown report with: - Complete directory tree - Document summaries organized by folder - Statistics and status overview - Links to original documents ## Supported URL Formats - **Wiki folders**: `https://{domain}.feishu.cn/wiki/{node_token}` - **Drive folders**: `https://{domain}.feishu.cn/drive/folder/{folder_token}` ## Workflow ### Step 1: Extract Folder Information Parse the provided Feishu URL to identify: - Document type (wiki or drive) - Space ID (for wiki) - Node token or folder token ### Step 2: Recursive Traversal Use `feishu_wiki` API to traverse the folder structure: ``` feishu_wiki action="get" [REDACTED_SECRET]" # Get folder info feishu_wiki action="nodes" space_id="{space_id}" # List child nodes ``` For folders with `has_child: true`, recursively process child nodes. ### Step 3: Document Reading For each document node, read its content: ``` feishu_doc action="read" doc_token="{obj_token}" ``` ### Step 4: Generate Summary Extract from each document: - **Title**: Document title - **Type**: Document or Folder - **Status**: Complete, In Progress, or Empty - **Core Content**: Key points, main topics, important information - **Child Documents**: If folder, list contained documents ### Step 5: Compile Report Generate a Markdown report with: 1. Header (source URL, generation time, document count) 2. Directory tree visualization 3. Hierarchical summaries (by folder level) 4. Statistics table 5. Related links ## Output Format The generated report includes: ```markdown # {Folder Name} Document Summary Report **Source:** {URL} **Generated:** {Timestamp} **Total Documents:** {Count} --- ## Directory Structure {Tree visualization} --- ## Level 1 Summaries ### 1. {Document Name} - **Type:** {docx/folder} - **Status:** {Complete/In Progress/Empty} - **Summary:** {Core content description} ### 2. {Folder Name}/ - **Type:** folder - **Documents:** {Count} - **Summary:** {Folder description} #### 2.1 {Child Document} - **Type:** docx - **Summary:** {Content summary} --- ## Statistics | Category | Count | Status | |----------|-------|--------| | Total | X | - | | Complete | X | ✅ | | In Progress | X | 🚧 | | Empty | X | ⚠️ | --- *Report generated by feishu-folder-summary skill* ``` ## Example Usage **User Request:** > "Extract summaries from https://caz6yhvgk5z.feishu.cn/wiki/BzslwD3Nei1Dggkvin5cV2hDnob" **Skill Execution:** 1. Parse URL → Wiki folder, node_token=BzslwD3Nei1Dggkvin5cV2hDnob 2. Get folder info → space_id=7593876306731732193, title="AI云平台" 3. Recursively traverse → Found 14 level-1 nodes, 30+ child documents 4. Read each document → Extract content and generate summaries 5. Compile report → Generate comprehensive Markdown summary **Output:** - Complete directory tree - Hierarchical summaries for all 44 documents - Status tracking (✅ Complete, 🚧 In Progress, ⚠️ Empty) - Statistics overview ## Key Considerations - **Recursive Depth**: Process all levels of nested folders - **Document Types**: Handle docx (documents) and folder (containers) - **Error Handling**: Continue processing if individual document read fails - **Content Length**: Generate concise but informative summaries - **Status Detection**: Identify empty or placeholder documents - **Token Efficiency**: Summarize long documents appropriately ## API Reference See [references/feishu_api.md](references/feishu_api.md) for detailed API documentation.

path: scripts/summary_generator.py
content: #!/usr/bin/env python3
"""
Feishu Folder Summary Generator
Helper script to generate summary reports from Feishu folders.
"""

import json
import sys
from datetime import datetime
from typing import Dict, List, Any

def generate_report_header(folder_name: str, url: str, total_docs: int) -> str:
    """Generate the report header section."""
    timestamp = datetime.now().strftime("%Y-%m-%d %H:%M")
    return f"""# {folder_name} Document Summary Report

**Source:** {url}  
**Generated:** {timestamp}  
**Total Documents:** {total_docs}

---

"""

def generate_directory_tree(structure: List[Dict], level: int = 0) -> str:
    """Generate a tree visualization of the folder structure."""
    tree = "## Directory Structure\n\n```\n"
    
    def add_node(node: Dict, prefix: str = "", is_last: bool = True):
        connector = "└── " if is_last else "├── "
        tree_line = f"{prefix}{connector}{node['title']}\n"
        nonlocal tree
        tree += tree_line
        
        if 'children' in node and node['children']:
            new_prefix = prefix + ("    " if is_last else "│   ")
            for i, child in enumerate(node['children']):
                add_node(child, new_prefix, i == len(node['children']) - 1)
    
    for i, node in enumerate(structure):
        add_node(node, "", i == len(structure) - 1)
    
    tree += "```\n\n---\n\n"
    return tree

def generate_document_summary(doc: Dict, index: str) -> str:
    """Generate summary for a single document."""
    title = doc.get('title', 'Untitled')
    doc_type = doc.get('type', 'unknown')
    status = doc.get('status', 'unknown')
    summary = doc.get('summary', 'No summary available')
    
    status_emoji = {
        'complete': '✅',
        'in_progress': '🚧',
        'empty': '⚠️',
        'unknown': '❓'
    }.get(status, '❓')
    
    return f"""### {index} {title}
- **Type:** {doc_type}
- **Status:** {status_emoji} {status.replace('_', ' ').title()}
- **Summary:** {summary}

"""

def generate_statistics(stats: Dict) -> str:
    """Generate the statistics table."""
    return f"""## Statistics

| Category | Count | Status |
|----------|-------|--------|
| Total | {stats.get('total', 0)} | - |
| Complete | {stats.get('complete', 0)} | ✅ |
| In Progress | {stats.get('in_progress', 0)} | 🚧 |
| Empty | {stats.get('empty', 0)} | ⚠️ |

---

*Report generated by feishu-folder-summary skill*
"""

def classify_content_status(content: str, block_count: int) -> str:
    """Classify document status based on content."""
    if block_count <= 2 or len(content.strip()) < 50:
        return 'empty'
    
    progress_keywords = ['待补充', '编写中', '开发中', '里程碑', 'TODO', '🚧']
    if any(kw in content for kw in progress_keywords):
        return 'in_progress'
    
    return 'complete'

def extract_key_summary(content: str, title: str) -> str:
    """Extract key summary points from document content."""
    # Remove markdown headers for analysis
    lines = content.split('\n')
    
    # Look for key sections
    summary_points = []
    
    for line in lines[:50]:  # Check first 50 lines
        line = line.strip()
        # Extract headings as key points
        if line.startswith('#') or line.startswith('**'):
            clean_line = line.lstrip('#').lstrip('*').strip()
            if len(clean_line) > 10 and len(clean_line) < 200:
                summary_points.append(clean_line)
        # Extract list items
        elif line.startswith('- ') or line.startswith('* '):
            if len(line) > 10 and len(line) < 150:
                summary_points.append(line[2:])
    
    # Limit summary length
    if summary_points:
        summary = '; '.join(summary_points[:5])
        if len(summary) > 300:
            summary = summary[:300] + '...'
        return summary
    
    # Fallback: use first non-empty paragraph
    for line in lines:
        line = line.strip()
        if line and not line.startswith('#') and len(line) > 20:
            return line[:200] + ('...' if len(line) > 200 else '')
    
    return "Document content available but no clear summary extracted"

if __name__ == '__main__':
    print("Feishu Folder Summary Helper")
    print("This script provides utility functions for generating summary reports.")
    print("Use through the skill interface for full functionality.")


path: references/feishu_api.md
content: # Feishu API Reference

## Wiki API

### Get Wiki Node Info
```
feishu_wiki action="get" [REDACTED_SECRET]"
```

Returns:
- node_token
- space_id
- obj_token (for documents)
- obj_type (docx, sheet, etc.)
- title
- has_child (boolean)
- parent_node_token

### List Child Nodes
```
feishu_wiki action="nodes" space_id="{space_id}" parent_node_token="{parent_token}"
```

Returns array of child nodes with:
- node_token
- obj_token
- obj_type
- title
- has_child

## Document API

### Read Document
```
feishu_doc action="read" doc_token="{obj_token}"
```

Returns:
- title
- content (text/markdown)
- revision_id
- block_count
- block_types

## URL Parsing

### Wiki URL Pattern
```
https://{domain}.feishu.cn/wiki/{node_token}
```

### Drive URL Pattern
```
https://{domain}.feishu.cn/drive/folder/{folder_token}
```

## Error Handling

Common errors:
- `403`: No permission to access document
- `404`: Document not found
- Empty content: Document has no text content


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: clean (LOW)