运行时依赖
安装命令
点击复制技能文档
Theo Confluence Reader 全局配置 # Confluence 配置(根据实际环境修改) $confluenceBaseUrl = "https://confluence.xxx.com" $输出Dir = "C:\Users\xxx\.OpenClaw\workspace\输出" $workspaceDir = "C:\Users\xxx\.OpenClaw\workspace" $maxSize = 1GB $warnThreshold = 0.8
核心原则
这个技能的职责是"忠实采集",不是"需求分析"
只做格式转换(HTML → MD),不做内容删减、概括或精简 保留原文的所有细节,包括表格、列表、备注、批注等 不要对原文做任何主观判断、删除或重组 执行规则(强制)
⚠️ 必须抓取所有页面,不允许部分抓取或偷懒
默认行为 自动抓取全部:给定一个Confluence页面链接后,必须抓取该页面及其所有子页面的全部内容 不允许只抓索引:不能只抓父页面或索引页就停下来,必须深入到每个叶子节点 不允许跳过:不能因为"内容太多"或"时间太长"而跳过某些页面 唯一例外:确认模式(仅允许询问一次)
如果预估采集时间超过5分钟或页面数量超过10个,可以先整理大纲并预估资源,返回给用户确认。
但必须遵守以下规则:
只能询问一次:确认后必须执行完整,不能再次询问 大纲必须包含: 所有待抓取页面的完整列表 预估页面数量 预估时间和资源消耗 确认后必须执行:用户确认后,立即开始抓取所有页面,中途不能停止或询问 禁止多次询问:一旦用户确认后,不能以任何理由再次询问是否继续 示例
错误做法(禁止):
只抓父页面索引,给用户后说"详细内容需要再抓" 抓了一部分后说"太多了要不要继续" 用户确认后 又问"这个子页面要不要抓"
正确做法:
要么直接全部抓完 要么先给大纲确认,确认后全部抓完 存储上限
输出/ 目录总大小上限:1GB
每次创建新目录前检查总大小 超过 80%(800MB)时:自动删除最早的目录 超过 100%(1GB)时:强制删除最早的目录直到低于 80%
检查并清理脚本:
$输出Dir = "C:\Users\xxx\.OpenClaw\workspace\输出" $workspaceDir = "C:\Users\xxx\.OpenClaw\workspace" $maxSize = 1GB $warnThreshold = 0.8
if (!(Test-Path $输出Dir)) { New-Item -ItemType Directory -Path $输出Dir -Force }
# 计算 输出 目录大小 + workspace 根目录下的 zip 文件大小 $输出Size = 0 $zipSize = 0
$输出Items = 获取-ChildItem $输出Dir -Recurse -ErrorAction SilentlyContinue if ($输出Items) { $输出Size = ($输出Items | Measure-Object -Property Length -Sum).Sum }
$zipFiles = 获取-ChildItem $workspaceDir -过滤器 ".zip" -ErrorAction SilentlyContinue if ($zipFiles) { $zipSize = ($zipFiles | Measure-Object -Property Length -Sum).Sum }
$totalSize = $输出Size + $zipSize
if ($totalSize -gt ($maxSize $warnThreshold)) { Write-Host "存储超过 80%,开始清理..." # 1. 删除最早的 zip 文件 if ($zipSize -gt 0) { $zipFiles排序ed = $zipFiles | 排序-Object LastWriteTime foreach ($zip in $zipFiles排序ed) { if ($totalSize -lt ($maxSize $warnThreshold)) { break } $z = $zip.Length 移除-Item $zip.FullName -Force $totalSize -= $z Write-Host "已删除压缩包: $($zip.Name)" } } # 2. 删除最早的 输出 子目录 $dirs = 获取-ChildItem $输出Dir -Directory -ErrorAction SilentlyContinue | 排序-Object LastWriteTime foreach ($dir in $dirs) { if ($totalSize -lt ($maxSize $warnThreshold)) { break } $dirSize = (获取-ChildItem $dir.FullName -Recurse -ErrorAction SilentlyContinue | Measure-Object -Property Length -Sum).Sum if ($dirSize -gt 0) { 移除-Item $dir.FullName -Recurse -Force $totalSize -= $dirSize Write-Host "已删除: $($dir.Name)" } } }
输出目录结构
重要:每次运行都会在 输出/ 下创建一个以"页面标题_时间戳"命名的独立目录,避免文件混淆。
pageId获取方式:
从Confluence URL中提取:/pages/viewpage.action?pageId=272188760 → pageId=272188760 或从页面源码中获取 输出/ ├── 页面标题_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:
在运行 OpenClaw 的机器上打开浏览器 访问 Confluence 页面并完成登录 保持登录状态,后续的图片下载和内容获取都依赖这个已登录的 会话 操作流程 Step 1: 分析页面结构 + 创建输出目录 + 检查存储上限
⚠️ 重要:必须抓取所有子页面
这一步必须展开页面树,列出所有子页面(包括二级、三级、四级等全部层级) 不能只抓父页面就停止 记录每个子页面的:pageId、标题、层级
输入验证:
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:通过浏览器页面树获取(默认推荐) 用浏览器打开用户提供的 Confluence URL 在页面左侧找到"页面树结构" 点击"展开全部"或手动展开所有层级(包括二级、三级、四级...直到叶子节点) 使用 browser evaluate 获取页面树的完整结构: // 在浏览器控制台执行,获取所有页面链接 const links = Array.from(document.查询SelectorAll('a[href*="pageId="]')).map(a => ({ title: a.textContent.trim(), pageId: a.href.match(/pageId=(\d+)/)?.[1], href: a.href })); console.记录(JSON.stringify(links, null, 2));
解析获取的数据,提取所有 pageId 和标题 ⚠️ 关键:必须确保页面树完全展开,所有层级的子页面都被展开 确认总共有多少个页面需要获取 方法2:通过 Confluence REST API 获取(备选) # 获取页面及其所有子页面 function 获取-ConfluencePa获取ree { 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" = "应用/json" } $响应 = Invoke-RestMethod -Uri $APIUrl -Headers $headers -Method 获取 foreach ($page in $响应.结果s) { $pages += @{ pageId = $page.id title = $page.title t