Skip to content
dsh.fish
Bundle

dsh-draw2code

Human-AI collaborative prototyping for DSH, Codex and MCP agents, from product clarification to editable Excalidraw wireframes and verified frontend generation.

Source
guchang
stars
3 stars
License
Apache-2.0
Updated
Updated 4 days ago

Readme

# Draw2Code · 画码

中文 | [English](README.en.md)

面向 DSH、Codex 与其他 MCP Agent 的人机协作原型工具:先通过结构化提问把产品需求想清楚,再让 Agent 和用户在同一张 Excalidraw 画板上共同修改低保真原型,最后基于已经确认的画板生成并验收前端页面。

Draw2Code 使用一个共享 Core 和按需启动的本地 daemon。DSH 与 Codex 不互相依赖,但同时运行时会打开同一份工作区数据。

## 为什么需要 Draw2Code

Vibe Coding 很容易从一句模糊需求直接跳到代码,结果往往是页面范围没想清楚、用户手工删除的内容被 Agent 恢复,或者 Agent 声称已经画完但用户看不到结果。Draw2Code 把协作过程拆成四个边界明确的阶段:

1. **Create:澄清产品**
   - 当用户提出一个新产品想法时,`draw2code_create` 先提取已经明确的事实,再由 Agent 围绕场景、差异化、核心闭环和关键风险提出产品专属问题。
   - 每题先给产品判断,再提供有真实取舍的可点击选项;不会固定重复询问模块和页面,信息足够即停止,最多 10 题。可跳过单题、直接整理简报,也可在 ready 后只调整受影响的产品决策。
   - 工具把结构化 `PrototypeBrief` 确定性渲染成包含逐页结构、真实 mock 数据、交互关系和验收方式的完整项目简报;最后用一张页面范围确认卡明确列出将绘制的页面,用户确认前不会创建画板。
   - 视觉品牌、颜色和正式前端实现仍留到生成阶段。
2. **Open & Demonstrate:用户画给 Agent 看**
   - 用户可以直接访问固定本机入口 `http://127.0.0.1:64775/`;画码会从本机已登记工作区恢复,无需先从 Codex 建立连接。用户说“打开画码,我自己画一下”时,由独立的 `$draw2code-open` 快速入口只调用一次 `draw2code_open`,不加载 Create、Update、Generate、代表页复核或质量门禁;工具内部的短期定向连接只用于把当前任务的 workspace/board 精确绑定到当前标签页,随后回到可收藏的干净根地址。
   - 用户说“我画好了”后,Agent 先用 `draw2code_read` 读取并复述页面、组件和交互关系,再按用户指令继续修改或生成。
   - URL 就绪、daemon 启动和画布真正可见是三个不同状态;只有侧边栏实际显示后才报告“已经打开”。
3. **Update:共同画原型**
   - `draw2code_update action=write` 把语义化低保真页面写入 Excalidraw,用户可以直接拖动、删除、改字或添加便签;`action=review` 使用写入返回的 `reviewToken` 记录可见复核,不改画板 revision,也不发布新的 reveal。
   - Agent 更新前先读取当前画板索引;`draw2code_read` 默认只返回页面、关系、分层容量和当前 review/pending 状态,不把整板元素塞进上下文。需要内容时再按 `pageIds`、`elementIds`、区域或近期 revision 增量读取。已有 3 页以上画板的独立小改动不会被旧的首次代表页门禁拦截。
   - Create 会逐页给出核心任务、首屏信息、主操作和语义组件蓝图;3 个及以上页面返回结构化 `drawingPlan`,强制先生成代表页,复核通过后才生成其余页面。若 Agent 仍误提前提交其余页面,Update 会返回 `pendingUpdateId` 暂存该批 ops,复核后以 `action=commit_pending` 直接提交,避免整批 JSON 被丢弃和重新生成。
   - 单次 ops 默认限制为 500 项或 512 KiB,超出时在布局检查前返回 `reduce_batch_size`;这与完整画板容量分开治理。画板不再设置正常业务容量:默认 32 MiB 仅进入 large 提示,256 MiB 只作为异常输入保险丝,且可配置提高;元素异常保护同步提高到 50,000。磁盘缩进、内联资源、元素数与 gzip checkpoint / delta 历史分别报告。真正触发保险丝时返回 `archive_or_split_board`,不会误导 Agent 反复缩小同一批次。
4. **Generate:生成并验收前端**
   - `draw2code_generate` 开始前先用普通对话询问是否有参考风格图片;随后读取最新画板,让用户多选页面范围,并结合参考图或产品语义智能推荐整体视觉方向。
   - 原型不完整时先回画板修复;不会在 HTML 中偷偷补出未经确认的产品功能。
   - 原型定义产品事实,前端使用 Grid/Flex、内容流和响应式约束重新排版,不复制 Excalidraw 绝对坐标。
   - 页面生成后必须逐页截图,检查控制台、DOM、布局和核心流程;工具会读取 workspace 内的截图/DOM 快照、核对 SHA-256 与视口尺寸,并直接比较未选页面块哈希,证据门禁通过后才会报告完成。

## 主要能力

- DSH 右侧 `dsh-better-sidebar` 中的完整 Excalidraw 画布;
- 多画板创建、切换、删除、历史版本和导出;独立画码可在本机已明确注册的工作区之间切换,各工作区的画板仍原位保存;
- Agent 工具:`draw2code_list`、`draw2code_read`、`draw2code_create`、`draw2code_update`、`draw2code_generate`、`draw2code_open`;
- 用户手工编辑与 Agent 更新之间的三方合并和冲突确认;
- 成功更新后自动展开画码、激活目标画板,同一事件不会反复抢焦点;
- 无 Frame 新页面模型:普通矩形页面外框、外部页面标题、自由组件和不被裁切的手绘跨页箭头;旧命名 Frame 画板继续兼容;
- 原型质量门禁:文字高度、页面边界、底部导航、绑定文字、mock 数据、信息密度、视觉层级、点击区域和页面节奏;
- 内置 153 个产品原型素材,安装后无需单独下载素材库;
- Create 和 Generate 都支持可恢复的结构化流程,会话中断后不会重新询问已完成选择;
- 画板、项目 brief、生成设置和前端产物都保存在用户自己的工作区中。

## 系统要求

- 已安装 DeepSeek Harness,且 `dsh web` 可以正常启动;
- Node.js 22 或更高版本;
- DSH 宿主使用 `dsh-better-sidebar` 0.12.3 或更高版本;Codex 可独立安装,不需要 DSH。

## 在 Codex 中使用

首版通过本地 personal marketplace 安装,不提交公共 Plugin 目录。开发构建并把仓库的 Plugin 产物同步到 `~/plugins/draw2code` 后执行:

```bash
codex plugin add draw2code@personal
```

安装后新建 Codex 任务,使 Skills 与六个 MCP 工具进入新会话。用户不需要进入单独的 Plugin 页面或手输工具名:选择“打开 Draw2Code / 画码”快速入口,或直接说“打开画码”,只走单次 Open;“用 Draw2Code 帮我设计一个习惯追踪 App”“帮我画原型”等产品任务才进入综合工作流。普通“帮我做一个 App”不会自动进入 Draw2Code。

`draw2code_open` 在 MCP/Codex 中默认使用 `presentation=handoff`:MCP 连接初始化时会后台预热固定入口网关和按需启动的动态 worker。普通用户直接访问 `http://127.0.0.1:64775/` 即可;网关会为 loopback 浏览器自动建立 `HttpOnly`、`SameSite=Strict` 的内部会话,从本机登记表恢复最近工作区,并在写请求中校验同源 CSRF token。用户无需理解或手工维护 session。Open 工具仍会返回只含短期 `code` 的定向连接 URL,以保证多个 Codex 任务可分别定位自己的 workspace/board;浏览器完成定位后立即回到干净根地址,最终地址不保留 workspace 路径、画板名、token 或 code。网关或内部 worker 重启后刷新固定地址即可自动恢复。工具不注册会生成打不开卡片的静态 `openai/outputTemplate`;只有显式选择 `presentation=browser` 时才尝试启动外部浏览器。后续更新通过 WebSocket 刷新,断线时继续使用 revision polling,不反复打开窗口。`localhost` 会永久重定向到规范的 `127.0.0.1` 地址;端口被其他程序占用时会明确报错,不会静默换端口。

Draw2Code 把画板注册到 `dsh-better-sidebar` 提供的右侧栏中。DSH 当前只会自动启用用户直接安装的 bundle,不会自动启用另一个插件的传递依赖,因此下面两条安装命令都必须执行。

## 从 GitHub 安装

仓库提交了经过测试的 `dist/` 和 `lib/` 运行产物,因此普通用户不需要在本地构建:

```bash
# 1. 安装右侧栏基础插件
dsh plugin --profile web add dsh-better-sidebar

# 2. 安装 Draw2Code 稳定版
dsh plugin --profile web add github:guchang/draw2code#v0.5.0

# 3. 重启 dsh web;如果已经在运行,请先停止旧进程再启动
dsh web
```

如果是第一次初始化 DSH web profile,pnpm 可能会先暂停 `node-pty` 的原生构建,并在 `$DSH_HOME/profiles/web/pnpm-workspace.yaml`(默认 `~/.dsh/profiles/web/pnpm-workspace.yaml`)写入待确认项。按提示把它设为允许后重跑安装命令:

```yaml
allowBuilds:
  node-pty: true
```

这是 DSH 基础运行时的首次构建授权,不是 Draw2Code 额外执行的安装脚本。

刷新 DSH 页面后,在右侧栏的 `+` 菜单中选择“画码”。随后可以直接在对话中说:

```text
我想创建一个新的习惯追踪 App。
```

Agent 会先调用 `draw2code_create` 澄清需求;确认 brief 后创建独立画板并开始绘制。

### 从源码安装(开发者)

```bash
git clone https://github.com/guchang/draw2code.git
cd draw2code
npm ci
npm test

dsh plugin --profile web add dsh-better-sidebar
dsh plugin --profile web add link:$(pwd)
```

修改源码后运行 `npm run build`,再重启 `dsh web` 并刷新页面。

## 工作区数据

Draw2Code 只在当前宿主注册的工作区内创建以下内容:

```text
draw2code/
├── <画板名>.excalidraw.json   # 原型画板
├── .active-board.json         # 当前画板指针
├── .projects/                 # Create 项目 brief 与版本
├── .generations/              # Generate 可恢复会话
└── .generate-settings/        # 项目级视觉方向

draw2code-pages/
└── <画板名>/index.html        # 生成并验收的前端 Demo
```

这些运行数据已加入 `.gitignore`,不会进入 Draw2Code 源码仓库。

独立画码会记住 Codex、DSH 或其他宿主明确注册过的工作区,并在画板菜单中显示当前工作区及其他已经存在画板的工作区,包括名称、完整路径和画板数量;插件缓存和没有画板的空 root 不进入切换菜单。切换工作区前会先落盘当前待保存内容,再换取目标工作区的新短期凭据;原凭据不能直接读取其他工作区。Draw2Code 不扫描整台电脑,也不会自动复制、合并或迁移不同工作区的画板。

## 协作与安全边界

- 文件访问受 HostContext workspace 门禁限制,root 经 `realpath` 后不能越过已注册工作区;
- 固定入口网关与动态 worker 都只监听 loopback,descriptor 权限为 `0600`;固定入口为本机浏览器自动建立 `HttpOnly`、`SameSite=Strict` 会话,并以同源 CSRF token 保护写请求;Codex 定向连接码一次有效且短时过期,只用于任务/标签页隔离。网关代浏览器持有短期 workspace-scoped token,最终 URL 不暴露 root、board、token 或 code;独立画码切换工作区时仍必须经过已授权会话;
- DSH `/api/draw2code/*` 是隐藏 token 的同源 daemon 代理;
- `draw2code_update` 使用原子写入、revision 和回读验证,不直接修改未知文件;
- 涉及用户手工修改的危险覆盖会返回确认状态,不会静默写入;
- Draw2Code 不上传画板、brief 或生成页面到外部服务;
- 画布不设日常业务上限;默认 50,000 元素与 256 MiB 规范内容只作为异常输入保险丝,32 MiB 仅提示按页面读取,均可通过环境变量提高;单次 Agent ops 另设 500 项 / 512 KiB 传输预算。

异常保险丝与传输预算可独立调整:`DRAW2CODE_MAX_SCENE_BYTES`、`DRAW2CODE_SOFT_SCENE_BYTES`、`DRAW2CODE_MAX_ELEMENTS`、`DRAW2CODE_MAX_OPS_BYTES`、`DRAW2CODE_MAX_OPS`、`DRAW2CODE_MAX_VERSION_STORAGE_BYTES`。它们不是套餐或业务配额;日常大画板不会因为磁盘缩进或历史快照增长而突然不可写。

## 架构

```text
Codex Skill / DSH tools / future MCP clients
                    │
              Host Adapters
                    │
 stable loopback gateway · dynamic worker
                    │
          Draw2CodeRuntime.execute()
                    │
 Create state · Scene/Project store · CAS/merge · Generate gate
                    │
     existing workspace files (no migration)
```

DSH Host 构建到 `dist/index.js`;Codex stdio MCP、固定入口网关与动态 worker 分别构建到 `dist/draw2code-mcp.js`、`dist/draw2code-gateway.js`、`dist/draw2code-daemon.js`;共享浏览器画板构建到 `lib/canvas.html`。Plugin 清单位于 `.codex-plugin/plugin.json`,跨宿主约束只有一份真值:[workflow contract](references/workflow-contract.md)。

## 开发与验证

```bash
npm ci
npm run typecheck
npm test
npm run build
npm pack --dry-run
```

- 产品行为说明:[BDD.md](BDD.md)
- Generate 产品流程:[GENERATE_PRODUCT_FLOW.md](GENERATE_PRODUCT_FLOW.md)
- Gherkin 契约:[features/draw2code.feature](features/draw2code.feature)

## License

Draw2Code 代码采用 [Apache License 2.0](LICENSE)。内置 Excalidraw 素材继续遵循其上游 MIT License,作者与来源见 [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md)。

Install

dsh plugin --profile web add github:guchang/draw2code

Profile: web

  • This package builds from source on install. pnpm will ask you to allow its build script — that is permission to run the package’s code on your machine, outside the agent sandbox. Only allow sources you trust.
  • This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.
Source