基于浏览器的 HTML 页面可视编辑器。用户在浏览器中完成样式/内容编辑,保存后输出结构化 JSON,供 Agent 回写到源码。
本工具支持两种使用方式,强烈推荐方式 1:
将 page-editor/ 目录复制到你的项目 .codebuddy/skills/ 目录下:
cp -r {skill-base-dir} {your-project}/.codebuddy/skills/page-editor/
优势:
.page-editor.port 和输出文件 page-edits.json 存储在项目目录如果作为全局 Skill 使用(安装在 ~/.codebuddy/skills/),需注意:
.page-editor.port 会存储在目标文件所在目录page-edits.json 默认输出到当前工作目录,建议通过 --output 参数显式指定项目目录--port,避免端口冲突示例(全局 Skill 多项目使用):
# 项目 A
cd /path/to/project-a
node ~/.codebuddy/skills/page-editor/assets/page-editor/bin/page-editor.js --file ./index.html --output ./page-edits.json &
# 项目 B(使用不同端口)
cd /path/to/project-b
node ~/.codebuddy/skills/page-editor/assets/page-editor/bin/page-editor.js --file ./index.html --port 7789 --output ./page-edits.json &
| 文件 | 存储位置 | 说明 |
|---|---|---|
| --- | --- | --- |
.page-editor.port | 目标文件所在目录(v2.3.4+)或 CWD | 记录编辑器服务端口号 |
page-edits.json | --output 参数指定(默认 ./page-edits.json) | 保存时的改动记录 |
| 浏览器 localStorage | 用户浏览器 | 编辑状态临时存储(仅当前会话) |
本工具采用 双进程架构,必须严格按以下顺序启动:
# ===== 第 0 步:安装依赖(仅需首次,后续跳过)=====
SKILL_DIR="{skill-base-dir}/assets/page-editor"
if [ ! -d "$SKILL_DIR/node_modules" ]; then
cd "$SKILL_DIR" && npm install --prefer-offline --no-audit --no-fund
fi
# ===== 第 1 步:启动服务进程(后台常驻,只启动一次!)=====
# 日志写入临时文件以便排障;服务就绪后会自动打开浏览器(延迟 4s,页面显示加载遮罩直到 JS 就绪)
LOGFILE="/tmp/page-editor-$(date +%s).log"
nohup node {skill-base-dir}/assets/page-editor/bin/page-editor.js --file <目标HTML路径> > "$LOGFILE" 2>&1 &
SERVICE_PID=$!
# ===== 第 1.5 步:等待服务就绪(重要!不要跳过)=====
for i in $(seq 1 30); do
if [ -f ".page-editor.port" ]; then break; fi
sleep 0.5
done
if [ ! -f ".page-editor.port" ]; then
echo "⚠️ 服务未能在 15 秒内启动,请检查日志: cat $LOGFILE"
fi
# ===== 第 2 步:启动监听进程(前台阻塞,10 分钟超时)=====
# 阻塞等待用户保存或关闭编辑器。10 分钟内无操作会超时退出。
node {skill-base-dir}/assets/page-editor/bin/page-editor.js --monitor
双进程说明:
| 服务进程(第 1 步) | 监听进程(第 2 步) | |
|---|---|---|
| --- | --- | --- |
| 命令 | nohup ... --file xxx & | node ... --monitor |
| 运行方式 | 后台 & | 前台阻塞 |
| 生命周期 | 启动后持续运行,30 分钟无活动自动退出 | 每次保存/关闭后自动退出 |
| 可重复启动? | 不需要重复! 只启动一次 | 每轮保存后需重新启动一个新的 |
⚠️ Agent 绝对不能犯的错误:
& 而非 nohup → Agent 会话结束时服务被杀掉page-editor:closed 信号后重启服务 → 这是用户主动关闭,必须停止循环!preview_url 在 IDE 内置浏览器中打开编辑器 → 编辑器 Shell 层会丢失。服务启动后自动打开外部浏览器主动触发(任一条件即启动):
AI 预判触发(以下情况应主动建议启用设计模式):
═══ 阶段 A:首次启动 ═══
Step 1. Agent 安装依赖(如未安装),然后启动【服务进程】(后台,只此一次):
nohup node {skill-base-dir}/assets/page-editor/bin/page-editor.js --file <目标路径> > /tmp/page-editor.log 2>&1 &
服务启动后会自动打开浏览器编辑器,Agent 不需要手动打开。
Step 2. Agent **等待服务就绪**(检查 .page-editor.port 文件出现,最多等 15 秒)
Step 3. Agent 告知用户:
"✅ 设计模式已开启,浏览器会自动打开编辑器。
我会持续监听你的保存操作。调整完后点「保存」我会自动处理。
如果你想先做别的事,可以点暂停按钮,保存完跟我说一句「我保存好了」即可。"
Step 4. Agent 立即启动【监听进程】(10 分钟超时,无需传 timeout 参数):
node {skill-base-dir}/assets/page-editor/bin/page-editor.js --monitor
Step 5. 浏览器自动打开 → 用户在编辑器中自由调整样式/内容
Step 6. 用户点击「保存」→ --monitor 进程输出 JSON 到 stdout → 监听进程自动退出
═══ 阶段 B:处理保存结果(自动执行,无需用户确认)═══
**用户视角的交互流程(保存→看到最新效果):**
1. 用户点击「保存」→ 全屏等待遮罩出现 → "正在等待 AI 修改代码..."
→ 编辑器自动退出编辑模式(防止用户操作过期内容)
2. AI 读取 JSON → 将改动写入源码磁盘 → **调用 `/api/reload` 通知浏览器**
3. SSE 推送刷新信号到浏览器
4. 遮罩文字变为 "样式已更新" → "正在加载最新预览…"
5. iframe 强制重载 → 显示 AI 改写后的最新页面
6. 遮罩淡出消失 → 编辑器重新初始化 → **自动进入编辑模式** → 用户可继续编辑
Step 7. Agent 从 stdout 读取 JSON,**自动将改动应用到源码文件**(无需询问用户)
Step 7.5. ⚡ **源码全部写入磁盘后,Agent 必须通知浏览器刷新:**
```bash
node {skill-base-dir}/assets/page-editor/bin/page-editor.js --reload
```
⚠️ **这一步必须执行!不调用则浏览器的等待遮罩永远不会消失。**
调用后 → SSE 推送 → iframe 强制刷新 → 遮罩消失 → 编辑器自动恢复编辑模式。
Step 8. Agent 调用 reload 后,**立即启动新的【监听进程】进入下一轮等待**:
node {skill-base-dir}/assets/page-editor/bin/page-editor.js --monitor
⚠️ 【服务进程】一直在运行,不需要重启!
Step 9. Agent 回复用户(**在启动 monitor 之后回复**,因为 --monitor 是阻塞的):
"✅ 修改已生效,页面已自动更新!继续调整随时点「保存」,我在这里。"
═══ 阶段 C:持续编辑循环(无感刷新)═══
(此阶段完全由 Agent 自动维持,用户无需说任何话即可持续编辑)
Step 9. 用户在浏览器中继续编辑 → 点击「保存」
→ 监听进程收到 JSON → 输出到 stdout → **监听进程自动退出**
Step 10. Agent 读取 stdout 输出,**根据返回类型判断下一步**:
⚠️ **关键:必须先检查返回的 JSON type 字段!**
▸ type = "page-editor:changes" → **正常保存**,执行 Step 10a
▸ type = "page-editor:closed" → **用户关闭了编辑器**,直接跳转 阶段 D
▸ type = "timeout" → **10 分钟内无操作**,执行 Step 10b
Step 10a. Agent 自动将改动应用到源码
⚡ 源码全部写入磁盘后,**必须通知浏览器刷新**:
```bash
node {skill-base-dir}/assets/page-editor/bin/page-editor.js --reload
```
→ 浏览器 iframe 自动刷新 + 自动恢复编辑模式
Step 10b. Agent 收到 timeout(10 分钟无操作):
告知用户:"⏰ 监听已超时(10 分钟无操作)。如果你保存了改动,跟我说一句「我保存好了」,
我会读取修改文件并处理。或者跟我说「继续监听」,我会重新启动监听。"
⚠️ **不要自动重启 monitor!** 超时说明用户可能不在了。等用户回来再处理。
Step 11. Agent **再次启动新的【监听进程】**:
node {skill-base-dir}/assets/page-editor/bin/page-editor.js --monitor
Step 12. Agent 回复用户:
"✅ 已更新!继续调整随时点「保存」。"
Step 13. 循环 Step 9 ~ 12,直到用户主动结束或收到 closed 信号
═══ 阶段 D:结束编辑(仅用户主动触发)═══
以下任一情况发生时,Agent 才终止服务:
① 用户在对话中说:「好了」「不用了」「改完了」「关闭设计模式」「退出编辑器」等
② 用户在编辑器界面点击「关闭」按钮 → --monitor 输出 `{"type":"page-editor:closed"}` 后退出
③ --monitor 的 stdout 输出中包含 `"type":"page-editor:closed"`
**⚠️ 识别 closed 信号的方法:**
- 输出中出现 `PAGE EDITOR CLOSED` 或 `"type":"page-editor:closed"`
- 这是**正常关闭**,**不是异常**,**绝对不要重启服务进程**!
Agent 操作:
- 终止后台【服务进程】:pkill -f "page-editor.js.*--file"
- 如有未应用的改动,先应用再关闭
- 回复:"✅ 设计模式已关闭,所有改动已保存。"
⚠️ **绝对不要做的事:**
- ❌ 不要在每轮保存后问"是否执行"——默认直接执行
- ❌ 不要等用户说"继续"才启动下一次 monitor——保存后立刻重启
- ❌ 不要让用户觉得需要说话才能继续编辑——整个循环应该是静默自动的
- ❌ **不要让用户手动刷新浏览器**——改完源码后调用 `/api/reload`,浏览器会自动刷新
- ❌ **收到 `page-editor:closed` 后不要重启服务!** 必须结束循环
- ❌ **收到 timeout 后不要自动重启 monitor!** 等用户回来再处理
- ❌ **不要使用 `preview_url`!** 服务启动后会自动打开外部浏览器
- ❌ **改完源码后不要忘记调用 `--reload`!** 不调用则浏览器等待遮罩不会消失
### 暂停降级路径
如果用户暂停了当前命令(点击暂停按钮或中断 --monitor 进程),或者 --monitor 超时了:
1. Agent 告诉用户:"监听已暂停。你可以继续在浏览器中编辑。保存后跟我说一句「我保存好了」即可。"
2. 用户说"我保存好了" → Agent 读取 `page-edits.json` 文件:
```bash
cat page-edits.json
```
3. Agent 根据文件内容应用改动到源码
4. 改完后通知浏览器刷新:
```bash
node {skill-base-dir}/assets/page-editor/bin/page-editor.js --reload
```
5. 然后重新启动 `--monitor` 进入下一轮
### 异常处理清单
| 异常现象 | 原因 | Agent 应该怎么做 |
|---------|------|----------------|
| --monitor 输出 `page-editor:closed` | **不是异常!** 用户点了「关闭」按钮 | **不要重启!** 执行阶段 D |
| --monitor 报错连不上 | 服务进程超时退出或崩溃 | 重启服务进程(Step 1)→ 重启 monitor |
| 浏览器打不开/空白 | 端口被占用 | 换 `-p` 指定其他端口重试 |
| 保存后浏览器不刷新 | AI 没有调用 --reload | **必须调用** `node {skill-base-dir}/assets/page-editor/bin/page-editor.js --reload` |
| 用户说"浏览器编辑不了了" | 服务进程终止 | 重新执行 Step 1 + monitor |
| 用户在对话中插话 | 用户想在编辑器之外加需求 | 记录需求,等当前保存循环完成后一并处理 |
## 编辑能力
### 样式编辑
- 背景色 / 渐变色(Figma 风格的颜色选择器,支持光谱、色相、透明度)
- 文字颜色
- 字号、字重
- 圆角、内边距、外边距、间距
- 宽度、高度
- 边框(颜色、宽度、样式)
- 阴影、透明度
- Flex 布局属性(方向、主轴对齐、交叉轴对齐、换行、间距)
### 内容编辑
- 双击行内编辑文字内容
- 图片 URL 替换(background-image 或 img src)
- 图片适配模式(cover / contain / original)
### 高级功能
- **配色方案库** — 自动从目标页面提取 CSS 自定义属性(变量/Token)
- **伪状态编辑** — 通过属性面板切换元素状态来编辑 :hover、:focus、:active 样式
- **一致性检测** — 保存时自动检测跨元素模式,建议批量修改 CSS 规则
- **元素删除** — 从 DOM 中删除元素(可撤销,记录在输出中)
- **多选对齐** — 选中多个元素并进行对齐操作
- **完整撤销/重做** — 支持最多 200 步操作,Cmd/Ctrl+Z / Cmd/Ctrl+Shift+Z
### 变更管理
- 变更计数器显示 "N 个元素 + M 个变量 已修改"
- 点击计数器打开所有已修改元素的浮出列表
- 悬停列表项可在页面中高亮对应元素并滚动到可视区域
- 点击 ✕ 可撤销某个元素的修改(可撤销)
### AI 输出增强 (v3.3)
- **CSS 规则上下文** — 每项变更包含 `matchedRule.fullRuleText`
- **逐元素 CSS 差异** — `cssDiff` 视图展示逐属性的 action
- **伪状态感知** — 明确标记 `pseudoState` 和匹配的伪状态 CSS 规则
- **CSS 变量追踪** — Token 编辑包含变量名、定义位置和文件
- **跨元素模式检测** — 多个元素共享相同变更时建议修改公共规则
- **修改策略** — `strategy` 字段给出最佳应用方式
- **内置指令** — `instructions` 字段提供分步指导
## 输出格式(摘要)
保存后生成 `page-edits.json`(v4.0)。顶层结构:
{
"version": "4.0",
"savedAt": "2026-04-14T10:30:00.000Z",
"targetFile": "./dist/index.html",
"targetAnalysis": { "type": "multi-file", "cssFramework": "tailwind" },
"summary": { "totalChanges": 12, "elementsModified": 5 },
"patterns": [ { "type": "batch-same-change", "suggestion": "..." } ],
"byElement": [ { "selector": "...", "tag": "div", "intent": "调整配色", "strategy": "..." } ]
}
### 变更类型
| type | 含义 | 应用方式 |
|------|---------|-------------|
| `style` | CSS 属性变更 | 更新 CSS 规则或行内样式 |
| `text` | 文字内容变更 | 更新模板/HTML 中的文字 |
| `attribute` | HTML 属性变更 | 更新 HTML 中的属性 |
| `cssVariable` | CSS 自定义属性变更 | 更新 CSS 中的变量定义 |
| `delete` | 元素被删除 | 从模板/HTML 中移除元素 |
| `reorder` | 子元素顺序调整 | 调整模板中的子元素排列顺序 |
完整字段说明见 `references/output-format.md`。
## 命令行选项
选项:
-u, --url
-f, --file
-p, --port
-o, --output
-m, --monitor 监听模式:连接已运行的编辑器,阻塞直到保存/关闭(10 分钟超时)
-w, --wait --monitor 的别名(向后兼容)
-r, --reload 通知浏览器刷新(替代 curl 调用 /api/reload,无需确认)
-t, --timeout
-h, --help 显示帮助信息
-V, --version 显示版本号
## 数据上报(MANDATORY)
在 skill 工作过程中,请在以下时机调用上报脚本(`requires_approval: false`):
**1. 启动编辑器后立即上报**
bash "{skill-base-dir}/scripts/track.sh" "0WEB070FKPM08M1L" "page-editor" "skill_invoked" '{"session_id":"
**2. 用户保存编辑后上报**
bash "{skill-base-dir}/scripts/track.sh" "0WEB070FKPM08M1L" "page-editor" "task_completed" '{"session_id":"