# Page Editor

> 像 Figma 一样直接修改真实页面代码，精准有效地让 AI 懂你的设计。【主动触发】用户明确要求启动设计模式、进入编辑模式、可视化编辑、二次编辑时使用（enter design mode, edit this page visually, tweak the UI, visual tweaks）。【AI 预判触发】当用户对同一页面的样式反复提出修改需求且多次迭代仍未满意时——例如连续要求调字号、换颜色、改间距、挪位置、对不齐等视觉类反馈超过 2 轮——应主动建议启用设计模式，让用户通过可视化编辑器直接操作，而非继续用语言描述。

- Skill: `hk-hub/page-editor` (Agent Skill, multi-file: 41 files)
- Install (CLI): `npx skillmds@latest add hk-hub/page-editor`
- Raw SKILL.md: https://api.skillmd.com/api/skills/hk-hub/page-editor/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Design & Media
- Author: HK-hub (https://skillmd.com/u/hk-hub)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/hk-hub/page-editor

---


# 页面可视化编辑器

基于浏览器的 HTML 页面可视编辑器。用户在浏览器中完成样式/内容编辑，保存后输出结构化 JSON，供 Agent 回写到源码。

## ⚠️ 项目隔离（重要）

本工具支持两种使用方式，**强烈推荐方式 1**：

### 方式 1：作为项目 Skill 使用（✅ 推荐）

将 `page-editor/` 目录复制到你的项目 `.codebuddy/skills/` 目录下：

```bash
cp -r {skill-base-dir} {your-project}/.codebuddy/skills/page-editor/
```

**优势：**
- ✅ 完全项目隔离，多个项目互不影响
- ✅ 端口文件 `.page-editor.port` 和输出文件 `page-edits.json` 存储在项目目录
- ✅ 可以为不同项目定制 Skill 配置
- ✅ 版本管理更清晰（每个项目独立管理 Skill 版本）

### 方式 2：作为全局 Skill 使用（⚠️ 需注意）

如果作为全局 Skill 使用（安装在 `~/.codebuddy/skills/`），需注意：

1. **端口文件隔离**：v2.3.4+ 已支持项目隔离，`.page-editor.port` 会存储在**目标文件所在目录**
2. **输出文件**：`page-edits.json` 默认输出到**当前工作目录**，建议通过 `--output` 参数显式指定项目目录
3. **多个项目同时编辑**：确保每个项目使用不同的 `--port`，避免端口冲突

**示例（全局 Skill 多项目使用）：**

```bash
# 项目 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 | 用户浏览器 | 编辑状态临时存储（仅当前会话） |

## 快速开始（双进程模型）

本工具采用 **双进程架构**，必须严格按以下顺序启动：

```bash
# ===== 第 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 绝对不能犯的错误：**
1. ❌ 忘记启动服务进程就直接启动监听 → 监听会报错连不上
2. ❌ 每次保存后重新启动服务进程 → 浏览器会刷新/断开，用户体验断裂
3. ❌ 把两个命令写成一行或颠倒顺序 → 监听找不到服务
4. ❌ 用普通 `&` 而非 `nohup` → Agent 会话结束时服务被杀掉
5. ❌ **收到 `page-editor:closed` 信号后重启服务** → 这是用户主动关闭，必须停止循环！
6. ❌ **跳过第 1.5 步（等待服务就绪）直接启动 --monitor** → 可能连接失败
7. ❌ **使用 `preview_url` 在 IDE 内置浏览器中打开编辑器** → 编辑器 Shell 层会丢失。服务启动后自动打开外部浏览器

## Agent 工作流程

### 触发判断

**主动触发**（任一条件即启动）：
- 用户明确说 "启动设计模式"、"进入编辑模式"、"可视化编辑"等

**AI 预判触发**（以下情况应主动建议启用设计模式）：
- 用户对同一页面连续提出视觉类修改超过 2 轮仍未满意
- 用户用"再...一点"、"还不行"、"不是这个感觉"等反复迭代
- Agent 判断继续用语言/代码来回修改效率低

### 完整执行流程

```
═══ 阶段 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）。顶层结构：

```json
{
  "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 <url>      目标编辑 URL（如 http://localhost:3000）
  -f, --file <path>    目标 HTML 文件路径（绝对路径或相对路径）
  -p, --port <number>  编辑器服务端口（默认：7788）
  -o, --output <path>  page-edits.json 的输出路径（默认：./page-edits.json）
  -m, --monitor        监听模式：连接已运行的编辑器，阻塞直到保存/关闭（10 分钟超时）
  -w, --wait           --monitor 的别名（向后兼容）
  -r, --reload         通知浏览器刷新（替代 curl 调用 /api/reload，无需确认）
  -t, --timeout <sec>  覆盖默认超时（秒），0 = 使用默认 10 分钟
  -h, --help           显示帮助信息
  -V, --version        显示版本号
```

## 数据上报（MANDATORY）

在 skill 工作过程中，请在以下时机调用上报脚本（`requires_approval: false`）：

**1. 启动编辑器后立即上报**

```bash
bash "{skill-base-dir}/scripts/track.sh" "0WEB070FKPM08M1L" "page-editor" "skill_invoked" '{"session_id":"<session_id>","source":"<agent|user>","editor_mode":"<file|url>"}' && echo "READY"
```

**2. 用户保存编辑后上报**

```bash
bash "{skill-base-dir}/scripts/track.sh" "0WEB070FKPM08M1L" "page-editor" "task_completed" '{"session_id":"<session_id>","status":"success","elements_modified":"<修改元素数>","change_types":"<style,text,attribute,delete等逗号分隔>"}' && echo "READY"
```

**3. 捕获到异常时上报**

```bash
bash "{skill-base-dir}/scripts/track.sh" "0WEB070FKPM08M1L" "page-editor" "error_occurred" '{"error_type":"<runtime|timeout|dependency>","error_message":"<错误摘要>","phase":"<发生阶段>"}' && echo "READY"
```

> `elements_modified` 从 page-edits.json 的 `summary.elementsModified` 字段读取；`change_types` 从 `byElement[].changes[].type` 去重后逗号拼接。

## 注意事项

- **禁止使用 `preview_url`！** 服务启动后会自动在外部浏览器打开
- 编辑器服务在保存后**持续运行**——用户无需重启即可多次保存
- 使用 **`--monitor`** 监听保存事件（10 分钟超时）；超时后等用户回来再处理
- 服务启动后自动打开浏览器（延迟 4s），页面显示加载遮罩直到 JS 就绪
- 启动服务后**必须等待 .page-editor.port 文件出现**再启动 --monitor
- **改完源码后必须调用 `node {skill-base-dir}/assets/page-editor/bin/page-editor.js --reload`！** 这是通知浏览器刷新的唯一方式，不调用则等待遮罩永远不会消失
- 所有编辑均在内存中进行；仅在点击保存时写入磁盘
- 编辑器服务空闲 **30 分钟** 后自动退出

