Skill: mcxxtyhd/theo-confluence-reader (version 1.0.1)

--- name: theo-confluence-reader description: | 读取Confluence需求文档并整理成指定格式。采集原则是"忠实记录"，而非"需求分析"。输出包括：{序号}_{标题}.md（每个页面一个Markdown文件）、requirement-meta.md（元信息）、images/（所有图片，文件中包含图片引用）。 --- # Theo Confluence Reader ## 全局配置 ```powershell # Confluence 配置（根据实际环境修改） $confluenceBaseUrl = "https://confluence.xxx.com" $outputDir = "C:\Users\xxx\.openclaw\workspace\output" $workspaceDir = "C:\Users\xxx\.openclaw\workspace" $maxSize = 1GB $warnThreshold = 0.8 ``` ## 核心原则 **这个skill的职责是"忠实采集"，不是"需求分析"** - 只做格式转换（HTML → MD），不做内容删减、概括或精简 - 保留原文的所有细节，包括表格、列表、备注、批注等 - 不要对原文做任何主观判断、删除或重组 ## 执行规则（强制） **⚠️ 必须抓取所有页面，不允许部分抓取或偷懒** ### 默认行为 1. **自动抓取全部**：给定一个Confluence页面链接后，必须抓取该页面**及其所有子页面**的全部内容 2. **不允许只抓索引**：不能只抓父页面或索引页就停下来，必须深入到每个叶子节点 3. **不允许跳过**：不能因为"内容太多"或"时间太长"而跳过某些页面 ### 唯一例外：确认模式（仅允许询问一次） 如果预估采集时间超过5分钟或页面数量超过10个，可以先整理大纲并预估资源，返回给用户确认。 **但必须遵守以下规则**： - **只能询问一次**：确认后必须执行完整，不能再次询问 - **大纲必须包含**： - 所有待抓取页面的完整列表 - 预估页面数量 - 预估时间和资源消耗 - **确认后必须执行**：用户确认后，立即开始抓取所有页面，中途不能停止或询问 - **禁止多次询问**：一旦用户确认后，不能以任何理由再次询问是否继续 ### 示例 **错误做法（禁止）**： - 只抓父页面索引，给用户后说"详细内容需要再抓" - 抓了一部分后说"太多了要不要继续" - 用户确认后 又问"这个子页面要不要抓" **正确做法**： - 要么直接全部抓完 - 要么先给大纲确认，**确认后全部抓完** ## 存储上限 **output/ 目录总大小上限：1GB** - 每次创建新目录前检查总大小 - 超过 80%（800MB）时：自动删除最早的目录 - 超过 100%（1GB）时：强制删除最早的目录直到低于 80% **检查并清理脚本**： ```powershell $outputDir = "C:\Users\xxx\.openclaw\workspace\output" $workspaceDir = "C:\Users\xxx\.openclaw\workspace" $maxSize = 1GB $warnThreshold = 0.8 if (!(Test-Path $outputDir)) { New-Item -ItemType Directory -Path $outputDir -Force } # 计算 output 目录大小 + workspace 根目录下的 zip 文件大小 $outputSize = 0 $zipSize = 0 $outputItems = Get-ChildItem $outputDir -Recurse -ErrorAction SilentlyContinue if ($outputItems) { $outputSize = ($outputItems | Measure-Object -Property Length -Sum).Sum } $zipFiles = Get-ChildItem $workspaceDir -Filter "*.zip" -ErrorAction SilentlyContinue if ($zipFiles) { $zipSize = ($zipFiles | Measure-Object -Property Length -Sum).Sum } $totalSize = $outputSize + $zipSize if ($totalSize -gt ($maxSize * $warnThreshold)) { Write-Host "存储超过 80%，开始清理..." # 1. 删除最早的 zip 文件 if ($zipSize -gt 0) { $zipFilesSorted = $zipFiles | Sort-Object LastWriteTime foreach ($zip in $zipFilesSorted) { if ($totalSize -lt ($maxSize * $warnThreshold)) { break } $z = $zip.Length Remove-Item $zip.FullName -Force $totalSize -= $z Write-Host "已删除压缩包: $($zip.Name)" } } # 2. 删除最早的 output 子目录 $dirs = Get-ChildItem $outputDir -Directory -ErrorAction SilentlyContinue | Sort-Object LastWriteTime foreach ($dir in $dirs) { if ($totalSize -lt ($maxSize * $warnThreshold)) { break } $dirSize = (Get-ChildItem $dir.FullName -Recurse -ErrorAction SilentlyContinue | Measure-Object -Property Length -Sum).Sum if ($dirSize -gt 0) { Remove-Item $dir.FullName -Recurse -Force $totalSize -= $dirSize Write-Host "已删除: $($dir.Name)" } } } ``` ## 输出目录结构 **重要：每次运行都会在 output/ 下创建一个以"页面标题_时间戳"命名的独立目录，避免文件混淆。** **pageId获取方式**： - 从Confluence URL中提取：`/pages/viewpage.action?pageId=272188760` → `pageId=272188760` - 或从页面源码中获取 ``` output/ ├── 页面标题_2026-03-13_2030/ │ ├── 01_需求概述.md # 页面1的MD转换版 │ ├── 02_登录注册.md # 页面2的MD转换版 │ ├── 03_系统首页.md # 页面3的MD转换版 │ ├── ... # 其他页面 │ ├── requirement-meta.md # 元信息（整个采集任务的元信息） │ └── images/ # 关联图片 │ ├── 01_需求概述_功能架构图.png │ ├── 02_登录注册.png │ └── ... ``` **时间戳格式**：`YYYY-MM-DD_HHmm`（年月日_时分） ## 前置要求 **必须先登录 Confluence**： 1. 在运行 OpenClaw 的机器上打开浏览器 2. 访问 Confluence 页面并完成登录 3. 保持登录状态，后续的图片下载和内容获取都依赖这个已登录的 session ## 操作流程 ### Step 1: 分析页面结构 + 创建输出目录 + 检查存储上限 **⚠️ 重要：必须抓取所有子页面** - 这一步必须展开页面树，列出**所有**子页面（包括二级、三级、四级等全部层级） - 不能只抓父页面就停止 - 记录每个子页面的：pageId、标题、层级 **输入验证**： ```powershell param( [Parameter(Mandatory=$true)] [string]$confluenceUrl ) # 验证URL格式 if ($confluenceUrl -notmatch 'https?://[^/]+/pages/(viewpage\.action\?pageId=|viewpage\.action\?title=)') { throw "无效的Confluence URL，请提供形如 https://confluence.xxx.com/pages/viewpage.action?pageId=123456 的URL" } # 提取pageId（如果URL中包含） if ($confluenceUrl -match 'pageId=(\d+)') { $rootPageId = $matches[1] Write-Host "根页面ID: $rootPageId" } ``` **获取完整页面树的两种方法：** #### 方法1：通过浏览器页面树获取（默认推荐） 1. 用浏览器打开用户提供的 Confluence URL 2. 在页面左侧找到"页面树结构" 3. 点击"展开全部"或手动展开**所有层级**（包括二级、三级、四级...直到叶子节点） 4. 使用 browser evaluate 获取页面树的完整结构： ```javascript // 在浏览器控制台执行，获取所有页面链接 const links = Array.from(document.querySelectorAll('a[href*="pageId="]')).map(a => ({ title: a.textContent.trim(), pageId: a.href.match(/pageId=(\d+)/)?.[1], href: a.href })); console.log(JSON.stringify(links, null, 2)); ``` 5. 解析获取的数据，提取所有 pageId 和标题 6. **⚠️ 关键**：必须确保页面树完全展开，所有层级的子页面都被展开 7. 确认总共有多少个页面需要获取 #### 方法2：通过 Confluence REST API 获取（备选） ```powershell # 获取页面及其所有子页面 function Get-ConfluencePageTree { param( [string]$baseUrl = "https://confluence.xxx.com", [string]$rootPageId, [string]$cookie # 登录 cookie ) $pages = @() # 获取当前页面的直接子页面 $apiUrl = "$baseUrl/rest/api/content/$rootPageId/child/page" $headers = @{ "Cookie" = $cookie "Content-Type" = "application/json" } $response = Invoke-RestMethod -Uri $apiUrl -Headers $headers -Method Get foreach ($page in $response.results) { $pages += @{ pageId = $page.id title = $page.title type = $page.type } # 递归获取子页面的子页面 $childPages = Get-ConfluencePageTree -baseUrl $baseUrl -rootPageId $page.id -cookie $cookie $pages += $childPages } return $pages } # 调用 $allPages = Get-ConfluencePageTree -rootPageId $rootPageId -cookie $cookie Write-Host "共获取 $($allPages.Count) 个页面" ``` **检查并清理存储（如果超过80%上限）**： ```powershell # 复用全局配置的变量，或直接使用以下默认值 $outputDir = "C:\Users\xxx\.openclaw\workspace\output" $workspaceDir = "C:\Users\xxx\.openclaw\workspace" $maxSize = 1GB $warnThreshold = 0.8 if (!(Test-Path $outputDir)) { New-Item -ItemType Directory -Path $outputDir -Force } # 计算 output 目录大小 + workspace 根目录下的 zip 文件大小 $outputSize = 0 $zipSize = 0 $outputItems = Get-ChildItem $outputDir -Recurse -ErrorAction SilentlyContinue if ($outputItems) { $outputSize = ($outputItems | Measure-Object -Property Length -Sum).Sum } $zipFiles = Get-ChildItem $workspaceDir -Filter "*.zip" -ErrorAction SilentlyContinue if ($zipFiles) { $zipSize = ($zipFiles | Measure-Object -Property Length -Sum).Sum } $totalSize = $outputSize + $zipSize if ($totalSize -gt ($maxSize * $warnThreshold)) { Write-Host "存储超过 80%，开始清理..." # 1. 删除最早的 zip 文件 if ($zipSize -gt 0) { $zipFilesSorted = $zipFiles | Sort-Object LastWriteTime foreach ($zip in $zipFilesSorted) { if ($totalSize -lt ($maxSize * $warnThreshold)) { break } $z = $zip.Length Remove-Item $zip.FullName -Force $totalSize -= $z Write-Host "已删除压缩包: $($zip.Name)" } } # 2. 删除最早的 output 子目录 $dirs = Get-ChildItem $outputDir -Directory -ErrorAction SilentlyContinue | Sort-Object LastWriteTime foreach ($dir in $dirs) { if ($totalSize -lt ($maxSize * $warnThreshold)) { break } $dirSize = (Get-ChildItem $dir.FullName -Recurse -ErrorAction SilentlyContinue | Measure-Object -Property Length -Sum).Sum if ($dirSize -gt 0) { Remove-Item $dir.FullName -Recurse -Force $totalSize -= $dirSize Write-Host "已删除: $($dir.Name)" } } } ``` **创建带时间戳的输出目录**： ```powershell # 获取当前时间戳 $timestamp = Get-Date -Format "yyyy-MM-dd_HHmm" # 页面标题（去除非法字符） $safeTitle = "页面标题" -replace '[\\/:*?"<>|]', '_' # 创建目录 $outputDir = "C:\Users\root\.openclaw\workspace\output\${safeTitle}_${timestamp}" New-Item -ItemType Directory -Path "$outputDir\images" -Force ``` **后续所有文件都写入这个新创建的目录**，而不是直接写进 `output/` 根目录。 ### Step 2: 获取每个页面的内容（使用 sessions_spawn） **⚠️ 必须抓取所有页面，不允许选择性抓取** **重要**：由于需要获取多个页面，必须使用 sessions_spawn 派发子任务并行处理。 **步骤**： 1. 分析所有pageId列表（从页面URL或页面树中提取） 2. 派发子任务获取所有页面的文字内容 3. 派发子任务下载所有页面的图片 4. 监控子任务直到完成 **获取页面内容的方法**： 1. 使用 browser 访问 Confluence 页面 2. 获取页面完整HTML内容（browser evaluate 或 snapshot） 3. 将HTML转换为Markdown格式 **HTML转Markdown推荐方法**： - 方法1：使用 Python `markdownify` 库 ```powershell python -m pip install markdownify python -c "from markdownify import markdownify; print(markdownify(html_content))" ``` - 方法2：使用 Node.js `turndown` 库 ```powershell npm install -g turndown echo $htmlContent | turndown ``` - 方法3：使用在线API（如 html2md.com 的API） **关键要求**：转换过程中不得删除任何内容，包括： - 表格（保持表格结构） - 图片引用（转换为 `![](images/xxx.png)` 格式） - 代码块（保持原始格式） - 特殊字符和格式 ### Step 3: 获取页面图片（使用 curl 直接下载） **重要**：使用 curl 直接下载图片原始文件，不再使用 browser 截图方式。 **⚠️ 必须为每个页面下载图片，不管页面层级** **不管是一级页面、二级页面、三级页面还是更深层次的子页面，都必须下载该页面的所有图片附件！** > **关键原则**：每个页面独立获取图片 — 页面层级不影响图片下载，父页面的图片 ≠ 子页面的图片，子页面需要单独获取自己的图片！ **⚠️ 前置要求：必须先获取登录 Cookie** 由于 Confluence 私有图片需要登录才能下载，**需要用户手动提供 Cookie**： 1. 用户在浏览器中登录 Confluence 2. 按 F12 打开开发者工具 → Application/Storage → Cookies 3. 复制以下 cookie 的值： - `JSESSIONID` - `CONFLAuth` - 其他可能需要的 cookie（如 `_ga`、`tgw_l7_route` 等） 4. 将完整 cookie 字符串提供给模型，格式如： ``` _ga=GA1.1.xxx; pt_66be4504=xxx; JSESSIONID=xxx; tgw_l7_route=xxx ``` **获取认证Cookie**： ```powershell # 用户提供的 cookie（直接使用，无需额外处理） $cookie = "用户提供的完整cookie字符串" ``` **图片获取步骤**： 1. **遍历所有页面**：对 Step 1 中获取的**每一个**页面（包括所有层级的一级、二级、三级...子页面） 2. 对每个pageId，访问附件页面：`https://confluence.xxx.com/pages/viewpageattachments.action?pageId={pageId}` 3. 使用 curl 获取附件列表页面源码 4. 解析 `data-attachment-filename` 属性，找到该页面**所有**图片附件 5. 使用 curl 下载每个图片 6. **重复步骤1-5直到所有页面的图片都下载完成** **图片命名规则**： - 格式：`{页面序号}_{页面名称}.{扩展名}` - 例如：`01_需求概述_功能架构图.png`、`02_登录注册.png` **curl 下载命令示例**： ```powershell $cookie = "用户提供的cookie" $imageUrl = "https://confluence.xxx.com/download/attachments/272188760/image-2026-3-3_14-10-42.png?api=v2" $outputFile = "C:\Users\root\.openclaw\workspace\output\images\01_需求概述_功能架构图.png" curl.exe -L -o $outputFile $imageUrl -H "Cookie: $cookie" ``` **注意事项**： - 使用 `curl.exe` 而非 PowerShell 内置 `curl` 别名 - 添加 `-L` 参数跟随重定向 - 必须携带完整登录 Cookie 才能下载私有图片 - Cookie 可能有有效期限制，如失效需让用户重新提供 **curl 下载脚本（含错误处理和重试）**： ```powershell # 配置 $cookie = "JSESSIONID=xxx; CONFLAuth=xxx" # 替换为实际 cookie $imagesDir = "$outputDir\images" $maxRetries = 3 # 创建 images 目录 if (!(Test-Path $imagesDir)) { New-Item -ItemType Directory -Path $imagesDir -Force } # 图片列表（从附件页面解析得到） $imageList = @( @{pageId="272191284"; filename="image.png"; ext="png"}, @{pageId="272191284"; filename="photo.jpg"; ext="jpg"} ) $index = 1 foreach ($img in $imageList) { $imageUrl = "https://confluence.xxx.com/download/attachments/$($img.pageId)/$($img.filename)" $outputFile = "$imagesDir\$($img.pageId)_$index.$($img.ext)" # 重试逻辑 $success = $false for ($retry = 1; $retry -le $maxRetries; $retry++) { Write-Host "尝试下载 ($retry/$maxRetries): $imageUrl" $result = curl.exe -L -o $outputFile $imageUrl ` -H "Cookie: $cookie" ` -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" ` --silent --show-error ` 2>&1 # 检查文件是否成功下载 if ((Test-Path $outputFile) -and (Get-Item $outputFile).Length -gt 0) { $success = $true Write-Host "已下载: $outputFile" break } else { Write-Host "下载失败，等待重试..." Start-Sleep -Seconds 2 } } if (-not $success) { Write-Host "警告: 图片下载失败 - $imageUrl" -ForegroundColor Yellow } $index++ } Write-Host "图片下载完成，共 $($imageList.Count) 张" ``` **注意事项**： - 使用 `curl.exe` 而非 PowerShell 内置 `curl` 别名 - 添加 `-L` 参数跟随重定向 - 保留原始文件格式（png/jpg/svg等） - 必须携带登录 Cookie 才能下载私有图片 - 添加重试逻辑应对网络不稳定 - 下载后检查文件大小确保下载成功 ### Step 4: 生成输出文件 **所有文件都写入 Step 1 创建的 `$outputDir` 目录**。 #### 4.1 {序号}_{标题}.md（每个页面一个） 将Confluence页面的HTML内容忠实转换为Markdown格式。 **关键：必须插入图片引用！** 在生成 md 文件时，对于该页面关联的每张图片，必须在**适当位置**插入图片引用： ```powershell # 假设当前页面是 "02_登录注册"，该页面有 2 张图片 # images/ 目录中的文件： # - 02_登录注册.png # - 02_登录注册_2.png # 在 md 文件内容中插入图片引用（建议放在页面标题下方或相关章节后） $markdownContent = @" # 2.1 登录注册（一期交付） ![](images/02_登录注册.png) ## 1、功能设计 ... ## 2、原型图 ![](images/02_登录注册_2.png) ... "@ # 写入文件 $mdFileName = "02_登录注册.md" $mdFilePath = Join-Path $outputDir $mdFileName Set-Content -Path $mdFilePath -Value $markdownContent -Encoding UTF8 ``` **图片引用规则**： - 格式：`![](images/{图片文件名})` - 位置： - 如果图片是功能架构图/流程图，放在页面标题下方或相应章节后 - 如果是原型图，放在对应功能描述之后 - 如果无法确定位置，放在页面末尾 - 如果一个页面有多张图片，按文件名排序后依次插入 #### 4.2 requirement-meta.md ```markdown # 采集元信息 - 来源页面: [Confluence 页面 URL] - 采集根页面: [根页面标题和 URL] - 采集时间: [ISO 8601 格式，如 2026-03-15T18:00:00+08:00] - 采集环境: [Confluence URL 域名] - 总页面数: [页面总数] - 页面列表: - 01_需求概述 (pageId: 272188760) - 02_登录注册 (pageId: 272189290) - ... ``` 写入 `$outputDir\requirement-meta.md`。 #### 4.3 images/ 目录 - 保存所有下载的图片到 `$outputDir\images\` - 文件名格式：`{序号}_{页面标题}_{图片描述}.{扩展名}` - 例如：`01_需求概述_功能架构图.png`、`02_登录注册.png`、`02_登录注册_2.png` ### Step 5: 打包输出 将整个output目录打包成zip文件，发送给用户。 **打包命令**： ```powershell # 打包整个 output 目录 $timestamp = Get-Date -Format "yyyy-MM-dd_HHmm" $zipName = "confluence_export_$timestamp.zip" $zipPath = "C:\Users\root\.openclaw\workspace\$zipName" # 使用 PowerShell Compress-Archive Compress-Archive -Path "C:\Users\root\.openclaw\workspace\output\*" -DestinationPath $zipPath -Force # 验证打包结果 if (Test-Path $zipPath) { $zipSize = (Get-Item $zipPath).Length Write-Host "打包完成: $zipName (大小: $([math]::Round($zipSize/1MB, 2)) MB)" } else { Write-Host "打包失败!" -ForegroundColor Red } ``` **或者使用 7z（如果安装了中国）**： ```powershell 7z a -r "$zipPath" "C:\Users\root\.openclaw\workspace\output\*" ``` **输出文件后**： - 将 zip 文件路径返回给用户 - 用户下载后可解压查看 ## 注意事项 1. **使用sessions_spawn**：长时间任务必须使用sessions_spawn派发子任务并行处理 2. **图片直接下载**： - 访问 `viewpageattachments.action?pageId={pageId}` 获取附件列表 - 使用 curl 携带登录 Cookie 直接下载图片原始文件 - 保留原始格式（png/jpg/svg等） - 添加重试逻辑（建议3次）确保稳定性 3. **认证Cookie获取**： - 主session已登录，可以从browser获取Cookie - Cookie格式：`JSESSIONID=xxx; CONFLAuth=xxx` - 必须携带Cookie才能下载私有图片 4. **HTML转Markdown**： - 推荐使用 `markdownify` (Python) 或 `turndown` (Node.js) - 转换过程不得删除任何内容 - 表格、代码块、图片引用需保持完整 5. **存储管理**： - 每次创建新目录前检查存储上限 - 超过80%自动清理最早的目录和zip文件 - 注意处理空目录的边界情况 6. **错误处理**： - 所有网络请求添加重试逻辑 - 下载后验证文件大小 - 记录错误日志以便排查 7. **不删减内容**：原文的每一个字都要保留 8. **保留格式**：表格、列表等都要完整保留 9. **层级准确**：严格按照Confluence的页面树层级整理


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