npm.io
0.1.1 • Published yesterdayCLI

@deeploop-ai/modao-cli

Licence
MIT
Version
0.1.1
Deps
6
Size
228 kB
Vulns
0
Weekly
0

Modao CLI

墨刀(MockingBot)离线包 CLI 与 MCP 服务器:在终端读取、浏览、检索墨刀设计资产,也可作为 stdio MCP 服务供 Claude Code、Cursor 等客户端调用——项目 → 画布 → 页面 → 元素树,以及批注与图片资源。

墨刀官方 MCP(modao-proto-mcp)只做 AI 生成 HTML / 导入,不读取已有设计。本项目补的是「加载并理解既有设计文件」这个空位,不与官方冲突。

Modao (MockingBot) offline-package CLI and MCP server: list/search/read projects, pages, element trees, annotations and image assets from exported Modao HTML packages. Complements the official generation-oriented modao-proto-mcp.

重要前置说明

本工具的输入是墨刀的「HTML 离线演示包」,这是付费导出功能(个人版/团队版付费用户可用,免费版不支持)。获取步骤:

  1. 在墨刀网页版(modao.cc)打开目标项目;
  2. 使用「导出 → HTML 离线演示包」;
  3. 解压导出的压缩包,得到一个项目目录(内含 extra/uploads7/index.html);
  4. --dir 指向该目录(或其父目录,可放多个项目)。

分享链接(modao.cc/app/<hash>)目前仅支持占位识别与降级指引,不做数据抓取。 原因:墨刀没有公开可用的读取型 API(历史 OAuth2 API 已被官方废弃且本就不含页面数据),分享页的设计数据由前端经未公开 XHR 接口加载,属非公开契约、随时可变更。把分享链接传给 --url(向后兼容也可传给 --dir)时,list / list_projects 中会出现一个 status: unsupported 的占位项目并附降级说明;对其做任何数据访问都会返回上述导出指引。

安装

需要 Node.js ≥ 18。

npm install -g @deeploop-ai/modao-cli

也可不安装、用 npx

npx @deeploop-ai/modao-cli --dir <离线包目录或其父目录>

命令

全局选项:--dir <path>--url <url>(均可重复)、--json(结构化输出)。

命令 说明 示例
mcp 以 stdio 启动 MCP 服务器(可裸启,数据源由工具调用参数指定) modao mcp / modao mcp --dir D:/design/modao-exports
list [project] 无参列出项目;带 project id 列出页面 modao list --dir ./pkgs / modao list <project> --dir ./pkgs --json
dsl <project> <page> 输出页面裁剪 DSL(--format yaml|json--depth n modao dsl <project> <page> --dir ./pkgs --format yaml
search <query> 全文检索(--project--limit modao search 首页 --dir ./pkgs --json
images <project> <page> 页面元素级图片清单(含缓存绝对路径) modao images <project> <page> --dir ./pkgs
menu <project> 提取播放器菜单树:画布顺序、分组与叶子画布 id(含 flpk 解析缺失的画布) modao menu <project> --url http://intranet/pkg/
snapshot <project> <page> 整页长图 PNG(可选 --out--zoom 1~4);远程目录源同时打印预览 URL modao snapshot <project> <page> --dir ./pkgs
snapshot-canvas <project> <canvas> 画布总览长图 PNG(该画布全部页面缩略图+页名;可选 --out--zoom 1~4 默认 2、--clip x,y,w,h 裁剪、--split 分片输出) modao snapshot-canvas <project> <canvas> --url http://intranet/pkg/ --zoom 3
pull [url...] 预拉/刷新远程包缓存 modao pull --url http://intranet/pkg/ / modao pull http://intranet/pkg.zip --url http://intranet/pkg/
默认命令

不带子命令时等同 mcp,兼容旧的直挂用法:

modao --dir D:/design/modao-exports
# 等同于
modao mcp --dir D:/design/modao-exports

--dir 可重复;值为分享链接 URL 时注册为占位项目。也可用 --url 指向远程离线包(内网静态目录或 zip)或分享链接:

modao list --dir D:/design/mdao-exports --url "https://modao.cc/app/<40位hash>"
modao mcp --url "http://192.168.12.67:18080/docs/6.2.6-pkg/"
modao mcp --url "http://192.168.12.67:18080/exports/pkg.zip"

modao mcp(不带 --dir/--url、也无相关环境变量)同样可以启动:此时没有默认数据源,每次工具调用需以 dir / url 入参指定(见「MCP 客户端配置」)。

MCP 客户端配置

推荐裸启:客户端配置只写 modao mcp,数据源由每次工具调用的 dir / url 入参指定(Agent 无需改配置即可切换多个项目/内网包);--dir/--url 与环境变量配置的数据源作为未传参时的默认值。

Claude Desktop(claude_desktop_config.json)/ Cursor / Kimi Code:

{
  "mcpServers": {
    "modao": {
      "command": "modao",
      "args": ["mcp"]
    }
  }
}

未全局安装时可用 npx:

{
  "mcpServers": {
    "modao": {
      "command": "npx",
      "args": ["-y", "@deeploop-ai/modao-cli", "mcp"]
    }
  }
}

Claude Code:

claude mcp add modao -- modao mcp

也可在启动参数里固定默认数据源(向后兼容,工具调用未传参时使用):

{
  "mcpServers": {
    "modao": {
      "command": "modao",
      "args": ["mcp", "--dir", "D:/design/modao-exports"]
    }
  }
}
MCP 工具数据源入参

每个工具都接受可选的 dir / url 入参(单值或数组均可,语义同 CLI 的 --dir/--url):

  • 传了 dir / url:以调用参数为准(不与默认源合并),相同组合的结果在服务内缓存复用;
  • 都不传:使用服务器启动配置(--dir/--urlMODO_DATA_DIR/MODO_DATA_URL)的默认数据源;
  • 两者都未配置时调用会返回指引错误,提示传 dirurl
MCP 工具列表
Tool 说明
list_projects 列出所有已识别项目(id、名称、来源、更新时间;分享链接显示为占位)
list_pages 列出项目页面(id、名称、所属画布——区分用户画布/动态组件画布、批注数)
get_page_dsl 页面裁剪 DSL(元素类型/名称/位置尺寸/文本/层级),yaml/json 双格式,depth 截断
get_element_detail 单个元素完整属性(含 DSL 裁掉的 zIndex、原始字段等)
get_annotations 页面批注(富文本说明)
search_assets 跨项目全文检索:项目名/页面名/元素名/文本内容,返回定位路径与片段
get_page_image 页面元素级图片清单(复制到缓存目录,返回绝对路径;不做整页合成渲染)
get_page_snapshot 整页长图 PNG:传 page_id 截单页(原尺寸);传 canvas_id 截画布总览长图(全部页面缩略图+页名一图纵览);canvas_id + split: true 追加分片输出(总览+按空白沟切的 N 张可读宽度小图,返回 tiles 清单,每片带墙内 clip 坐标,适合逐片读小字)。返回磁盘绝对路径(及远程目录源的预览 URL),Agent 自行读取该图;需要 Playwright
refresh_projects 刷新数据源:远程离线包重新拉取,本地目录重新扫描(范围同上:调用参数优先,未传则默认源)

以上所有工具均接受可选 dir / url 入参指定数据源(见「MCP 工具数据源入参」)。

典型用法流程:先检索定位,再精读——用 search_assets / list_pages 找到目标页面,再用 get_page_dsl 拉裁剪后的 DSL;超大页面先用 depth 看骨架,按截断提示用 get_element_detail 精读子树。看稿get_page_snapshot(读取返回的 path 直接看整页长图),读结构与文案get_page_dsl

环境变量

环境变量 说明
MODO_DATA_DIR 数据源(等价 --dir,逗号分隔多个值;CLI 有值时不生效)。MCP 模式下作为工具未传 dir/url 入参时的默认数据源
MODO_DATA_URL 远程数据源(等价 --url,逗号分隔多个值;CLI 有值时不生效)。MCP 模式下作为工具未传 dir/url 入参时的默认数据源
MODO_CACHE_DIR 缓存目录(图片、远程数据),默认 Windows 为 %LOCALAPPDATA%\modao-mcp,macOS/Linux 为 ~/.cache/modao-mcp

数据源形态

支持三种输入(CLI 用 --dir/--url,MCP 工具调用用 dir/url 入参,形态一致):

  • 本地目录(一等)dir 指向已解压的离线包根目录,或其父目录(扫描含 extra/data.0.js 的子目录)。
  • 远程离线包url 指向内网静态服务器上的解压目录,或 zip 下载地址;会下载到本地缓存后再解析。
  • 分享链接url(或向后兼容写在 dir/--dir)识别为占位项目,不抓取数据,仅返回导出离线包的降级指引。

远程数据缓存于 MODO_CACHE_DIR(或系统默认缓存目录)下的 remote/。MCP 启动时会自动检查默认远程源的更新,工具调用首次使用某个 url 数据源时同样做一次检查(目录形态对比 updated_at,zip 对比 ETag/Last-Modified);运行期间可调用 refresh_projects 工具重新拉取,或在 CLI 使用 modao pull 检查并在有更新时拉取。

图片缓存

images 命令与 MCP 工具 get_page_image 不做整页合成渲染,只收集页面元素级图片:从包内 uploads7/images/ 按需复制到缓存目录,返回绝对路径。远程目录形态若本地未带图片,会按 uploads7/images/<file> 回源拉取并落盘;失败则跳过该图片。缓存根目录由 MODO_CACHE_DIR 控制。

整页截图(snapshot)

snapshot 命令与 MCP 工具 get_page_snapshot 用 Playwright 打开官方离线 HTML 播放器,按页面画板实际宽度截取整页长图 PNG:

  • 默认落盘 <缓存目录>/snapshots/<project>/<画布序>-<页序>-<页面名>.png(画布总览为 overview-<画布序>-<画布名>.png),序号 1 起零填充两位,目录按名排序即设计稿顺序;页面不在模型中(远程源宽容放行)时回退用页面 id。CLI 可用 --out 覆盖;返回值含 pathwidthheight
  • 数据源为远程目录形态(--url http://...)时一并返回 previewUrl(包根地址,可直接打开播放器);zip 与本地 --dir 源只返回 path(本地源截图期间会临时起一个仅绑定 127.0.0.1 的静态服务,进程退出即关闭)。
  • Playwright 为可选依赖:未安装时报错并提示安装,不做静默降级;托管 chromium 未下载时会自动回退本机 Chrome/Edge(channel 方式),无需 150MB 浏览器下载:
npm install playwright          # 未安装时
npx playwright install chromium # 可选:下载托管浏览器(无系统 Chrome/Edge 时)
  • 跳页采用官方播放器深链 ?view_mode=device&canvasId=<页面id> 直达目标页,并按画板自然尺寸(非模拟器缩放尺寸)输出 PNG。
  • 画布总览snapshot-canvas 命令(或 get_page_snapshotcanvas_id,来自 list_pagescanvasId,或 menu 命令输出的叶子画布 id)切换到播放器总览模式,一面长图截下该画布全部页面缩略图与页名——适合一图纵览多页结构。默认 2 倍像素输出,--zoom 1~4 调节;--clip x,y,w,h(相对墙左上 CSS 像素)可只截批注/文档区域。页面级 snapshot --zoom 同理。
  • 分片输出(读小字推荐):整墙长图送入读图模型会被降采样,批注小字必然不可读。--split 在同一次渲染内追加输出:总览 1 张(看结构)+ 按内容空白沟切的 N 张可读宽度分片(逐片读文字,无需手工估算 clip 坐标),并写 tiles.json 清单——每片带墙内 CSS 像素 clip 坐标与切法(gutter=刀口在空白沟,uniform=等宽退化切),可溯源、可定点复查。--split auto 按空白沟自适应片数(默认片宽 520 CSS px,--band 调节);--split <n> 强制片数;墙内容过密无沟可切时退化为等宽切并留 --overlap(默认 60 CSS px);沟内有内容贯穿(表格行线、白卡连续区——切开会把一张表/一张卡劈到两片)时不下刀,整块内容并入同一条分片(最宽 band+200 CSS px,超宽才等宽切);墙缘滚动条等过窄伪内容不参与切线。--out 此时为输出目录(默认 snapshots/<project>/split-<画布序>-<画布名>/);--skip-existing 在清单与文件齐全时直接复用不重截。与 --clip 互斥。
  • 画布 id 校验规则:id 在解析结果中时直接使用;不在时,远程目录源会放行并由播放器侧选中态校验(覆盖菜单中存在但解析缺失的画布),本地源则严格报错并列出可用画布。

典型工作流:从设计稿到需求文档(Agent 自主完成)

modao list --url http://intranet/pkg/                    # 1. 找到项目 id
modao menu <project> --url http://intranet/pkg/          # 2. 菜单顺序 + 全部画布 id(含解析缺失的)
modao snapshot-canvas <project> <canvasId> \
  --url http://intranet/pkg/ --zoom 3 \
  --split auto --out shots/<canvasId>/                   # 3. 总览 + 按空白沟分片 + tiles.json
# Agent 识读:先读总览看结构,再按 tiles.json 顺序逐片读文字;
# 个别没读清的行用 tiles.json 的 clip 坐标 --clip 定点复查

全程只需要 CLI 返回的信息:菜单给出顺序与 id,snapshot 返回 PNG 绝对路径与尺寸(分片模式附每片墙内坐标),无需了解墨刀文件结构,也无需人工估算裁剪坐标。

数据格式说明

离线包内 extra/data.0.js 为项目元信息,extra/data.1.js 为设计数据,核心是 window.hzv5.flpk 操作码序列:

  • v1(旧版):明文操作码数组;
  • v2(新版):gzip+base64 压缩块 + 明文增量更新。

解析器做操作码回放(I 定义元素 / A 更新属性 / B@ref-danli 动态组件画布 / @@T 外部引用跳过),用 rRBPK 索引区分用户画布与动态组件画布。flpk 是墨刀内部格式、非公开契约,解析器采用防御式解析:无法识别的操作码跳过并计数,不会崩溃。

本项目的 flpk 解析逻辑移植自 modao-exporter(MIT 许可证)的 src/parser/,特此致谢。本项目同样以 MIT 许可证发布。

开发

npm install
npm run build   # tsc → dist/
npm test        # vitest
npm run dev     # tsx 直接跑 src/index.ts(需 -- --dir <path> 或子命令)

项目结构:

modao-cli/
├── src/
│   ├── index.ts              # 入口:分发到 cli
│   ├── cli.ts                # cac 命令定义与分发
│   ├── config.ts             # configFromOptions(CLI 选项 + 环境变量)
│   ├── bootstrap.ts          # createSource / checkRemoteUpdates
│   ├── cli-output.ts         # 人类可读格式化
│   ├── mcp-command.ts        # mcp 子命令:stdio 启动│   ├── commands/             # list / dsl / search / images / pull
│   ├── model/                # Project/Canvas/Page/Element/Annotation/Asset 统一模型
│   ├── flpk/
│   │   ├── decode.ts         # flpk v1/v2 解包(gzip+base64 → 操作码行)
│   │   └── replay.ts         # 操作码回放 → 统一文档模型
│   ├── sources/
│   │   ├── source.ts         # Source 接口
│   │   ├── offline-package.ts# 本地离线包目录(惰性解析)
│   │   ├── remote-package.ts # 远程离线包目录 / zip 拉取与缓存
│   │   ├── share-link.ts     # 分享链接占位(降级指引,不抓取)
│   │   └── combined.ts       # 多数据源组合
│   ├── services/
│   │   ├── dsl.ts            # 文档模型 → 裁剪 DSL(json/yaml、depth 截断)
│   │   ├── index.ts          # 内存检索索引与打分
│   │   ├── assets.ts         # uploads7/images 资源读取与缓存目录落盘
│   │   └── pages.ts          # 页面查找辅助
│   └── mcp/
│       ├── server.ts         # McpServer 装配
│       ├── source-manager.ts # 工具调用 dir/url 入参 → 数据源解析与缓存
│       └── tools.ts          # tool 注册
└── test/                     # vitest + 手工构造的微型离线包 fixtures

License

MIT deeploop-ai

Keywords