diff --git a/README.md b/README.md index 9d794a3..4c651ab 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,25 @@ Canvas/WebGL/Audio 指纹、HTTP 请求头、屏幕视口、权限状态、鼠 ## 技术栈 -TypeScript + Node.js + Playwright + playright-extra + stealth 插件 + 自研 stealth 模块 +TypeScript + Node.js + Playwright + playwright-extra + stealth 插件 + 自研 stealth 模块 + +## 已验证功能 + +| 功能 | 状态 | 说明 | +|------|------|------| +| 页面打开/关闭/列表 | ✅ | 支持别名引用 | +| 文本提取 | ✅ | body.innerText | +| HTML 提取 | ✅ | documentElement.outerHTML | +| 截图 | ✅ | PNG base64 输出 | +| JS 执行 | ✅ | 任意代码 eval | +| 点击/输入/滚动 | ✅ | CSS 选择器定位 | +| 等待 | ✅ | 选择器或毫秒 | +| Cookie 管理 | ✅ | 查看/设置/删除 | +| 网络请求监控 | ✅ | 实时请求/响应日志 | +| 控制台监控 | ✅ | 实时 console 输出 | +| 指纹模版切换 | ✅ | 3 套内置配置 | +| WebSocket 实时推送 | ✅ | 页面事件广播 | +| 反检测 (navigator/screen/canvas/headers) | ✅ | 7 个 stealth 模块 | ## License diff --git a/docs/usage/examples.md b/docs/usage/examples.md index db82367..dde6ff4 100644 --- a/docs/usage/examples.md +++ b/docs/usage/examples.md @@ -1,143 +1,148 @@ # VisionL 使用示例 -> 面向智能体和人工用户的典型场景。 +> 基于实际测试验证的场景。 ## 场景一:搜索引擎查询 ```bash # 1. 打开百度 -visionl page open https://www.baidu.com --alias search -# → {"ok":true,"data":{"id":"p_1234","alias":"search",...}} +curl -s -X POST http://127.0.0.1:9527/pages \ + -H 'Content-Type: application/json' \ + -d '{"url":"https://www.baidu.com","alias":"search"}' -# 2. 输入搜索词 -visionl type search "#kw" "VisionL 浏览器" +# 2. 获取首页文本 +curl -s http://127.0.0.1:9527/pages/search/text -# 3. 点击搜索 -visionl click search "#su" +# 3. 输入搜索词并搜索 +curl -s -X POST http://127.0.0.1:9527/pages/search/type \ + -H 'Content-Type: application/json' \ + -d '{"selector":"#kw","text":"VisionL 浏览器"}' +curl -s -X POST http://127.0.0.1:9527/pages/search/click \ + -H 'Content-Type: application/json' \ + -d '{"selector":"#su"}' +curl -s -X POST http://127.0.0.1:9527/pages/search/wait \ + -H 'Content-Type: application/json' \ + -d '{"ms":2000}' -# 4. 等待结果加载 -visionl wait search --selector "#content_left" +# 4. 获取搜索结果 +curl -s http://127.0.0.1:9527/pages/search/text -# 5. 获取页面文本 -visionl text search -# → {"ok":true,"data":{"text":"搜索结果..."}} +# 5. 截图保存 +curl -s http://127.0.0.1:9527/pages/search/screenshot | jq -r '.data.base64' | base64 -d > result.png -# 6. 用完关闭 -visionl page kill search +# 6. 关闭 +curl -s -X DELETE http://127.0.0.1:9527/pages/search ``` ## 场景二:多页面信息收集 ```bash # 同时打开多个信息源 -visionl page open https://news.ycombinator.com --alias hn -visionl page open https://www.reddit.com/r/programming --alias reddit -visionl page open https://github.com/trending --alias gh +curl -s -X POST http://127.0.0.1:9527/pages \ + -H 'Content-Type: application/json' \ + -d '{"url":"https://www.baidu.com","alias":"baidu"}' +curl -s -X POST http://127.0.0.1:9527/pages \ + -H 'Content-Type: application/json' \ + -d '{"url":"https://www.bing.com","alias":"bing"}' # 分别提取内容 -visionl text hn -visionl text reddit -visionl text gh +curl -s http://127.0.0.1:9527/pages/baidu/text +curl -s http://127.0.0.1:9527/pages/bing/text -# 用完批量关闭 -visionl page kill-all +# 查看所有页面 +curl -s http://127.0.0.1:9527/pages + +# 关闭指定页面 +curl -s -X DELETE http://127.0.0.1:9527/pages/baidu ``` -## 场景三:表单填写 +## 场景三:Cookie 管理 ```bash -# 1. 打开登录页 -visionl page open https://example.com/login --alias login +# 查看页面 Cookie(百度首页返回 8 个 Cookie) +curl -s http://127.0.0.1:9527/pages/baidu/cookies -# 2. 填写表单 -visionl type login "#email" "user@example.com" -visionl type login "#password" "s3cret" +# 设置自定义 Cookie +curl -s -X POST http://127.0.0.1:9527/pages/baidu/cookies \ + -H 'Content-Type: application/json' \ + -d '{"name":"session","value":"abc123","domain":".baidu.com"}' -# 3. 提交 -visionl click login "button[type=submit]" - -# 4. 截图验证 -visionl screenshot login -o logged-in.png +# 删除特定 Cookie +curl -s -X DELETE http://127.0.0.1:9527/pages/baidu/cookies/session ``` -## 场景四:页面截图 +## 场景四:网络请求监控 ```bash -# 打开并截图 -visionl page open https://www.example.com --alias page -visionl wait page --ms 2000 # 等待渲染 -visionl screenshot page -o page.png +# 打开页面后查看网络请求日志 +curl -s http://127.0.0.1:9527/pages/baidu/network -# 滚动后截图 -visionl scroll page --down 600 -visionl screenshot page -o page-scrolled.png +# 返回包含请求 URL、方法、状态码等信息: +# [{"type":"response","url":"https://pss.bdstatic.com/...","status":200,...}] ``` ## 场景五:JS 数据提取 +```bash +# 获取页面标题 +curl -s -X POST http://127.0.0.1:9527/pages/baidu/eval \ + -H 'Content-Type: application/json' \ + -d '{"code":"document.title"}' +# {"ok":true,"data":{"result":"百度一下,你就知道"}} + +# 获取链接数量 +curl -s -X POST http://127.0.0.1:9527/pages/baidu/eval \ + -H 'Content-Type: application/json' \ + -d '{"code":"document.querySelectorAll(\"a\").length"}' + +# 获取页面 meta 信息 +curl -s -X POST http://127.0.0.1:9527/pages/baidu/eval \ + -H 'Content-Type: application/json' \ + -d '{"code":"document.querySelector(\"meta[name=description]\")?.content"}' +``` + +## 场景六:滚动截图 + +```bash +# 滚动页面 +curl -s -X POST http://127.0.0.1:9527/pages/baidu/scroll \ + -H 'Content-Type: application/json' \ + -d '{"deltaY":500}' + +# 滚动到底部 +curl -s -X POST http://127.0.0.1:9527/pages/baidu/scroll \ + -H 'Content-Type: application/json' \ + -d '{"toBottom":true}' + +# 截图 +curl -s http://127.0.0.1:9527/pages/baidu/screenshot | jq -r '.data.base64' | base64 -d > scrolled.png +``` + +## 场景七:切换指纹配置 + +```bash +# 查看可用配置 +curl -s http://127.0.0.1:9527/profiles + +# 使用 Windows Chrome 指纹打开页面 +curl -s -X POST http://127.0.0.1:9527/pages \ + -H 'Content-Type: application/json' \ + -d '{"url":"https://www.baidu.com","alias":"win","profile":"desktop-windows"}' +``` + +## 场景八:页面持久化验证 + ```bash # 1. 打开页面 -visionl page open https://api.example.com/data --alias data +curl -s -X POST http://127.0.0.1:9527/pages \ + -H 'Content-Type: application/json' \ + -d '{"url":"https://www.baidu.com","alias":"persistent"}' -# 2. 执行 JS 提取 JSON 数据 -visionl eval data "JSON.parse(document.body.innerText)" -# → {"ok":true,"data":{"result":{"items":[...]}}} +# 2. 关闭 curl 连接(页面不消失) +# 3. 重新查询 — 页面仍在 +curl -s http://127.0.0.1:9527/pages/persistent +# {"ok":true,"data":{"id":"p_xxx","status":"active",...}} -# 3. 获取页面标题 -visionl eval data "document.title" -# → {"ok":true,"data":{"result":"API Data Page"}} -``` - -## 场景六:REST 直通(高级) - -```bash -# 不使用子命令,直接调用 HTTP API -visionl raw POST /pages '{"url":"https://example.com","alias":"test"}' -# → {"ok":true,"data":{"id":"p_5678",...}} - -visionl raw GET /pages/p_5678/text -# → {"ok":true,"data":{"text":"..."}} - -visionl raw DELETE /pages/p_5678 -# → {"ok":true,"data":null} -``` - -## 场景七:智能体自动化工作流 - -LLM 通过 VisionL 完成机票比价: - -``` -1. visionl page open https://flights.example.com --alias flights -2. visionl type flights "#from" "北京" -3. visionl type flights "#to" "上海" -4. visionl type flights "#date" "2026-08-20" -5. visionl click flights "#search" -6. visionl wait flights --selector ".results" -7. visionl text flights - → 提取票价信息 -8. visionl eval flights "document.querySelectorAll('.price').length" - → 统计结果数量 -9. visionl page kill flights -``` - -## 场景八:长时间运行的任务 - -```bash -# 打开监控面板 -visionl page open https://monitor.example.com --alias monitor --pretty -# ✓ 页面已打开 -# ID: p_mon_001 -# URL: https://monitor.example.com -# 别名: monitor - -# ... 过了一段时间 ... - -# 还是同一个页面 -visionl page list --pretty -# ✓ 1 个页面 -# p_mon_001 monitor https://monitor.example.com active - -# 刷新重新截图 -visionl navigate monitor https://monitor.example.com -visionl screenshot monitor -o latest.png +# 4. 只有显式 kill 才关闭 +curl -s -X DELETE http://127.0.0.1:9527/pages/persistent ``` diff --git a/docs/usage/llm-integration.md b/docs/usage/llm-integration.md index eada769..6a45709 100644 --- a/docs/usage/llm-integration.md +++ b/docs/usage/llm-integration.md @@ -1,138 +1,192 @@ # 在 LLM 智能体中集成 VisionL -> 本文档介绍如何让 LLM 通过工具调用使用 VisionL-CLI 操控浏览器。 +> 让 LLM 通过 HTTP API 工具调用操控 VisionL 浏览器。 ## 原理 -LLM 将 `visionl` 注册为一个系统命令/工具,在需要浏览网页时调用。 -所有命令输出结构化的 JSON,LLM 直接解析结果并决定下一步操作。 +VisionL daemon 提供完整的 REST API。LLM 将 API 调用注册为工具/函数(Function Calling), +在需要浏览网页时生成对应的 HTTP 请求。所有接口返回结构化 JSON,LLM 直接解析。 + +## API 总览 + +| 方法 | 端点 | 功能 | +|------|------|------| +| POST | `/pages` | 打开页面 | +| GET | `/pages` | 列出所有页面 | +| GET | `/pages/:id` | 页面详情 | +| DELETE | `/pages/:id` | 关闭页面 | +| POST | `/pages/:id/navigate` | 跳转 | +| POST | `/pages/:id/click` | 点击元素 | +| POST | `/pages/:id/type` | 输入文本 | +| POST | `/pages/:id/scroll` | 滚动 | +| POST | `/pages/:id/eval` | 执行 JS | +| POST | `/pages/:id/wait` | 等待 | +| GET | `/pages/:id/screenshot` | 截图(base64) | +| GET | `/pages/:id/text` | 纯文本 | +| GET | `/pages/:id/html` | HTML 源码 | +| GET | `/pages/:id/cookies` | Cookie 列表 | +| POST | `/pages/:id/cookies` | 设置 Cookie | +| DELETE | `/pages/:id/cookies/:name` | 删除 Cookie | +| GET | `/pages/:id/console` | 控制台日志 | +| GET | `/pages/:id/network` | 网络请求日志 | +| GET | `/profiles` | 指纹配置列表 | + +完整文档见 [API 文档](../development/api.md)。 ## 集成方式 ### 方式一:Function Calling(推荐) -在 LLM 的 function/tool 定义中注册 VisionL 命令。大多数 LLM 平台(OpenAI、Claude、本地模型)都支持。 - -**工具定义示例(OpenAI 格式):** +注册 `visionl_api` 工具,LLM 直接生成 HTTP 请求: ```json { "type": "function", "function": { - "name": "visionl", - "description": "通过 VisionL 浏览器操控网页。子命令: page open|list|info|kill|kill-all, click, type, scroll, navigate, eval, wait, screenshot, text, html, daemon start|stop|status, raw", + "name": "visionl_api", + "description": "通过 VisionL 浏览器操控网页。支持打开页面、点击、输入、截图、提取文本、执行JS、管理Cookie、查看网络请求等。", "parameters": { "type": "object", "properties": { - "command": { + "method": { "type": "string", - "description": "完整 visionl 命令,例如 'page open https://example.com'" + "enum": ["GET", "POST", "DELETE"], + "description": "HTTP 方法" + }, + "path": { + "type": "string", + "description": "API 路径,如 /pages、/pages/baidu/text" + }, + "body": { + "type": "object", + "description": "请求体(仅 POST 需要)" } }, - "required": ["command"] + "required": ["method", "path"] } } } ``` -**使用流程:** +### 使用流程 1. LLM 决策需要访问网页 -2. LLM 生成 `visionl page open ` 调用 -3. 宿主程序在终端执行该命令,将 JSON 输出返回给 LLM -4. LLM 解析结果,继续决策(截图、点击、提取文本等) +2. LLM 调用 `visionl_api`:`POST /pages` 打开 baidu.com +3. 宿主程序执行 HTTP 请求,将 JSON 结果返回 LLM +4. LLM 解析结果,获得页面 ID `p_xxx` +5. LLM 继续:`GET /pages/p_xxx/text` 读取内容 +6. 或:`POST /pages/p_xxx/click` 点击搜索 -### 方式二:MCP Server +### 方式二:多工具注册 -可以封装一个 MCP(Model Context Protocol)Server,将 VisionL-CLI 包装为 MCP 工具: +将每个操作注册为独立工具(更细粒度): -```typescript -// 伪代码示意 -server.tool( - "visionl", - "通过 VisionL 浏览器操控网页", - { command: z.string() }, - async ({ command }) => { - const { stdout } = await exec(`visionl ${command}`); - return JSON.parse(stdout); +```json +[ + { + "name": "visionl_open", + "description": "打开网页", + "parameters": { + "url": { "type": "string" }, + "alias": { "type": "string" } + } + }, + { + "name": "visionl_text", + "description": "获取页面文本内容", + "parameters": { + "page_id": { "type": "string" } + } + }, + { + "name": "visionl_click", + "description": "点击页面元素", + "parameters": { + "page_id": { "type": "string" }, + "selector": { "type": "string" } + } } -); +] ``` -### 方式三:Agent 框架集成 - -与 LangChain、AutoGPT、CrewAI 等框架集成,注册为自定义工具。 - -**LangChain 示例:** +### 方式三:LangChain 集成 ```python -from langchain.tools import Tool -import subprocess, json +from langchain.tools import BaseTool +import requests -def visionl_tool(command: str) -> str: - result = subprocess.run( - ["visionl", *command.split()], - capture_output=True, text=True - ) - return result.stdout +class VisionLTool(BaseTool): + name = "visionl" + description = "浏览器操控工具。API 基础 URL: http://127.0.0.1:9527" -visionl = Tool( - name="visionl", - description="浏览器操控工具。命令示例:page open , click , text ", - func=visionl_tool, -) + def _run(self, method: str, path: str, body: dict = None) -> str: + url = f"http://127.0.0.1:9527{path}" + resp = requests.request(method, url, json=body) + return resp.text ``` -## LLM Prompt 建议 - -在系统 prompt 中添加以下指引: +## LLM 系统提示词建议 ``` -你可以使用 visionl 命令操控浏览器: +你可以使用 visionl_api 工具操控浏览器: -1. visionl page open [--alias ] — 打开页面 -2. visionl page list — 列出所有页面 -3. visionl text — 获取页面文本 -4. visionl screenshot — 截图(返回 base64) -5. visionl click — 点击元素 -6. visionl type — 输入文本 -7. visionl page kill — 关闭页面 +打开页面: POST /pages {"url":"...","alias":"..."} +页面文本: GET /pages/{id}/text +页面截图: GET /pages/{id}/screenshot (返回 base64) +点击元素: POST /pages/{id}/click {"selector":"#id"} +输入文本: POST /pages/{id}/type {"selector":"#id","text":"..."} +执行 JS: POST /pages/{id}/eval {"code":"..."} +滚动页面: POST /pages/{id}/scroll {"deltaY":300} +等待加载: POST /pages/{id}/wait {"ms":2000} +查看Cookie: GET /pages/{id}/cookies +网络日志: GET /pages/{id}/network +关闭页面: DELETE /pages/{id} -所有命令返回 JSON。解析 ok 字段判断成功/失败。 -使用 --alias 给页面起别名方便后续引用。 +所有接口返回 {"ok":true,"data":{...}} 或 {"ok":false,"error":{...}}。 +打开页面后记录返回的 page_id,后续操作使用该 id。 +页面在被显式 kill 之前永远存活,可跨多轮对话复用。 ``` -## 多页面管理 +## 多页面并行管理 -LLM 可以同时打开多个页面,通过别名区分: +LLM 同时打开多个页面,通过别名区分: ``` -LLM: visionl page open https://docs.python.org --alias py -LLM: visionl page open https://developer.mozilla.org --alias mdn -LLM: visionl text py # 读 Python 文档 -LLM: visionl text mdn # 读 MDN 文档 +LLM: POST /pages {"url":"https://docs.python.org","alias":"py"} +→ {"ok":true,"data":{"id":"p_aaa",...}} + +LLM: POST /pages {"url":"https://developer.mozilla.org","alias":"mdn"} +→ {"ok":true,"data":{"id":"p_bbb",...}} + +LLM: GET /pages/py/text # 读 Python 文档 +LLM: GET /pages/mdn/text # 读 MDN 文档 ``` ## 错误处理 -LLM 应检查返回的 `ok` 字段: - ```json // 失败示例 {"ok":false,"error":{"code":"PAGE_NOT_FOUND","message":"页面 py 不存在"}} ``` -常见错误及处理: +常见错误码及处理: -| 错误码 | 处理建议 | -|--------|---------| -| `PAGE_NOT_FOUND` | 页面可能已被关闭,重新打开 | -| `DAEMON_UNREACHABLE` | 等待几秒重试(自动拉起正在启动) | -| `TIMEOUT` | 页面加载慢,重试或增加等待时间 | -| `ALIAS_EXISTS` | 换一个别名或直接用 page ID | +| 错误码 | HTTP | 处理建议 | +|--------|------|---------| +| `PAGE_NOT_FOUND` | 404 | 页面已关闭,重新打开 | +| `DAEMON_UNREACHABLE` | 502 | 启动 daemon 或稍后重试 | +| `TIMEOUT` | 408 | 页面加载慢,重试或增加等待 | +| `ALIAS_EXISTS` | 409 | 换别名或直接用 page_id | -## 安全注意事项 +## 反检测能力 -- VisionL daemon 仅监听 127.0.0.1,外部不可访问 -- 执行的 JS 代码在页面沙箱内运行,无法逃逸到宿主机 -- LLM 应避免在不可信页面执行敏感操作(自动填写密码等) +VisionL 内置多层反检测,使自动化访问尽可能不被简单人机验证拦截: + +- `navigator.webdriver` → `false` +- 真实 Chrome User-Agent 和请求头 +- Canvas/WebGL/Audio 指纹加噪 +- 屏幕分辨率和视口合理性 +- 权限状态模拟 +- 3 套指纹模版可切换 + +详见 [反检测设计文档](../development/anti-detection.md)。 diff --git a/docs/usage/quickstart.md b/docs/usage/quickstart.md index 4ab56e2..0a0d104 100644 --- a/docs/usage/quickstart.md +++ b/docs/usage/quickstart.md @@ -1,89 +1,138 @@ # VisionL 快速开始 +## 环境要求 + +- Node.js >= 18 +- Chromium 浏览器(系统自带或 Playwright 安装) +- Linux/macOS/Windows(Android 需配合 Ubuntu proot 容器) + ## 安装 ```bash -# 1. 克隆仓库 git clone ssh://git@git.yeij.top:2222/AskaEth/VisionL.git cd VisionL - -# 2. 安装依赖 -npm install - -# 3. 安装 Chromium 浏览器 -npx playwright install chromium - -# 4. 构建 +npm install --registry=https://registry.npmmirror.com +npx playwright install chromium # 如果没有系统 Chromium npm run build +``` -# 5. 全局安装 CLI(可选) -cd packages/cli && npm link +## 启动 + +```bash +# 方式一:使用内置启动脚本 +node start-daemon.js & + +# 方式二:直接运行 daemon +VISIONL_PORT=9527 node packages/daemon/dist/server.js & ``` ## 基本使用 -### 启动 daemon +所有命令输出 JSON 格式,可使用 `--pretty` 切换为人类可读。 + +### 打开页面 ```bash -visionl daemon start -# ✓ Daemon 已启动 (端口 9527, PID 12345) +curl -X POST http://127.0.0.1:9527/pages \ + -H 'Content-Type: application/json' \ + -d '{"url":"https://www.baidu.com","alias":"baidu"}' ``` -### 打开一个页面 - -```bash -visionl page open https://www.baidu.com --alias baidu -# {"ok":true,"data":{"id":"p_a1b2c3d4","url":"https://www.baidu.com","alias":"baidu","title":"百度一下,你就知道","status":"active"}} +返回: +```json +{ + "ok": true, + "data": { + "id": "p_f1990959", + "url": "https://www.baidu.com", + "alias": "baidu", + "title": "百度一下,你就知道", + "status": "active", + "profile": "desktop-chrome" + } +} ``` ### 获取页面文本 ```bash -visionl text baidu -# {"ok":true,"data":{"text":"百度一下,你就知道\n..."}} +curl http://127.0.0.1:9527/pages/baidu/text ``` ### 搜索 ```bash -visionl type baidu "#kw" "VisionL" -visionl click baidu "#su" +# 输入搜索词 +curl -X POST http://127.0.0.1:9527/pages/baidu/type \ + -H 'Content-Type: application/json' \ + -d '{"selector":"#kw","text":"VisionL"}' + +# 点击搜索按钮 +curl -X POST http://127.0.0.1:9527/pages/baidu/click \ + -H 'Content-Type: application/json' \ + -d '{"selector":"#su"}' + +# 等待结果加载 +curl -X POST http://127.0.0.1:9527/pages/baidu/wait \ + -H 'Content-Type: application/json' \ + -d '{"ms":2000}' + +# 获取搜索结果 +curl http://127.0.0.1:9527/pages/baidu/text ``` ### 截图 ```bash -visionl screenshot baidu -o result.png +curl http://127.0.0.1:9527/pages/baidu/screenshot +# 返回 base64 编码的 PNG 图片 +``` + +### 执行 JavaScript + +```bash +curl -X POST http://127.0.0.1:9527/pages/baidu/eval \ + -H 'Content-Type: application/json' \ + -d '{"code":"document.title"}' +# {"ok":true,"data":{"result":"百度一下,你就知道"}} +``` + +### Cookie 管理 + +```bash +# 查看所有 Cookie +curl http://127.0.0.1:9527/pages/baidu/cookies + +# 设置 Cookie +curl -X POST http://127.0.0.1:9527/pages/baidu/cookies \ + -H 'Content-Type: application/json' \ + -d '{"name":"mycookie","value":"hello","domain":".baidu.com"}' +``` + +### 网络请求监控 + +```bash +# 查看网络请求日志 +curl http://127.0.0.1:9527/pages/baidu/network +``` + +### 查看指纹配置 + +```bash +curl http://127.0.0.1:9527/profiles +# [{"id":"desktop-chrome","name":"桌面 Chrome (通用)"}, +# {"id":"desktop-windows","name":"桌面 Chrome (Windows)"}, +# {"id":"desktop-mac","name":"桌面 Chrome (macOS)"}] ``` ### 关闭页面 ```bash -visionl page kill baidu -# {"ok":true,"data":null} +curl -X DELETE http://127.0.0.1:9527/pages/baidu ``` -### 停止 daemon +### 查看所有页面 ```bash -visionl daemon stop -``` - -## 无需手动启动 daemon - -CLI 会自动检测 daemon 是否运行,未运行则自动启动: - -```bash -# 直接使用,CLI 自动拉起 daemon -visionl page open https://example.com - -# 关闭所有页面(daemon 继续运行) -visionl page kill-all -``` - -## 查看所有页面 - -```bash -visionl page list -# {"ok":true,"data":[{"id":"p_xxx","url":"...","alias":"...","title":"...","status":"active"}]} +curl http://127.0.0.1:9527/pages ```