diff --git a/.claude/skills/text-formatter/SKILL.md b/.claude/skills/text-formatter/SKILL.md
new file mode 100644
index 00000000..d8cb22cc
--- /dev/null
+++ b/.claude/skills/text-formatter/SKILL.md
@@ -0,0 +1,185 @@
+---
+name: text-formatter
+description: Transform and optimize text content with intelligent formatting. Output BBCode + Markdown hybrid format optimized for forums. Triggers on "format text", "text formatter", "排版", "格式化文本", "BBCode".
+allowed-tools: Task, AskUserQuestion, Read, Write, Bash, Glob
+---
+
+# Text Formatter
+
+Transform and optimize text content with intelligent structure analysis. Output format: **BBCode + Markdown hybrid** optimized for forum publishing.
+
+## Architecture Overview
+
+```
+┌─────────────────────────────────────────────────────────────────┐
+│ Text Formatter Architecture (BBCode + MD Mode) │
+├─────────────────────────────────────────────────────────────────┤
+│ │
+│ Phase 1: Input Collection → 接收文本/文件 │
+│ ↓ │
+│ Phase 2: Content Analysis → 分析结构、识别 Callout/Admonition │
+│ ↓ │
+│ Phase 3: Format Transform → 转换为 BBCode+MD 格式 │
+│ ↓ │
+│ Phase 4: Output & Preview → 保存文件 + 预览 │
+│ │
+└─────────────────────────────────────────────────────────────────┘
+```
+
+## Key Design Principles
+
+1. **Single Format Output**: BBCode + Markdown hybrid (forum optimized)
+2. **Pixel-Based Sizing**: size=150/120/100/80 (not 1-7 levels)
+3. **Forum Compatibility**: Only use widely-supported BBCode tags
+4. **Markdown Separators**: Use `---` for horizontal rules (not `[hr]`)
+5. **No Alignment Tags**: `[align]` not supported, avoid usage
+
+---
+
+## Format Specification
+
+### Supported BBCode Tags
+
+| Tag | Usage | Example |
+|-----|-------|---------|
+| `[size=N]` | Font size (pixels) | `[size=120]Title[/size]` |
+| `[color=X]` | Text color | `[color=#2196F3]Blue[/color]` |
+| `[b]` | Bold | `[b]Bold text[/b]` |
+| `[i]` | Italic | `[i]Italic[/i]` |
+| `[quote]` | Quote block | `[quote]Content[/quote]` |
+| `[code]` | Code block | `[code]code[/code]` |
+| `[img]` | Image | `[img]url[/img]` |
+| `[url]` | Link | `[url=link]text[/url]` |
+| `[list]` | List container | `[list][*]item[/list]` |
+
+### Unsupported Tags (Avoid!)
+
+| Tag | Reason | Alternative |
+|-----|--------|-------------|
+| `[align]` | Not rendered | Remove or use default left |
+| `[hr]` | Shows as text | Use Markdown `---` |
+| `
` | HTML not supported | Use BBCode only |
+| `[table]` | Limited support | Use list or code block |
+
+### Size Hierarchy (Pixels)
+
+| Element | Size | Color | Usage |
+|---------|------|-------|-------|
+| **Main Title** | 150 | #2196F3 | Document title |
+| **Section Title** | 120 | #2196F3 | Major sections (## H2) |
+| **Subsection** | 100 | #333 | Sub-sections (### H3) |
+| **Normal Text** | (default) | - | Body content |
+| **Notes/Gray** | 80 | gray | Footnotes, metadata |
+
+### Color Palette
+
+| Color | Hex | Semantic Usage |
+|-------|-----|----------------|
+| **Blue** | #2196F3 | Titles, links, info |
+| **Green** | #4CAF50 | Success, tips, features |
+| **Orange** | #FF9800 | Warnings, caution |
+| **Red** | #F44336 | Errors, danger, important |
+| **Purple** | #9C27B0 | Examples, code |
+| **Gray** | gray | Notes, metadata |
+
+---
+
+## Mandatory Prerequisites
+
+> Read before execution:
+
+| Document | Purpose | Priority |
+|----------|---------|----------|
+| [specs/format-rules.md](specs/format-rules.md) | Format conversion rules | **P0** |
+| [specs/element-mapping.md](specs/element-mapping.md) | Element type mappings | P1 |
+| [specs/callout-types.md](specs/callout-types.md) | Callout/Admonition types | P1 |
+
+---
+
+## Execution Flow
+
+```
+┌────────────────────────────────────────────────────────────────┐
+│ Phase 1: Input Collection │
+│ - Ask: paste text OR file path │
+│ - Output: input-config.json │
+├────────────────────────────────────────────────────────────────┤
+│ Phase 2: Content Analysis │
+│ - Detect structure: headings, lists, code blocks, tables │
+│ - Identify Callouts/Admonitions (>[!type]) │
+│ - Output: analysis.json │
+├────────────────────────────────────────────────────────────────┤
+│ Phase 3: Format Transform │
+│ - Apply BBCode + MD rules from specs/format-rules.md │
+│ - Convert elements with pixel-based sizes │
+│ - Use Markdown --- for separators │
+│ - Output: formatted content │
+├────────────────────────────────────────────────────────────────┤
+│ Phase 4: Output & Preview │
+│ - Save to .bbcode.txt file │
+│ - Display preview │
+│ - Output: final file │
+└────────────────────────────────────────────────────────────────┘
+```
+
+## Callout/Admonition Support
+
+支持 Obsidian 风格的 Callout 语法,转换为 BBCode quote:
+
+```markdown
+> [!NOTE]
+> 这是一个提示信息
+
+> [!WARNING]
+> 这是一个警告信息
+```
+
+转换结果:
+
+```bbcode
+[quote]
+[size=100][color=#2196F3][b]📝 注意[/b][/color][/size]
+
+这是一个提示信息
+[/quote]
+```
+
+| Type | Color | Icon |
+|------|-------|------|
+| NOTE/INFO | #2196F3 | 📝 |
+| TIP/HINT | #4CAF50 | 💡 |
+| SUCCESS | #4CAF50 | ✅ |
+| WARNING/CAUTION | #FF9800 | ⚠️ |
+| DANGER/ERROR | #F44336 | ❌ |
+| EXAMPLE | #9C27B0 | 📋 |
+
+## Directory Setup
+
+```javascript
+const timestamp = new Date().toISOString().slice(0,10).replace(/-/g, '');
+const workDir = `.workflow/.scratchpad/text-formatter-${timestamp}`;
+
+Bash(`mkdir -p "${workDir}"`);
+```
+
+## Output Structure
+
+```
+.workflow/.scratchpad/text-formatter-{date}/
+├── input-config.json # 输入配置
+├── analysis.json # 内容分析结果
+└── output.bbcode.txt # BBCode+MD 输出
+```
+
+## Reference Documents
+
+| Document | Purpose |
+|----------|---------|
+| [phases/01-input-collection.md](phases/01-input-collection.md) | 收集输入内容 |
+| [phases/02-content-analysis.md](phases/02-content-analysis.md) | 分析内容结构 |
+| [phases/03-format-transform.md](phases/03-format-transform.md) | 格式转换 |
+| [phases/04-output-preview.md](phases/04-output-preview.md) | 输出和预览 |
+| [specs/format-rules.md](specs/format-rules.md) | 格式转换规则 |
+| [specs/element-mapping.md](specs/element-mapping.md) | 元素映射表 |
+| [specs/callout-types.md](specs/callout-types.md) | Callout 类型定义 |
+| [templates/bbcode-template.md](templates/bbcode-template.md) | BBCode 模板 |
diff --git a/.claude/skills/text-formatter/phases/01-input-collection.md b/.claude/skills/text-formatter/phases/01-input-collection.md
new file mode 100644
index 00000000..2b48c8da
--- /dev/null
+++ b/.claude/skills/text-formatter/phases/01-input-collection.md
@@ -0,0 +1,111 @@
+# Phase 1: Input Collection
+
+收集用户输入的文本内容。
+
+## Objective
+
+- 获取用户输入内容(直接粘贴或文件路径)
+- 生成输入配置文件
+
+**注意**: 输出格式固定为 BBCode + Markdown 混合格式(论坛优化),无需选择。
+
+## Input
+
+- 来源: 用户交互
+- 配置: 无前置依赖
+
+## Execution Steps
+
+### Step 1: 询问输入方式
+
+```javascript
+const inputMethod = await AskUserQuestion({
+ questions: [
+ {
+ question: "请选择输入方式",
+ header: "输入方式",
+ multiSelect: false,
+ options: [
+ { label: "直接粘贴文本", description: "在对话中粘贴要格式化的内容" },
+ { label: "指定文件路径", description: "读取指定文件的内容" }
+ ]
+ }
+ ]
+});
+```
+
+### Step 2: 获取内容
+
+```javascript
+let content = '';
+
+if (inputMethod["输入方式"] === "直接粘贴文本") {
+ // 提示用户粘贴内容
+ const textInput = await AskUserQuestion({
+ questions: [
+ {
+ question: "请粘贴要格式化的文本内容(粘贴后选择确认)",
+ header: "文本内容",
+ multiSelect: false,
+ options: [
+ { label: "已粘贴完成", description: "确认已在上方粘贴内容" }
+ ]
+ }
+ ]
+ });
+ // 从用户消息中提取文本内容
+ content = extractUserText();
+} else {
+ // 询问文件路径
+ const filePath = await AskUserQuestion({
+ questions: [
+ {
+ question: "请输入文件路径",
+ header: "文件路径",
+ multiSelect: false,
+ options: [
+ { label: "已输入路径", description: "确认路径已在上方输入" }
+ ]
+ }
+ ]
+ });
+ content = Read(extractedFilePath);
+}
+```
+
+### Step 3: 保存配置
+
+```javascript
+const config = {
+ input_method: inputMethod["输入方式"],
+ target_format: "BBCode+MD", // 固定格式
+ original_content: content,
+ timestamp: new Date().toISOString()
+};
+
+Write(`${workDir}/input-config.json`, JSON.stringify(config, null, 2));
+```
+
+## Output
+
+- **File**: `input-config.json`
+- **Format**: JSON
+
+```json
+{
+ "input_method": "直接粘贴文本",
+ "target_format": "BBCode+MD",
+ "original_content": "...",
+ "timestamp": "2026-01-13T..."
+}
+```
+
+## Quality Checklist
+
+- [ ] 成功获取用户输入内容
+- [ ] 内容非空且有效
+- [ ] 配置文件已保存
+
+## Next Phase
+
+→ [Phase 2: Content Analysis](02-content-analysis.md)
diff --git a/.claude/skills/text-formatter/phases/02-content-analysis.md b/.claude/skills/text-formatter/phases/02-content-analysis.md
new file mode 100644
index 00000000..34d86729
--- /dev/null
+++ b/.claude/skills/text-formatter/phases/02-content-analysis.md
@@ -0,0 +1,248 @@
+# Phase 2: Content Analysis
+
+分析输入内容的结构和语义元素。
+
+## Objective
+
+- 识别内容结构(标题、段落、列表等)
+- 检测特殊元素(代码块、表格、链接等)
+- 生成结构化分析结果
+
+## Input
+
+- 依赖: `input-config.json`
+- 配置: `{workDir}/input-config.json`
+
+## Execution Steps
+
+### Step 1: 加载输入
+
+```javascript
+const config = JSON.parse(Read(`${workDir}/input-config.json`));
+const content = config.original_content;
+```
+
+### Step 2: 结构分析
+
+```javascript
+function analyzeStructure(text) {
+ const analysis = {
+ elements: [],
+ stats: {
+ headings: 0,
+ paragraphs: 0,
+ lists: 0,
+ code_blocks: 0,
+ tables: 0,
+ links: 0,
+ images: 0,
+ quotes: 0,
+ callouts: 0
+ }
+ };
+
+ // Callout 检测正则 (Obsidian 风格)
+ const CALLOUT_PATTERN = /^>\s*\[!(\w+)\](?:\s+(.+))?$/;
+
+ const lines = text.split('\n');
+ let currentElement = null;
+ let inCodeBlock = false;
+ let inList = false;
+
+ for (let i = 0; i < lines.length; i++) {
+ const line = lines[i];
+
+ // 检测代码块
+ if (line.match(/^```/)) {
+ inCodeBlock = !inCodeBlock;
+ if (inCodeBlock) {
+ analysis.elements.push({
+ type: 'code_block',
+ start: i,
+ language: line.replace(/^```/, '').trim()
+ });
+ analysis.stats.code_blocks++;
+ }
+ continue;
+ }
+
+ if (inCodeBlock) continue;
+
+ // 检测标题 (Markdown 或纯文本模式)
+ if (line.match(/^#{1,6}\s/)) {
+ const level = line.match(/^(#+)/)[1].length;
+ analysis.elements.push({
+ type: 'heading',
+ level: level,
+ content: line.replace(/^#+\s*/, ''),
+ line: i
+ });
+ analysis.stats.headings++;
+ continue;
+ }
+
+ // 检测列表
+ if (line.match(/^[\s]*[-*+]\s/) || line.match(/^[\s]*\d+\.\s/)) {
+ if (!inList) {
+ analysis.elements.push({
+ type: 'list',
+ start: i,
+ ordered: line.match(/^\d+\./) !== null
+ });
+ analysis.stats.lists++;
+ inList = true;
+ }
+ continue;
+ } else {
+ inList = false;
+ }
+
+ // 检测 Callout (Obsidian 风格) - 优先于普通引用
+ const calloutMatch = line.match(CALLOUT_PATTERN);
+ if (calloutMatch) {
+ const calloutType = calloutMatch[1].toLowerCase();
+ const calloutTitle = calloutMatch[2] || null;
+ // 收集 Callout 内容行
+ const calloutContent = [];
+ let j = i + 1;
+ while (j < lines.length && lines[j].startsWith('>')) {
+ calloutContent.push(lines[j].replace(/^>\s*/, ''));
+ j++;
+ }
+ analysis.elements.push({
+ type: 'callout',
+ calloutType: calloutType,
+ title: calloutTitle,
+ content: calloutContent.join('\n'),
+ start: i,
+ end: j - 1
+ });
+ analysis.stats.callouts++;
+ i = j - 1; // 跳过已处理的行
+ continue;
+ }
+
+ // 检测普通引用
+ if (line.match(/^>\s/)) {
+ analysis.elements.push({
+ type: 'quote',
+ content: line.replace(/^>\s*/, ''),
+ line: i
+ });
+ analysis.stats.quotes++;
+ continue;
+ }
+
+ // 检测表格
+ if (line.match(/^\|.*\|$/)) {
+ analysis.elements.push({
+ type: 'table_row',
+ line: i
+ });
+ if (!analysis.elements.find(e => e.type === 'table')) {
+ analysis.stats.tables++;
+ }
+ continue;
+ }
+
+ // 检测链接
+ const links = line.match(/\[([^\]]+)\]\(([^)]+)\)/g);
+ if (links) {
+ analysis.stats.links += links.length;
+ }
+
+ // 检测图片
+ const images = line.match(/!\[([^\]]*)\]\(([^)]+)\)/g);
+ if (images) {
+ analysis.stats.images += images.length;
+ }
+
+ // 普通段落
+ if (line.trim() && !line.match(/^[-=]{3,}$/)) {
+ analysis.elements.push({
+ type: 'paragraph',
+ line: i,
+ preview: line.substring(0, 50)
+ });
+ analysis.stats.paragraphs++;
+ }
+ }
+
+ return analysis;
+}
+
+const analysis = analyzeStructure(content);
+```
+
+### Step 3: 语义增强
+
+```javascript
+// 识别特殊语义
+function enhanceSemantics(text, analysis) {
+ const enhanced = { ...analysis };
+
+ // 检测关键词强调
+ const boldPatterns = text.match(/\*\*[^*]+\*\*/g) || [];
+ const italicPatterns = text.match(/\*[^*]+\*/g) || [];
+
+ enhanced.semantics = {
+ emphasis: {
+ bold: boldPatterns.length,
+ italic: italicPatterns.length
+ },
+ estimated_reading_time: Math.ceil(text.split(/\s+/).length / 200) // 200 words/min
+ };
+
+ return enhanced;
+}
+
+const enhancedAnalysis = enhanceSemantics(content, analysis);
+```
+
+### Step 4: 保存分析结果
+
+```javascript
+Write(`${workDir}/analysis.json`, JSON.stringify(enhancedAnalysis, null, 2));
+```
+
+## Output
+
+- **File**: `analysis.json`
+- **Format**: JSON
+
+```json
+{
+ "elements": [
+ { "type": "heading", "level": 1, "content": "Title", "line": 0 },
+ { "type": "paragraph", "line": 2, "preview": "..." },
+ { "type": "callout", "calloutType": "warning", "title": "注意事项", "content": "...", "start": 4, "end": 6 },
+ { "type": "code_block", "start": 8, "language": "javascript" }
+ ],
+ "stats": {
+ "headings": 3,
+ "paragraphs": 10,
+ "lists": 2,
+ "code_blocks": 1,
+ "tables": 0,
+ "links": 5,
+ "images": 0,
+ "quotes": 1,
+ "callouts": 2
+ },
+ "semantics": {
+ "emphasis": { "bold": 5, "italic": 3 },
+ "estimated_reading_time": 2
+ }
+}
+```
+
+## Quality Checklist
+
+- [ ] 所有结构元素已识别
+- [ ] 统计信息准确
+- [ ] 语义增强完成
+- [ ] 分析文件已保存
+
+## Next Phase
+
+→ [Phase 3: Format Transform](03-format-transform.md)
diff --git a/.claude/skills/text-formatter/phases/03-format-transform.md b/.claude/skills/text-formatter/phases/03-format-transform.md
new file mode 100644
index 00000000..47b72b8d
--- /dev/null
+++ b/.claude/skills/text-formatter/phases/03-format-transform.md
@@ -0,0 +1,237 @@
+# Phase 3: Format Transform
+
+将内容转换为 BBCode + Markdown 混合格式(论坛优化)。
+
+## Objective
+
+- 根据分析结果转换内容
+- 应用像素级字号规则
+- 处理 Callout/标注语法
+- 生成论坛兼容的输出
+
+## Input
+
+- 依赖: `input-config.json`, `analysis.json`
+- 规范: `specs/format-rules.md`, `specs/element-mapping.md`
+
+## Format Specification
+
+### Size Hierarchy (Pixels)
+
+| Element | Size | Color | Usage |
+|---------|------|-------|-------|
+| **H1** | 150 | #2196F3 | 文档主标题 |
+| **H2** | 120 | #2196F3 | 章节标题 |
+| **H3** | 100 | #333 | 子标题 |
+| **H4+** | (默认) | - | 仅加粗 |
+| **Notes** | 80 | gray | 备注/元数据 |
+
+### Unsupported Tags (禁止使用)
+
+| Tag | Reason | Alternative |
+|-----|--------|-------------|
+| `[align]` | 不渲染 | 删除,使用默认左对齐 |
+| `[hr]` | 显示为文本 | 使用 Markdown `---` |
+| `[table]` | 支持有限 | 转为列表或代码块 |
+| HTML tags | 不支持 | 仅使用 BBCode |
+
+## Execution Steps
+
+### Step 1: 加载配置和分析
+
+```javascript
+const config = JSON.parse(Read(`${workDir}/input-config.json`));
+const analysis = JSON.parse(Read(`${workDir}/analysis.json`));
+const content = config.original_content;
+```
+
+### Step 2: Callout 配置
+
+```javascript
+// Callout 类型映射(像素级字号)
+const CALLOUT_CONFIG = {
+ // 信息类
+ note: { icon: '📝', color: '#2196F3', label: '注意' },
+ info: { icon: 'ℹ️', color: '#2196F3', label: '信息' },
+ abstract: { icon: '📄', color: '#2196F3', label: '摘要' },
+ summary: { icon: '📄', color: '#2196F3', label: '摘要' },
+ tldr: { icon: '📄', color: '#2196F3', label: '摘要' },
+
+ // 成功/提示类
+ tip: { icon: '💡', color: '#4CAF50', label: '提示' },
+ hint: { icon: '💡', color: '#4CAF50', label: '提示' },
+ success: { icon: '✅', color: '#4CAF50', label: '成功' },
+ check: { icon: '✅', color: '#4CAF50', label: '完成' },
+ done: { icon: '✅', color: '#4CAF50', label: '完成' },
+
+ // 警告类
+ warning: { icon: '⚠️', color: '#FF9800', label: '警告' },
+ caution: { icon: '⚠️', color: '#FF9800', label: '注意' },
+ attention: { icon: '⚠️', color: '#FF9800', label: '注意' },
+ question: { icon: '❓', color: '#FF9800', label: '问题' },
+ help: { icon: '❓', color: '#FF9800', label: '帮助' },
+ faq: { icon: '❓', color: '#FF9800', label: 'FAQ' },
+ todo: { icon: '📋', color: '#FF9800', label: '待办' },
+
+ // 错误/危险类
+ danger: { icon: '❌', color: '#F44336', label: '危险' },
+ error: { icon: '❌', color: '#F44336', label: '错误' },
+ bug: { icon: '🐛', color: '#F44336', label: 'Bug' },
+ important: { icon: '⭐', color: '#F44336', label: '重要' },
+
+ // 其他
+ example: { icon: '📋', color: '#9C27B0', label: '示例' },
+ quote: { icon: '💬', color: 'gray', label: '引用' },
+ cite: { icon: '💬', color: 'gray', label: '引用' }
+};
+
+// Callout 检测正则 (支持 +/- 折叠标记)
+const CALLOUT_PATTERN = /^>\s*\[!(\w+)\][+-]?(?:\s+(.+))?$/;
+```
+
+### Step 3: Callout 解析器
+
+```javascript
+function parseCallouts(text) {
+ const lines = text.split('\n');
+ const result = [];
+ let i = 0;
+
+ while (i < lines.length) {
+ const match = lines[i].match(CALLOUT_PATTERN);
+ if (match) {
+ const type = match[1].toLowerCase();
+ const title = match[2] || null;
+ const content = [];
+ i++;
+
+ // 收集 Callout 内容行
+ while (i < lines.length && lines[i].startsWith('>')) {
+ content.push(lines[i].replace(/^>\s*/, ''));
+ i++;
+ }
+
+ result.push({
+ isCallout: true,
+ type,
+ title,
+ content: content.join('\n')
+ });
+ } else {
+ result.push({ isCallout: false, line: lines[i] });
+ i++;
+ }
+ }
+
+ return result;
+}
+```
+
+### Step 4: BBCode+MD 转换器
+
+```javascript
+function formatBBCodeMD(text) {
+ let result = text;
+
+ // ===== 标题转换 (像素级字号) =====
+ result = result.replace(/^######\s*(.+)$/gm, '[b]$1[/b]');
+ result = result.replace(/^#####\s*(.+)$/gm, '[b]$1[/b]');
+ result = result.replace(/^####\s*(.+)$/gm, '[b]$1[/b]');
+ result = result.replace(/^###\s*(.+)$/gm, '[size=100][color=#333][b]$1[/b][/color][/size]');
+ result = result.replace(/^##\s*(.+)$/gm, '[size=120][color=#2196F3][b]$1[/b][/color][/size]');
+ result = result.replace(/^#\s*(.+)$/gm, '[size=150][color=#2196F3][b]$1[/b][/color][/size]');
+
+ // ===== 文本样式 =====
+ result = result.replace(/\*\*\*(.+?)\*\*\*/g, '[b][i]$1[/i][/b]');
+ result = result.replace(/\*\*(.+?)\*\*/g, '[b]$1[/b]');
+ result = result.replace(/\*(.+?)\*/g, '[i]$1[/i]');
+ result = result.replace(/~~(.+?)~~/g, '[s]$1[/s]');
+ result = result.replace(/==(.+?)==/g, '[color=yellow]$1[/color]');
+
+ // ===== 代码 =====
+ result = result.replace(/```(\w*)\n([\s\S]*?)```/g, '[code]$2[/code]');
+ // 行内代码保持原样 (部分论坛不支持 font=monospace)
+
+ // ===== 链接和图片 =====
+ result = result.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '[url=$2]$1[/url]');
+ result = result.replace(/!\[([^\]]*)\]\(([^)]+)\)/g, '[img]$2[/img]');
+
+ // ===== 引用 (非 Callout) =====
+ result = result.replace(/^>\s+(.+)$/gm, '[quote]$1[/quote]');
+
+ // ===== 列表 (使用 • 符号) =====
+ result = result.replace(/^[-*+]\s+(.+)$/gm, '• $1');
+
+ // ===== 分隔线 (保持 Markdown 语法) =====
+ // `---` 在混合格式中通常可用,不转换为 [hr]
+
+ return result.trim();
+}
+```
+
+### Step 5: Callout 转换
+
+```javascript
+function convertCallouts(text) {
+ const parsed = parseCallouts(text);
+
+ return parsed.map(item => {
+ if (item.isCallout) {
+ const cfg = CALLOUT_CONFIG[item.type] || CALLOUT_CONFIG.note;
+ const displayTitle = item.title || cfg.label;
+
+ // 使用 [quote] 包裹,标题使用 size=100
+ return `[quote]
+[size=100][color=${cfg.color}][b]${cfg.icon} ${displayTitle}[/b][/color][/size]
+
+${item.content}
+[/quote]`;
+ }
+ return item.line;
+ }).join('\n');
+}
+```
+
+### Step 6: 执行转换
+
+```javascript
+// 1. 先处理 Callouts
+let formattedContent = convertCallouts(content);
+
+// 2. 再进行通用 BBCode+MD 转换
+formattedContent = formatBBCodeMD(formattedContent);
+
+// 3. 清理多余空行
+formattedContent = formattedContent.replace(/\n{3,}/g, '\n\n');
+```
+
+### Step 7: 保存转换结果
+
+```javascript
+const outputFile = 'output.bbcode.txt';
+Write(`${workDir}/${outputFile}`, formattedContent);
+
+// 更新配置
+config.output_file = outputFile;
+config.formatted_content = formattedContent;
+Write(`${workDir}/input-config.json`, JSON.stringify(config, null, 2));
+```
+
+## Output
+
+- **File**: `output.bbcode.txt`
+- **Format**: BBCode + Markdown 混合格式
+
+## Quality Checklist
+
+- [ ] 标题使用像素值 (150/120/100)
+- [ ] 未使用 `[align]` 标签
+- [ ] 未使用 `[hr]` 标签
+- [ ] 分隔线使用 `---`
+- [ ] Callout 正确转换为 [quote]
+- [ ] 颜色值使用 hex 格式
+- [ ] 内容完整无丢失
+
+## Next Phase
+
+→ [Phase 4: Output & Preview](04-output-preview.md)
diff --git a/.claude/skills/text-formatter/phases/04-output-preview.md b/.claude/skills/text-formatter/phases/04-output-preview.md
new file mode 100644
index 00000000..5a27a43f
--- /dev/null
+++ b/.claude/skills/text-formatter/phases/04-output-preview.md
@@ -0,0 +1,183 @@
+# Phase 4: Output & Preview
+
+输出最终结果并提供预览。
+
+## Objective
+
+- 保存格式化后的内容到文件
+- 提供预览功能
+- 显示转换统计信息
+
+## Input
+
+- 依赖: `input-config.json`, `output.*`
+- 配置: `{workDir}/input-config.json`
+
+## Execution Steps
+
+### Step 1: 加载结果
+
+```javascript
+const config = JSON.parse(Read(`${workDir}/input-config.json`));
+const analysis = JSON.parse(Read(`${workDir}/analysis.json`));
+const outputFile = `${workDir}/${config.output_file}`;
+const formattedContent = Read(outputFile);
+```
+
+### Step 2: 生成统计摘要
+
+```javascript
+const summary = {
+ input: {
+ method: config.input_method,
+ original_length: config.original_content.length,
+ word_count: config.original_content.split(/\s+/).length
+ },
+ output: {
+ format: config.target_format,
+ file: outputFile,
+ length: formattedContent.length
+ },
+ elements: analysis.stats,
+ reading_time: analysis.semantics?.estimated_reading_time || 1
+};
+
+console.log(`
+╔════════════════════════════════════════════════════════════════╗
+║ Text Formatter Summary ║
+╠════════════════════════════════════════════════════════════════╣
+║ Input: ${summary.input.word_count} words (${summary.input.original_length} chars)
+║ Output: ${summary.output.format} → ${summary.output.file}
+║ Elements Converted:
+║ • Headings: ${summary.elements.headings}
+║ • Paragraphs: ${summary.elements.paragraphs}
+║ • Lists: ${summary.elements.lists}
+║ • Code Blocks: ${summary.elements.code_blocks}
+║ • Links: ${summary.elements.links}
+║ Estimated Reading Time: ${summary.reading_time} min
+╚════════════════════════════════════════════════════════════════╝
+`);
+```
+
+### Step 3: HTML 预览(如适用)
+
+```javascript
+if (config.target_format === 'HTML') {
+ // 生成完整 HTML 文件用于预览
+ const previewHtml = `
+
+
+
+
+
Text Formatter Preview
+
+
+
+
+ ${formattedContent}
+
+
+`;
+
+ Write(`${workDir}/preview.html`, previewHtml);
+
+ // 可选:在浏览器中打开预览
+ // Bash(`start "${workDir}/preview.html"`); // Windows
+ // Bash(`open "${workDir}/preview.html"`); // macOS
+}
+```
+
+### Step 4: 显示输出内容
+
+```javascript
+// 显示格式化后的内容
+console.log('\n=== Formatted Content ===\n');
+console.log(formattedContent);
+console.log('\n=========================\n');
+
+// 提示用户
+console.log(`
+📁 Output saved to: ${outputFile}
+${config.target_format === 'HTML' ? '🌐 Preview available: ' + workDir + '/preview.html' : ''}
+
+💡 Tips:
+- Copy the content above for immediate use
+- Or access the saved file at the path shown
+`);
+```
+
+### Step 5: 询问后续操作
+
+```javascript
+const nextAction = await AskUserQuestion({
+ questions: [
+ {
+ question: "需要执行什么操作?",
+ header: "后续操作",
+ multiSelect: false,
+ options: [
+ { label: "完成", description: "结束格式化流程" },
+ { label: "转换为其他格式", description: "选择另一种输出格式" },
+ { label: "重新编辑", description: "修改原始内容后重新格式化" }
+ ]
+ }
+ ]
+});
+
+if (nextAction["后续操作"] === "转换为其他格式") {
+ // 返回 Phase 1 选择新格式
+ console.log('请重新运行 /text-formatter 选择其他格式');
+}
+```
+
+## Output
+
+- **File**: `output.{ext}` (最终输出)
+- **File**: `preview.html` (HTML 预览,仅 HTML 格式)
+- **Console**: 统计摘要和格式化内容
+
+## Final Output Structure
+
+```
+{workDir}/
+├── input-config.json # 配置信息
+├── analysis.json # 分析结果
+├── output.md # Markdown 输出(如选择)
+├── output.bbcode.txt # BBCode 输出(如选择)
+├── output.html # HTML 输出(如选择)
+└── preview.html # HTML 预览页面
+```
+
+## Quality Checklist
+
+- [ ] 输出文件已保存
+- [ ] 统计信息正确显示
+- [ ] 预览功能可用(HTML)
+- [ ] 用户可访问输出内容
+
+## Completion
+
+此为最终阶段,格式化流程完成。
diff --git a/.claude/skills/text-formatter/specs/callout-types.md b/.claude/skills/text-formatter/specs/callout-types.md
new file mode 100644
index 00000000..0647b2a1
--- /dev/null
+++ b/.claude/skills/text-formatter/specs/callout-types.md
@@ -0,0 +1,293 @@
+# Callout Types
+
+Obsidian 风格的 Callout/Admonition 类型定义和转换规则。
+
+## When to Use
+
+| Phase | Usage | Section |
+|-------|-------|---------|
+| Phase 2 | 检测 Callout | Detection patterns |
+| Phase 3 | 格式转换 | Conversion rules |
+
+---
+
+## Callout 语法
+
+### Obsidian 原生语法
+
+```markdown
+> [!TYPE] 可选标题
+> 内容行1
+> 内容行2
+```
+
+### 支持的类型
+
+| Type | Alias | Icon | Color | 用途 |
+|------|-------|------|-------|------|
+| `note` | - | 📝 | blue | 普通提示 |
+| `info` | - | ℹ️ | blue | 信息说明 |
+| `tip` | `hint` | 💡 | green | 技巧提示 |
+| `success` | `check`, `done` | ✅ | green | 成功状态 |
+| `warning` | `caution`, `attention` | ⚠️ | orange | 警告信息 |
+| `danger` | `error` | ❌ | red | 危险/错误 |
+| `bug` | - | 🐛 | red | Bug 说明 |
+| `example` | - | 📋 | purple | 示例内容 |
+| `quote` | `cite` | 💬 | gray | 引用内容 |
+| `abstract` | `summary`, `tldr` | 📄 | cyan | 摘要 |
+| `question` | `help`, `faq` | ❓ | yellow | 问题/FAQ |
+| `todo` | - | 📌 | orange | 待办事项 |
+
+---
+
+## 检测 Pattern
+
+```javascript
+// Callout 检测正则
+const CALLOUT_PATTERN = /^>\s*\[!(\w+)\](?:\s+(.+))?$/;
+
+// 检测函数
+function detectCallout(line) {
+ const match = line.match(CALLOUT_PATTERN);
+ if (match) {
+ return {
+ type: match[1].toLowerCase(),
+ title: match[2] || null
+ };
+ }
+ return null;
+}
+
+// 解析完整 Callout 块
+function parseCalloutBlock(lines, startIndex) {
+ const firstLine = lines[startIndex];
+ const calloutInfo = detectCallout(firstLine);
+
+ if (!calloutInfo) return null;
+
+ const content = [];
+ let i = startIndex + 1;
+
+ while (i < lines.length && lines[i].startsWith('>')) {
+ content.push(lines[i].replace(/^>\s*/, ''));
+ i++;
+ }
+
+ return {
+ ...calloutInfo,
+ content: content.join('\n'),
+ endIndex: i - 1
+ };
+}
+```
+
+---
+
+## 转换规则
+
+### BBCode 转换
+
+```javascript
+const CALLOUT_BBCODE = {
+ note: {
+ icon: '📝',
+ color: '#2196F3',
+ label: '注意'
+ },
+ info: {
+ icon: 'ℹ️',
+ color: '#2196F3',
+ label: '信息'
+ },
+ tip: {
+ icon: '💡',
+ color: '#4CAF50',
+ label: '提示'
+ },
+ success: {
+ icon: '✅',
+ color: '#4CAF50',
+ label: '成功'
+ },
+ warning: {
+ icon: '⚠️',
+ color: '#FF9800',
+ label: '警告'
+ },
+ danger: {
+ icon: '❌',
+ color: '#F44336',
+ label: '危险'
+ },
+ bug: {
+ icon: '🐛',
+ color: '#F44336',
+ label: 'Bug'
+ },
+ example: {
+ icon: '📋',
+ color: '#9C27B0',
+ label: '示例'
+ },
+ quote: {
+ icon: '💬',
+ color: '#9E9E9E',
+ label: '引用'
+ },
+ question: {
+ icon: '❓',
+ color: '#FFEB3B',
+ label: '问题'
+ }
+};
+
+function calloutToBBCode(type, title, content, style = 'forum') {
+ const config = CALLOUT_BBCODE[type] || CALLOUT_BBCODE.note;
+ const displayTitle = title || config.label;
+
+ if (style === 'compact') {
+ return `[quote][b]${config.icon} ${displayTitle}[/b]
+${content}[/quote]`;
+ }
+
+ // Forum style - more visual
+ return `[quote]
+[color=${config.color}][size=4][b]${config.icon} ${displayTitle}[/b][/size][/color]
+
+${content}
+[/quote]`;
+}
+```
+
+### HTML 转换
+
+```javascript
+function calloutToHTML(type, title, content) {
+ const config = CALLOUT_BBCODE[type] || CALLOUT_BBCODE.note;
+ const displayTitle = title || config.label;
+
+ return `
+
+ ${config.icon}
+ ${displayTitle}
+
+
+ ${content}
+
+
`;
+}
+```
+
+### Hybrid 转换
+
+```javascript
+function calloutToHybrid(type, title, content) {
+ const config = CALLOUT_BBCODE[type] || CALLOUT_BBCODE.note;
+ const displayTitle = title || config.label;
+
+ // HTML container + BBCode styling + MD content
+ return `
+
+[color=${config.color}][b]${config.icon} ${displayTitle}[/b][/color]
+
+${content}
+
+
`;
+}
+```
+
+---
+
+## Callout CSS 样式
+
+```css
+/* Base callout styles */
+.callout {
+ padding: 1rem;
+ margin: 1rem 0;
+ border-left: 4px solid;
+ border-radius: 4px;
+ background: #f8f9fa;
+}
+
+.callout-title {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ font-weight: 600;
+ margin-bottom: 0.5rem;
+}
+
+.callout-icon {
+ font-size: 1.2em;
+}
+
+/* Type-specific colors */
+.callout-note, .callout-info {
+ border-color: #2196F3;
+ background: #E3F2FD;
+}
+
+.callout-tip, .callout-success {
+ border-color: #4CAF50;
+ background: #E8F5E9;
+}
+
+.callout-warning {
+ border-color: #FF9800;
+ background: #FFF3E0;
+}
+
+.callout-danger, .callout-bug {
+ border-color: #F44336;
+ background: #FFEBEE;
+}
+
+.callout-example {
+ border-color: #9C27B0;
+ background: #F3E5F5;
+}
+
+.callout-quote {
+ border-color: #9E9E9E;
+ background: #FAFAFA;
+}
+
+.callout-question {
+ border-color: #FFC107;
+ background: #FFFDE7;
+}
+```
+
+---
+
+## 折叠 Callout
+
+支持可折叠的 Callout 语法:
+
+```markdown
+> [!NOTE]+ 默认展开
+> 内容
+
+> [!NOTE]- 默认折叠
+> 内容
+```
+
+### BBCode 折叠
+
+```bbcode
+[collapse=📝 注意]
+内容
+[/collapse]
+```
+
+### HTML 折叠
+
+```html
+
+ 📝 注意
+
+ 内容
+
+
+```
diff --git a/.claude/skills/text-formatter/specs/element-mapping.md b/.claude/skills/text-formatter/specs/element-mapping.md
new file mode 100644
index 00000000..1602454e
--- /dev/null
+++ b/.claude/skills/text-formatter/specs/element-mapping.md
@@ -0,0 +1,209 @@
+# Element Mapping
+
+内容元素到 BBCode + Markdown 混合格式的映射表。
+
+## When to Use
+
+| Phase | Usage | Section |
+|-------|-------|---------|
+| Phase 2 | 元素识别 | Detection patterns |
+| Phase 3 | 格式转换 | Conversion rules |
+
+---
+
+## Element Detection Patterns
+
+### 标题检测
+
+| 类型 | Pattern | 示例 |
+|------|---------|------|
+| ATX 标题 | `/^#{1,6}\s+(.+)$/` | `# Title`, `## Subtitle` |
+| Setext H1 | `/^(.+)\n={3,}$/` | `Title\n====` |
+| Setext H2 | `/^(.+)\n-{3,}$/` | `Subtitle\n----` |
+
+### 列表检测
+
+| 类型 | Pattern | 示例 |
+|------|---------|------|
+| 无序列表 | `/^[\s]*[-*+]\s+(.+)$/` | `- item`, `* item` |
+| 有序列表 | `/^[\s]*\d+\.\s+(.+)$/` | `1. item`, `2. item` |
+| 任务列表 | `/^[\s]*[-*]\s+\[([ x])\]\s+(.+)$/` | `- [ ] todo`, `- [x] done` |
+
+### Callout 检测
+
+| 类型 | Pattern | 示例 |
+|------|---------|------|
+| Callout 开始 | `/^>\s*\[!(\w+)\](?:\s+(.+))?$/` | `> [!NOTE] 标题` |
+| Callout 内容 | `/^>\s*(.*)$/` | `> 内容行` |
+| 可折叠展开 | `/^>\s*\[!(\w+)\]\+/` | `> [!NOTE]+` |
+| 可折叠收起 | `/^>\s*\[!(\w+)\]-/` | `> [!NOTE]-` |
+
+### 代码检测
+
+| 类型 | Pattern | 示例 |
+|------|---------|------|
+| 代码块开始 | `/^```(\w*)$/` | ` ```js ` |
+| 代码块结束 | `/^```$/` | ` ``` ` |
+| 行内代码 | `/`([^`]+)`/` | `` `code` `` |
+
+### 其他元素
+
+| 类型 | Pattern | 示例 |
+|------|---------|------|
+| 链接 | `/\[([^\]]+)\]\(([^)]+)\)/` | `[text](url)` |
+| 图片 | `/!\[([^\]]*)\]\(([^)]+)\)/` | `` |
+| 普通引用 | `/^>\s+(.+)$/` | `> quote` |
+| 分隔线 | `/^[-*_]{3,}$/` | `---`, `***` |
+| 高亮 | `/==(.+?)==/` | `==highlight==` |
+| 粗体 | `/\*\*(.+?)\*\*/` | `**bold**` |
+| 斜体 | `/\*(.+?)\*/` | `*italic*` |
+| 删除线 | `/~~(.+?)~~/` | `~~strike~~` |
+
+---
+
+## Element Conversion Matrix
+
+### 标题映射 (Pixel-Based)
+
+| Element | Markdown | BBCode Output |
+|---------|----------|---------------|
+| **H1** | `# text` | `[size=150][color=#2196F3][b]text[/b][/color][/size]` |
+| **H2** | `## text` | `[size=120][color=#2196F3][b]text[/b][/color][/size]` |
+| **H3** | `### text` | `[size=100][color=#333][b]text[/b][/color][/size]` |
+| **H4** | `#### text` | `[b]text[/b]` |
+| **H5** | `##### text` | `[b]text[/b]` |
+| **H6** | `###### text` | `[b]text[/b]` |
+
+### 文本样式映射
+
+| Element | Markdown | BBCode |
+|---------|----------|--------|
+| **Bold** | `**text**` | `[b]text[/b]` |
+| **Italic** | `*text*` | `[i]text[/i]` |
+| **Bold+Italic** | `***text***` | `[b][i]text[/i][/b]` |
+| **Strike** | `~~text~~` | `[s]text[/s]` |
+| **Highlight** | `==text==` | `[color=yellow]text[/color]` |
+| **Code (inline)** | `` `text` `` | 保持原样 |
+
+### 块级元素映射
+
+| Element | Markdown | BBCode |
+|---------|----------|--------|
+| **Code Block** | ` ```lang\ncode\n``` ` | `[code]code[/code]` |
+| **Quote** | `> text` | `[quote]text[/quote]` |
+| **HR** | `---` | `---` (保持 Markdown) |
+| **List Item** | `- text` | `• text` |
+| **Paragraph** | `text\n\ntext` | `text\n\ntext` |
+
+### 链接和媒体映射
+
+| Element | Markdown | BBCode |
+|---------|----------|--------|
+| **Link** | `[text](url)` | `[url=url]text[/url]` |
+| **Image** | `` | `[img]url[/img]` |
+
+---
+
+## Callout Mapping
+
+### 类型到样式映射
+
+| Callout Type | Color | Icon | Label |
+|--------------|-------|------|-------|
+| note | #2196F3 | 📝 | 注意 |
+| info | #2196F3 | ℹ️ | 信息 |
+| tip | #4CAF50 | 💡 | 提示 |
+| hint | #4CAF50 | 💡 | 提示 |
+| success | #4CAF50 | ✅ | 成功 |
+| check | #4CAF50 | ✅ | 完成 |
+| done | #4CAF50 | ✅ | 完成 |
+| warning | #FF9800 | ⚠️ | 警告 |
+| caution | #FF9800 | ⚠️ | 注意 |
+| attention | #FF9800 | ⚠️ | 注意 |
+| danger | #F44336 | ❌ | 危险 |
+| error | #F44336 | ❌ | 错误 |
+| bug | #F44336 | 🐛 | Bug |
+| example | #9C27B0 | 📋 | 示例 |
+| question | #FF9800 | ❓ | 问题 |
+| help | #FF9800 | ❓ | 帮助 |
+| faq | #FF9800 | ❓ | FAQ |
+| quote | gray | 💬 | 引用 |
+| cite | gray | 💬 | 引用 |
+| abstract | #2196F3 | 📄 | 摘要 |
+| summary | #2196F3 | 📄 | 摘要 |
+| tldr | #2196F3 | 📄 | 摘要 |
+| todo | #FF9800 | 📋 | 待办 |
+| important | #F44336 | ⭐ | 重要 |
+
+### Callout 输出模板
+
+```bbcode
+[quote]
+[size=100][color={color}][b]{icon} {title}[/b][/color][/size]
+
+{content}
+[/quote]
+```
+
+---
+
+## Unsupported Elements
+
+### 不支持转换的元素
+
+| 元素 | 原因 | 降级方案 |
+|------|------|----------|
+| 表格 | BBCode 表格支持有限 | 转为代码块或列表 |
+| 脚注 | 不支持 | 转为括号注释 `(注: ...)` |
+| 数学公式 | 不支持 | 保留原始文本 |
+| 嵌入内容 | 不支持 | 转为链接 |
+| 任务列表 | 复选框不支持 | 转为普通列表 `☐`/`☑` |
+
+### 降级示例
+
+**表格**:
+```
+| A | B |
+|---|---|
+| 1 | 2 |
+
+→ 降级为:
+
+A: 1
+B: 2
+```
+
+**脚注**:
+```
+文本[^1]
+
+[^1]: 脚注内容
+
+→ 降级为:
+
+文本 (注: 脚注内容)
+```
+
+**任务列表**:
+```
+- [ ] 待办
+- [x] 已完成
+
+→ 降级为:
+
+☐ 待办
+☑ 已完成
+```
+
+---
+
+## Validation Rules
+
+### 转换验证
+
+- [ ] 所有 H1-H3 使用像素值 size (150/120/100)
+- [ ] 未使用 `[align]` 标签
+- [ ] 未使用 `[hr]` 标签
+- [ ] 分隔线保持 `---`
+- [ ] Callout 正确识别并转换
+- [ ] 颜色值使用 hex 格式
diff --git a/.claude/skills/text-formatter/specs/format-rules.md b/.claude/skills/text-formatter/specs/format-rules.md
new file mode 100644
index 00000000..9db85f3b
--- /dev/null
+++ b/.claude/skills/text-formatter/specs/format-rules.md
@@ -0,0 +1,260 @@
+# Format Conversion Rules
+
+BBCode + Markdown 混合格式转换规则(论坛优化)。
+
+## When to Use
+
+| Phase | Usage | Section |
+|-------|-------|---------|
+| Phase 3 | 格式转换 | All sections |
+
+---
+
+## Core Principles
+
+### 1. Pixel-Based Sizing
+
+**重要**: 使用像素值而非 1-7 级别
+
+| 元素 | Size (px) | 说明 |
+|------|-----------|------|
+| 主标题 (H1) | 150 | 文档标题 |
+| 章节标题 (H2) | 120 | 主要章节 |
+| 子标题 (H3) | 100 | 子章节 |
+| 正文 | (默认) | 不指定 size |
+| 备注/灰色 | 80 | 脚注、元数据 |
+
+### 2. Supported Tags Only
+
+**支持的 BBCode 标签**:
+- `[size=N]` - 字号(像素值)
+- `[color=X]` - 颜色(hex 或名称)
+- `[b]`, `[i]`, `[s]` - 粗体、斜体、删除线
+- `[quote]` - 引用块
+- `[code]` - 代码块
+- `[url]`, `[img]` - 链接、图片
+- `[list]`, `[*]` - 列表
+
+**禁止使用的标签**:
+- `[align]` - 不渲染,显示为文本
+- `[hr]` - 不渲染,使用 Markdown `---`
+- `[table]` - 支持有限,避免使用
+- HTML 标签 (`
`, `
`) - 不支持
+
+### 3. Markdown as Separator
+
+分隔线使用 Markdown 语法:`---`
+
+---
+
+## Element Conversion Rules
+
+### 标题转换
+
+| Markdown | BBCode Output |
+|----------|---------------|
+| `# H1` | `[size=150][color=#2196F3][b]H1[/b][/color][/size]` |
+| `## H2` | `[size=120][color=#2196F3][b]H2[/b][/color][/size]` |
+| `### H3` | `[size=100][color=#333][b]H3[/b][/color][/size]` |
+| `#### H4+` | `[b]H4[/b]` (不加 size) |
+
+### 文本样式
+
+| Markdown | BBCode |
+|----------|--------|
+| `**bold**` | `[b]bold[/b]` |
+| `*italic*` | `[i]italic[/i]` |
+| `***both***` | `[b][i]both[/i][/b]` |
+| `~~strike~~` | `[s]strike[/s]` |
+| `==highlight==` | `[color=yellow]highlight[/color]` |
+
+### 代码
+
+| Markdown | BBCode |
+|----------|--------|
+| `` `inline` `` | 保持原样或 `[color=#9C27B0]inline[/color]` |
+| ` ```code``` ` | `[code]code[/code]` |
+
+### 链接和图片
+
+| Markdown | BBCode |
+|----------|--------|
+| `[text](url)` | `[url=url]text[/url]` |
+| `` | `[img]url[/img]` |
+
+### 列表
+
+```
+Markdown:
+- item 1
+- item 2
+ - nested
+
+BBCode:
+• item 1
+• item 2
+ • nested
+```
+
+注意:使用 `•` 符号而非 `[list][*]`,因为部分论坛渲染有问题。
+
+### 引用
+
+```
+Markdown:
+> quote text
+
+BBCode:
+[quote]
+quote text
+[/quote]
+```
+
+---
+
+## Callout (标注) 转换
+
+### Obsidian Callout 语法
+
+```markdown
+> [!TYPE] 可选标题
+> 内容行 1
+> 内容行 2
+```
+
+### 支持的 Callout 类型
+
+| Type | Color | Icon | 中文标签 |
+|------|-------|------|----------|
+| note, info | #2196F3 | 📝 | 注意 / 信息 |
+| tip, hint | #4CAF50 | 💡 | 提示 |
+| success, check, done | #4CAF50 | ✅ | 成功 |
+| warning, caution, attention | #FF9800 | ⚠️ | 警告 |
+| danger, error, bug | #F44336 | ❌ | 危险 / 错误 |
+| example | #9C27B0 | 📋 | 示例 |
+| question, help, faq | #FF9800 | ❓ | 问题 |
+| quote, cite | gray | 💬 | 引用 |
+| abstract, summary, tldr | #2196F3 | 📄 | 摘要 |
+
+### Callout 转换模板
+
+```bbcode
+[quote]
+[size=100][color={color}][b]{icon} {title}[/b][/color][/size]
+
+{content}
+[/quote]
+```
+
+**示例**:
+
+```markdown
+> [!WARNING] 注意事项
+> 这是警告内容
+```
+
+转换为:
+
+```bbcode
+[quote]
+[size=100][color=#FF9800][b]⚠️ 注意事项[/b][/color][/size]
+
+这是警告内容
+[/quote]
+```
+
+### 可折叠 Callout
+
+Obsidian 支持 `> [!NOTE]+` (展开) 和 `> [!NOTE]-` (折叠)。
+
+由于 BBCode 不支持折叠,统一转换为普通 quote。
+
+---
+
+## Color Palette
+
+### 语义颜色
+
+| 语义 | Hex | 使用场景 |
+|------|-----|----------|
+| Primary | #2196F3 | 标题、链接、信息 |
+| Success | #4CAF50 | 成功、提示、特性 |
+| Warning | #FF9800 | 警告、注意 |
+| Error | #F44336 | 错误、危险 |
+| Purple | #9C27B0 | 示例、代码 |
+| Gray | gray | 备注、元数据 |
+| Dark | #333 | 子标题 |
+
+### 颜色使用规则
+
+1. **标题颜色**: H1/H2 使用 #2196F3,H3 使用 #333
+2. **Callout 颜色**: 根据类型使用语义颜色
+3. **备注颜色**: 使用 gray
+4. **强调颜色**: 根据语义选择(成功用绿色,警告用橙色)
+
+---
+
+## Spacing Rules
+
+### 空行控制
+
+| 元素 | 前空行 | 后空行 |
+|------|--------|--------|
+| 标题 | 1 | 1 |
+| 段落 | 0 | 1 |
+| 列表 | 0 | 1 |
+| 代码块 | 1 | 1 |
+| Callout | 1 | 1 |
+| 分隔线 `---` | 1 | 1 |
+
+### 示例输出结构
+
+```bbcode
+[size=150][color=#2196F3][b]文档标题[/b][/color][/size]
+
+[size=80][color=gray]作者 | 日期[/color][/size]
+
+---
+
+[size=120][color=#2196F3][b]第一章节[/b][/color][/size]
+
+正文内容...
+
+[quote]
+[size=100][color=#4CAF50][b]💡 提示[/b][/color][/size]
+
+提示内容
+[/quote]
+
+---
+
+[size=120][color=#2196F3][b]第二章节[/b][/color][/size]
+
+更多内容...
+
+---
+
+[size=80][color=gray]— 全文完 —[/color][/size]
+```
+
+---
+
+## Quality Checklist
+
+### 转换完整性
+
+- [ ] 所有标题使用像素值 size
+- [ ] 未使用 `[align]` 或 `[hr]`
+- [ ] 分隔线使用 `---`
+- [ ] Callout 正确转换为 quote
+- [ ] 颜色符合语义规范
+- [ ] 空行控制正确
+
+### 常见错误
+
+| 错误 | 正确做法 |
+|------|----------|
+| `[size=5]` | `[size=120]` |
+| `[align=center]` | 删除,默认左对齐 |
+| `[hr]` | 使用 `---` |
+| `` | 删除 HTML 标签 |
diff --git a/.claude/skills/text-formatter/templates/bbcode-template.md b/.claude/skills/text-formatter/templates/bbcode-template.md
new file mode 100644
index 00000000..d854af5e
--- /dev/null
+++ b/.claude/skills/text-formatter/templates/bbcode-template.md
@@ -0,0 +1,350 @@
+# BBCode Template
+
+论坛优化的 BBCode + Markdown 混合模板(像素级字号)。
+
+## 核心规则
+
+### 字号体系 (Pixels)
+
+| 元素 | Size | 说明 |
+|------|------|------|
+| 主标题 | 150 | 文档标题 |
+| 章节标题 | 120 | H2 级别 |
+| 子标题 | 100 | H3 级别 |
+| 正文 | (默认) | 不指定 |
+| 备注 | 80 | 灰色小字 |
+
+### 禁止使用
+
+- `[align]` - 不渲染
+- `[hr]` - 不渲染,用 `---`
+- `[table]` - 支持有限
+- HTML 标签
+
+---
+
+## 文档模板
+
+### 基础文档结构
+
+```bbcode
+[size=150][color=#2196F3][b]{{title}}[/b][/color][/size]
+
+[size=80][color=gray]{{metadata}}[/color][/size]
+
+---
+
+{{introduction}}
+
+---
+
+[size=120][color=#2196F3][b]{{section1_title}}[/b][/color][/size]
+
+{{section1_content}}
+
+---
+
+[size=120][color=#2196F3][b]{{section2_title}}[/b][/color][/size]
+
+{{section2_content}}
+
+---
+
+[size=80][color=gray]— 全文完 —[/color][/size]
+```
+
+### 带目录的文档
+
+```bbcode
+[size=150][color=#2196F3][b]{{title}}[/b][/color][/size]
+
+[size=80][color=gray]{{author}} | {{date}}[/color][/size]
+
+---
+
+[size=100][b]📋 目录[/b][/size]
+
+• {{section1_title}}
+• {{section2_title}}
+• {{section3_title}}
+
+---
+
+[size=120][color=#2196F3][b]{{section1_title}}[/b][/color][/size]
+
+{{section1_content}}
+
+---
+
+[size=120][color=#2196F3][b]{{section2_title}}[/b][/color][/size]
+
+{{section2_content}}
+
+---
+
+[size=120][color=#2196F3][b]{{section3_title}}[/b][/color][/size]
+
+{{section3_content}}
+
+---
+
+[size=80][color=gray]— 全文完 —[/color][/size]
+```
+
+---
+
+## Callout 模板
+
+### 提示 (Note/Info)
+
+```bbcode
+[quote]
+[size=100][color=#2196F3][b]📝 {{title}}[/b][/color][/size]
+
+{{content}}
+[/quote]
+```
+
+### 技巧 (Tip/Hint)
+
+```bbcode
+[quote]
+[size=100][color=#4CAF50][b]💡 {{title}}[/b][/color][/size]
+
+{{content}}
+[/quote]
+```
+
+### 成功 (Success)
+
+```bbcode
+[quote]
+[size=100][color=#4CAF50][b]✅ {{title}}[/b][/color][/size]
+
+{{content}}
+[/quote]
+```
+
+### 警告 (Warning/Caution)
+
+```bbcode
+[quote]
+[size=100][color=#FF9800][b]⚠️ {{title}}[/b][/color][/size]
+
+{{content}}
+[/quote]
+```
+
+### 危险/错误 (Danger/Error)
+
+```bbcode
+[quote]
+[size=100][color=#F44336][b]❌ {{title}}[/b][/color][/size]
+
+{{content}}
+[/quote]
+```
+
+### 示例 (Example)
+
+```bbcode
+[quote]
+[size=100][color=#9C27B0][b]📋 {{title}}[/b][/color][/size]
+
+{{content}}
+[/quote]
+```
+
+### 问题 (Question/FAQ)
+
+```bbcode
+[quote]
+[size=100][color=#FF9800][b]❓ {{title}}[/b][/color][/size]
+
+{{content}}
+[/quote]
+```
+
+### 重要 (Important)
+
+```bbcode
+[quote]
+[size=100][color=#F44336][b]⭐ {{title}}[/b][/color][/size]
+
+{{content}}
+[/quote]
+```
+
+---
+
+## 代码展示模板
+
+### 单代码块
+
+```bbcode
+[size=100][color=#9C27B0][b]代码示例[/b][/color][/size]
+
+[code]
+{{code}}
+[/code]
+
+[size=80][color=gray]说明: {{description}}[/color][/size]
+```
+
+### 带标题的代码
+
+```bbcode
+[size=100][b]{{code_title}}[/b][/size]
+
+[code]
+{{code}}
+[/code]
+```
+
+---
+
+## 特性展示模板
+
+### 特性列表
+
+```bbcode
+[size=120][color=#2196F3][b]功能特性[/b][/color][/size]
+
+• [color=#4CAF50][b]✨ {{feature1}}[/b][/color] — {{desc1}}
+• [color=#2196F3][b]🚀 {{feature2}}[/b][/color] — {{desc2}}
+• [color=#FF9800][b]⚡ {{feature3}}[/b][/color] — {{desc3}}
+```
+
+### 详细特性卡片
+
+```bbcode
+[size=120][color=#2196F3][b]功能特性[/b][/color][/size]
+
+[quote]
+[size=100][color=#4CAF50][b]✨ {{feature1_title}}[/b][/color][/size]
+
+{{feature1_description}}
+
+[size=80][color=gray]适用场景: {{feature1_use_case}}[/color][/size]
+[/quote]
+
+[quote]
+[size=100][color=#2196F3][b]🚀 {{feature2_title}}[/b][/color][/size]
+
+{{feature2_description}}
+
+[size=80][color=gray]适用场景: {{feature2_use_case}}[/color][/size]
+[/quote]
+```
+
+---
+
+## 步骤指南模板
+
+```bbcode
+[size=120][color=#2196F3][b]操作步骤[/b][/color][/size]
+
+[size=100][color=#2196F3][b]步骤 1: {{step1_title}}[/b][/color][/size]
+
+{{step1_content}}
+
+[quote]
+[size=100][color=#FF9800][b]💡 提示[/b][/color][/size]
+
+{{step1_tip}}
+[/quote]
+
+[size=100][color=#2196F3][b]步骤 2: {{step2_title}}[/b][/color][/size]
+
+{{step2_content}}
+
+[size=100][color=#2196F3][b]步骤 3: {{step3_title}}[/b][/color][/size]
+
+{{step3_content}}
+
+---
+
+[color=#4CAF50][b]✅ 完成![/b][/color] {{completion_message}}
+```
+
+---
+
+## 版本更新模板
+
+```bbcode
+[size=150][color=#673AB7][b]🎉 版本 {{version}} 更新日志[/b][/color][/size]
+
+---
+
+[size=120][color=#4CAF50][b]✨ 新功能[/b][/color][/size]
+
+• [b]{{new_feature1}}[/b]: {{new_feature1_desc}}
+• [b]{{new_feature2}}[/b]: {{new_feature2_desc}}
+
+[size=120][color=#2196F3][b]🔧 改进[/b][/color][/size]
+
+• {{improvement1}}
+• {{improvement2}}
+
+[size=120][color=#F44336][b]🐛 修复[/b][/color][/size]
+
+• {{bugfix1}}
+• {{bugfix2}}
+
+---
+
+[url={{download_url}}][b]📥 立即下载[/b][/url]
+```
+
+---
+
+## FAQ 模板
+
+```bbcode
+[size=120][color=#2196F3][b]❓ 常见问题[/b][/color][/size]
+
+---
+
+[size=100][color=#333][b]Q: {{question1}}[/b][/color][/size]
+
+[b]A:[/b] {{answer1}}
+
+---
+
+[size=100][color=#333][b]Q: {{question2}}[/b][/color][/size]
+
+[b]A:[/b] {{answer2}}
+
+---
+
+[size=100][color=#333][b]Q: {{question3}}[/b][/color][/size]
+
+[b]A:[/b] {{answer3}}
+```
+
+---
+
+## 转换检查清单
+
+### 必须检查
+
+- [ ] 标题使用像素值 (150/120/100)
+- [ ] 分隔线使用 `---`
+- [ ] 未使用 `[align]`
+- [ ] 未使用 `[hr]`
+- [ ] 未使用 HTML 标签
+- [ ] Callout 标题 size=100
+- [ ] 灰色备注 size=80
+
+### 颜色规范
+
+| 用途 | 颜色 |
+|------|------|
+| 主标题 | #2196F3 |
+| 章节标题 | #2196F3 |
+| 子标题 | #333 |
+| 成功/提示 | #4CAF50 |
+| 警告 | #FF9800 |
+| 错误/危险 | #F44336 |
+| 示例 | #9C27B0 |
+| 备注 | gray |