dsh-design-studio 0.5.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +16 -6
- package/README.md +23 -6
- package/cordis.patch.yml +1 -1
- package/lib/browser.js +27 -5
- package/lib/client.js +380 -6
- package/lib/core.js +35 -9
- package/lib/handoff.js +555 -0
- package/lib/history.js +1 -1
- package/lib/index.js +258 -6
- package/lib/look.js +1 -1
- package/lib/picker.js +35 -0
- package/lib/serve.js +2 -1
- package/lib/system.js +1360 -0
- package/lib/tool.js +6 -3
- package/lib/tweaks.js +362 -0
- package/locale/tool/en.json +2 -2
- package/locale/tool/zh.json +2 -2
- package/package.json +1 -1
- package/skills/ui-design/SKILL.md +27 -1
package/README.en.md
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
>
|
|
20
20
|
> **Use it for:** "make a landing page", "design an app screen", "make a poster", "make a few slides".
|
|
21
21
|
>
|
|
22
|
-
> **Install:**
|
|
22
|
+
> **Install:** on the DSH Plugins page, click Add plugin and enter `dsh-design-studio` (an npm package), then restart DSH.
|
|
23
23
|
|
|
24
24
|
A design workbench for DSH (DeepSeek Harness), in the spirit of Google Stitch. When the model builds a web page, an app screen, a poster or a slide deck, the **Design Studio** tab in the right sidebar shows it live. Screens appear one by one on a canvas, each inside a phone or browser frame. When something looks off, click the element or drag over an area. The plugin turns your pick into text in the chat input. Add "make it orange" and send. The model edits the source, and the change flashes in the preview.
|
|
25
25
|
|
|
@@ -35,13 +35,17 @@ The exported showcase, straight from the plugin with no editing:
|
|
|
35
35
|
|
|
36
36
|
## Install
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
On the DSH Plugins page, click **Add plugin** and enter the package name:
|
|
39
|
+
|
|
40
40
|
```
|
|
41
|
+
dsh-design-studio
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
It is an npm package. When DSH installs by package name and can't reach the official npm registry, it falls back to the npmmirror mirror in China, so GitHub is never needed. You can also enter the release tarball `https://github.com/OrderG-X/dsh-design-studio/releases/latest/download/dsh-design-studio.tgz`, which needs GitHub access.
|
|
41
45
|
|
|
42
46
|
**Restart DSH** after installing, because client code is bundled when DSH starts. The plugin is listed as 设计工作台 / Design Studio on the Plugins page.
|
|
43
47
|
|
|
44
|
-
For development,
|
|
48
|
+
For development, enter the absolute path of a local checkout under **Add plugin**; it installs as a `link:`. Client changes still need a restart. `lib/picker.js` is served fresh on every request, so it doesn't.
|
|
45
49
|
|
|
46
50
|
## What it does
|
|
47
51
|
|
|
@@ -65,10 +69,13 @@ For development, link a local checkout with `dsh plugin --profile desktop add li
|
|
|
65
69
|
18. **Takes a reference image.** Drop an image onto the sidebar, paste it there, or use "Restyle from a reference…" in the tokens panel. The image is saved to `refs/` in the design folder (or the plugin cache when there is none). Its main colors with their shares, any small vivid accent, and whether it reads light or dark go into the chat input with the file path and an instruction to update `tokens.css` first.
|
|
66
70
|
19. **Checks the design.** The stethoscope button measures the rendered pages: text running off the screen, clipped, overflowing its box or overlapping; text contrast below WCAG (3:1 for large text, 4.5:1 for body); tap targets below 44 px in apps or 24 px on the web; tiny text; images that failed to load or are stretched; lines that are too long on web, email and tablet (about 45 Chinese characters or 90 letters); short labels and prices squeezed onto two lines; and too many font sizes. Every screen on the canvas is checked, and numbered markers appear on the problems in the preview (red for serious ones). Click an item to scroll to it. "Ask the model to fix" puts the list (screen, element, problem, by how much) into the chat input. After every model turn the sidebar measures again by itself: an open panel refreshes, and a closed one shows the number of remaining problems on its button (no number means all clear). Clicking an item brings its screen into view when the panel covers it or it is off the canvas. The model can run the check itself: in Design mode it calls `check_design` after writing or changing screens. The plugin opens each screen at real sizes in a hidden Chrome or Edge on this computer (several sizes at once, such as a short 375×667 and a large 430×932, and dark mode if asked). Besides the same list, it reports each screen's measurements (page height, top and bottom bar heights and their gap to the content) and catches four more problems: fixed top or bottom bars covering content or sitting too close to it (like the last row hidden under a tab bar; content merely scrolling under a bar is fine), script errors, stylesheets, scripts or fonts that failed to load, and links to screens that don't exist. Low-contrast and tiny text also name the CSS rule that sets them, with file and line. Serious problems (covered by a bar, overlapping, clipped or overflowing text, running off the screen, broken images, very low contrast) come with a close-up screenshot of that spot (up to 4, taken at the size and scroll position where it was found: the element outlined in red with the amount on it, the other one of an overlapping pair in orange, a covering bar made see-through, nearby problems sharing one picture), so the model doesn't need a separate screenshot. Overlapping text also gets a likely cause (negative margin, absolute positioning or a transform) with the rule's file and line, and overlaps with the same cause are listed as one. A repeat run says how many problems were fixed and how many are new (new ones are marked), and an incomplete run says so. The sidebar doesn't need to be open; without Chrome or Edge the sidebar measures instead.
|
|
67
71
|
20. **Lets the model look.** When the model wants to see the real rendering it calls `look_design`. The same hidden browser takes a screenshot at a given size (the top, scrolled to the bottom, the whole page in parts, or one element such as the tab bar, in light or dark) and hands the image to the model. No servers or screenshot scripts of its own.
|
|
72
|
+
21. **Learns your brand.** Give the model a website or a project folder ("follow our site's style") and it calls `extract_design_system`. The hidden browser opens the site and measures what it actually renders: page and surface colors, body and secondary text, brand and accent colors, borders, fonts and the type scale, radii, shadows, and how the primary and secondary buttons, inputs, cards and header look. A project folder is also scanned for CSS variables, hard-coded colors, Tailwind config and component libraries. The result is a full set of files in `~/.dsh/design-systems/<brand>/`: `tokens.css` (same variable names as the skill's starter), `components.css` (buttons, inputs, cards, text styles), a `components.html` specimen and a `DESIGN.md`, plus screenshots of the site and its components. Once it is the default, every new design starts from it: the model skips the "what feel?" question and varies the three directions in layout only. "Brand design systems…" in the tokens panel (or the More menu) lists them with a specimen thumbnail and swatches, and lets you set or clear the default, apply one to the current design, or enter an address to extract a new one.
|
|
73
|
+
22. **Tweaks.** The model picks the dimensions most worth trying for this design (spacing, radius, brand color, card layout…) and writes them to `tweaks.json`. The dial button shows them as sliders, color pickers and choices. Dragging updates every screen on the canvas at once (only CSS variables and `<html>` attributes on the live page; files are untouched). When you like it, "Write back" puts variables into the defaults in `tokens.css` and attributes onto each screen's `<html>`, with a version saved before and after; "Ask the model" has it apply the values and adjust related details. With no tweaks yet, one click asks the model for some, and `check_design` also reports tweaks that aren't wired up.
|
|
74
|
+
23. **Builds it as code.** The `</>` button asks what to build with (same as the existing project, React, Vue, Next.js or plain HTML), where to put the code and whether to do all screens or just this one, then "Start building". The model first calls `handoff_design`, which writes `handoff/HANDOFF.md` in the design folder (each screen's file, suggested route and links; the tokens; parts shared by several screens that should become components; scripts, forms and hover states; tweaks; images and fonts; steps and acceptance) plus top-to-bottom screenshots of every screen. It then builds one screen at a time, and after each one runs the dev server and calls `compare_design`: both pages are captured at the same size and compared pixel by pixel, returning a "design | built | difference" image with the worst areas boxed and numbered, which element each one is on both sides, and the overall difference. It moves on once that is under 3%.
|
|
68
75
|
|
|
69
76
|
On a narrow sidebar the less-used toolbar buttons move into a "More" menu.
|
|
70
77
|
|
|
71
|
-
`preview_page` takes `target` (a file path, port or URL), `kind` (web / app / tablet / poster / slides / email), and optionally `size` (such as `1080x1920`) and `screens` (dev-server routes to show side by side). `check_design` takes `screens` (which ones to measure), `sizes` (such as `["375x667","430x932"]`), `dark` and `images` (`false` for no screenshots). `look_design` takes `screens`, `size`, `at` (top / bottom / full), `selector` (just this element) and `dark`.
|
|
78
|
+
`preview_page` takes `target` (a file path, port or URL), `kind` (web / app / tablet / poster / slides / email), and optionally `size` (such as `1080x1920`) and `screens` (dev-server routes to show side by side). `check_design` takes `screens` (which ones to measure), `sizes` (such as `["375x667","430x932"]`), `dark` and `images` (`false` for no screenshots). `look_design` takes `screens`, `size`, `at` (top / bottom / full), `selector` (just this element) and `dark`. `extract_design_system` takes `sources` (1–5 URLs, project folders or HTML files), `name` and `default`. `handoff_design` takes `framework` (same / react / vue / next / html), `dest` and `screens`. `compare_design` takes `url` (the built page: a local address or port), `screen`, `size`, `at` (top / bottom) and `dark`.
|
|
72
79
|
|
|
73
80
|
## Design mode and switches
|
|
74
81
|
|
|
@@ -80,7 +87,7 @@ The plugin is split into parts, each with its own switch under DSH Plugins → D
|
|
|
80
87
|
| --- | --- | --- |
|
|
81
88
|
| Design Studio | The sidebar and preview servers (turning it off means not using the plugin) | On |
|
|
82
89
|
| Open previews automatically | While designing, a written HTML file or a started dev server opens in the sidebar; off, the sidebar only offers a "Preview …" button | On |
|
|
83
|
-
| Preview and check tools (other modes) | Standard, Creator and other modes can use `preview_page`, `check_design` and `
|
|
90
|
+
| Preview and check tools (other modes) | Standard, Creator and other modes can use `preview_page`, `check_design`, `look_design`, `extract_design_system`, `handoff_design` and `compare_design` | On |
|
|
84
91
|
| Design skill (other modes) | Standard, Creator and other modes can load the `ui-design` skill | On |
|
|
85
92
|
| Design mode | The Design entry in the mode menu | On |
|
|
86
93
|
|
|
@@ -108,6 +115,9 @@ node test/test-history.mjs
|
|
|
108
115
|
node test/test-phone.mjs
|
|
109
116
|
node test/test-doc.mjs # PDF and PowerPoint export
|
|
110
117
|
node test/test-look.mjs # check_design / look_design (the real-browser part needs Chrome or Edge)
|
|
118
|
+
node test/test-system.mjs # brand design systems (the real-browser part needs Chrome or Edge)
|
|
119
|
+
node test/test-tweaks.mjs # tweaks: tweaks.json, write-back (every top-level copy of a variable), wiring check, live page
|
|
120
|
+
node test/test-handoff.mjs # build as code: handoff note and screenshots, default destination, symlink guards, lossless pixel compare (inner scroll areas, data-theme dark, redirects off localhost blocked)
|
|
111
121
|
node e2e/check-page.mjs # design check in headless Chrome
|
|
112
122
|
node e2e/e2e-studio.mjs # end to end: a throwaway DSH from npm, a fake model and headless Chrome
|
|
113
123
|
```
|
package/README.md
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
>
|
|
20
20
|
> **什么时候用**:「做个落地页」「设计一个 App 界面」「做张海报」「做几页幻灯片」。新会话可以直接选「设计模式」。
|
|
21
21
|
>
|
|
22
|
-
>
|
|
22
|
+
> **安装**:DSH「插件」页 →「添加插件」,填 `dsh-design-studio`(npm 包,连不上 npm 会自动换国内镜像),重启 DSH。
|
|
23
23
|
|
|
24
24
|
让 DSH(DeepSeek Harness)做界面设计时像 Google Stitch / Claude Code 桌面端那样:模型做网页、App 界面、海报、幻灯片时,右侧栏「设计工作台」实时显示——一屏一屏生成出来,在画布上并排摆好,套上手机 / 浏览器外框;看到哪里不对,点一下那个元素、或拖出一块区域,它就整理成一段文字放进输入框,补一句「改成橙色」发出去,模型照着源码改,改过的地方在预览里闪一下。
|
|
25
25
|
|
|
@@ -35,13 +35,17 @@
|
|
|
35
35
|
|
|
36
36
|
## 安装
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
在 DSH「插件」页点「添加插件」,填包名:
|
|
39
|
+
|
|
40
40
|
```
|
|
41
|
+
dsh-design-studio
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
这是 npm 包:按包名装时,DSH 连不上 npm 官方源会自动改用国内镜像(npmmirror),不经过 GitHub。也可以填发布包地址 `https://github.com/OrderG-X/dsh-design-studio/releases/latest/download/dsh-design-studio.tgz`,那样要能连上 GitHub。
|
|
41
45
|
|
|
42
46
|
装完**重启 DSH**(客户端代码在 DSH 启动时打包)。DSH「插件」页里显示为「设计工作台」。
|
|
43
47
|
|
|
44
|
-
|
|
48
|
+
开发时可以直接链到本地目录:在「添加插件」里填本仓库的绝对路径,装上的是 `link:`,改了客户端代码同样要重启(`lib/picker.js` 每次现给,不用重启)。
|
|
45
49
|
|
|
46
50
|
## 用起来是什么样
|
|
47
51
|
|
|
@@ -83,10 +87,13 @@ dsh plugin add https://github.com/OrderG-X/dsh-design-studio/releases/latest/dow
|
|
|
83
87
|
23. **风格卡**:九套现成风格——极简白、温暖手作、杂志编辑、深色高级、活泼年轻、清新自然、专业科技、玻璃质感、柔和立体,每张卡是一套配色、字体、圆角、阴影的小样。还没开始设计时,空白页上点一张,输入框里写好〔风格〕和整套配色,再补一句要做什么;已经有设计了,在设计规范面板点「换个风格…」,模型先改 `tokens.css`,再把写死的颜色换掉,版式和文字不动,改完自己体检一遍。
|
|
84
88
|
24. **远程也能看**:从手机(dsh-mobile 走外网)或别的电脑打开 DSH 网页时,电脑本机的预览端口那边连不上。本地 HTML 做的设计,插件把一屏连同样式、脚本、图片打成一份传过去,放进沙盒 iframe 显示,选择、改字、调样式、体检、导出照样能用;页面里点跳转就换到那一屏,文件改了跟着刷新(只刷用到这个文件的屏)。开发服务器的页面打包不了,还是只给一句说明。
|
|
85
89
|
25. **模型自己看图**:模型想看真实渲染的样子时调 `look_design`:同样用那个看不见的浏览器,按指定尺寸截一屏——顶上一屏、滚到底、整页分几段,或者只截某个元素(比如底栏),也能截深色——图直接交给模型看。不用自己起服务器、写截图脚本。
|
|
90
|
+
26. **品牌设计系统**:给一个网站地址或项目文件夹(「照我们官网的风格」),模型调 `extract_design_system`,插件用看不见的浏览器打开网页量真实渲染的样式——底色、正文和次要文字、主色、点睛色、边框,字体和字号阶梯,圆角、阴影,主按钮 / 次按钮 / 输入框 / 卡片 / 顶栏的样子——项目文件夹还会扫 CSS 变量、写死的颜色、Tailwind 配置和组件库。提出来的是一整套文件:`tokens.css`(和技能起手模板同一套变量名)、`components.css`(按钮、输入框、卡片、文字样式)、`components.html` 样张、`DESIGN.md` 说明,连同网站和组件截图存进 `~/.dsh/design-systems/<品牌>/`。设成默认后,以后每次做新设计模型都先复制这一套,不再问「想要什么感觉」,三个方向只在版式上拉开。右侧栏设计规范面板里「品牌设计系统…」(窄的时候在「更多」里)列出所有套,带样张缩略图和色块,能设默认、取消默认、一键套用到当前设计,也能直接填地址让模型提一套。
|
|
91
|
+
27. **调节滑块**:模型给这套设计挑几个最值得试的维度(留白疏密、圆角、主色、卡片排法……)写进 `tweaks.json`,工具栏旋钮按钮列成滑块、取色、几选一;拖的时候画布上每一屏一起变(只改页面上的 CSS 变量和 `<html>` 上的属性,不动文件),满意了「写回文件」(变量写进 `tokens.css` 的默认值,属性写到每屏的 `<html>` 上,改前改后各存一版),或「交给模型」照这几个值改、顺手协调相关的地方。还没有滑块时一键让模型做几个;`check_design` 会顺带查滑块有没有真接上(变量没人用、没有默认值、选项没有对应的样式)。
|
|
92
|
+
28. **转成代码**:工具栏 `</>` 按钮,选用什么做(跟现有项目一样 / React / Vue / Next.js / 纯 HTML)、代码放哪、转全部还是这一屏,点「开始转成代码」。模型先调 `handoff_design`:插件在设计目录写一份 `handoff/HANDOFF.md`(每屏的文件、建议路由、跳去哪,设计变量,几屏共用该抽成组件的部分,脚本 / 表单 / 悬停这些交互,滑块,图片字体,做法和验收)和每屏从上到下的截图;模型照着一屏一屏写,每屏写完把开发服务器跑起来调 `compare_design`:同样尺寸各截一张逐像素比,回一张「设计稿 | 做出来的 | 差异」拼图,差得多的地方红框标号、写明两边分别是哪个元素,差异降到 3% 以下再做下一屏。
|
|
86
93
|
|
|
87
94
|
工具栏还有:地址(点一下能改,输文件路径 / 端口 / localhost 地址都行)、刷新、在浏览器里打开。右侧栏拉窄时,不常用的几个按钮收进「更多」菜单。会话标题栏右边有个「设计工作台」按钮,随时打开。DSH 重启后,每个会话接着预览原来的页面(类型、视图也记着)。
|
|
88
95
|
|
|
89
|
-
`preview_page` 工具的参数:`target`(文件路径 / 端口 / 地址)、`kind`(web / app / tablet / poster / slides / email)、`size`(如 `1080x1920`,可选)、`screens`(开发服务器上并排看的几个路由,可选)。`check_design`:`screens`(只量哪几屏)、`sizes`(如 `["375x667","430x932"]`)、`dark`、`images`(`false` 不附截图)。`look_design`:`screens`、`size`、`at`(top / bottom / full)、`selector`(只截这个元素)、`dark`。
|
|
96
|
+
`preview_page` 工具的参数:`target`(文件路径 / 端口 / 地址)、`kind`(web / app / tablet / poster / slides / email)、`size`(如 `1080x1920`,可选)、`screens`(开发服务器上并排看的几个路由,可选)。`check_design`:`screens`(只量哪几屏)、`sizes`(如 `["375x667","430x932"]`)、`dark`、`images`(`false` 不附截图)。`look_design`:`screens`、`size`、`at`(top / bottom / full)、`selector`(只截这个元素)、`dark`。`extract_design_system`:`sources`(网址 / 项目文件夹 / HTML 文件,1–5 个)、`name`、`default`。`handoff_design`:`framework`(same / react / vue / next / html)、`dest`、`screens`。`compare_design`:`url`(做出来的页面,本机地址或端口)、`screen`、`size`、`at`(top / bottom)、`dark`。
|
|
90
97
|
|
|
91
98
|
## 设计模式和开关
|
|
92
99
|
|
|
@@ -98,7 +105,7 @@ dsh plugin add https://github.com/OrderG-X/dsh-design-studio/releases/latest/dow
|
|
|
98
105
|
| --- | --- | --- |
|
|
99
106
|
| 设计工作台 | 右侧栏和预览服务器(关掉就等于不用这个插件) | 开 |
|
|
100
107
|
| 自动打开预览 | 做设计时写了 HTML、起了开发服务器,右侧自动打开;关掉后只在右侧栏给一个「预览刚写的 …」按钮 | 开 |
|
|
101
|
-
| 预览和体检工具(其他模式) | 标准、创造等模式也能用 `preview_page`、`check_design` 和 `
|
|
108
|
+
| 预览和体检工具(其他模式) | 标准、创造等模式也能用 `preview_page`、`check_design`、`look_design`、`extract_design_system`、`handoff_design` 和 `compare_design` | 开 |
|
|
102
109
|
| 设计技能(其他模式) | 标准、创造等模式也能加载 `ui-design` 技能 | 开 |
|
|
103
110
|
| 设计模式 | 模式菜单里的「设计模式」 | 开 |
|
|
104
111
|
|
|
@@ -138,7 +145,11 @@ dsh plugin add https://github.com/OrderG-X/dsh-design-studio/releases/latest/dow
|
|
|
138
145
|
/dsh-design-studio/api/edit|ref 预览里改的字写回 HTML、存参考图
|
|
139
146
|
/dsh-design-studio/api/style|locate 调样式:写进元素在源码里的 style 属性;按规则找回源文件和行号
|
|
140
147
|
/dsh-design-studio/api/bundle 远程看:一屏连同样式、图片打成一份(放进沙盒 iframe)
|
|
148
|
+
/dsh-design-studio/api/tweak 调节滑块写回文件(tokens.css 默认值、每屏 <html> 属性、tweaks.json)
|
|
149
|
+
/dsh-design-studio/api/systems|systhumb 品牌设计系统库:列出来、设 / 取消默认、样张缩略图
|
|
150
|
+
/dsh-design-studio/api/project 转成代码前:会话目录是不是前端项目、建议放哪
|
|
141
151
|
check_design / look_design → 无头浏览器(browser.js)按真实尺寸开页面,picker 里量、截图(look.js)
|
|
152
|
+
extract_design_system → system.js;handoff_design / compare_design → handoff.js
|
|
142
153
|
页面 picker.js 注入到 HTML:悬停框选、点选 / 拖选、屏间链接、演示时接住跳转、就地改字、postMessage 回右侧栏、改动后刷新
|
|
143
154
|
客户端 右侧栏标签页(sidebarRightTabs)+ 标题栏按钮(session.header.utilities)
|
|
144
155
|
```
|
|
@@ -150,6 +161,9 @@ dsh plugin add https://github.com/OrderG-X/dsh-design-studio/releases/latest/dow
|
|
|
150
161
|
- `lib/serve.js` —— 预览服务器:静态文件 / 代理 / 改动推送 / 注入(picker 和一段收集页面报错、没载到的资源的小脚本)
|
|
151
162
|
- `lib/browser.js` —— 无头浏览器:找本机的 Chrome / Edge / Chromium / Brave,`--remote-debugging-pipe` 说话(不开端口),临时用户目录,闲置自己关
|
|
152
163
|
- `lib/look.js` —— `check_design` / `look_design` 的量和截:挑屏、解析尺寸、每种尺寸开一页量问题和测量数字、挑严重问题截局部图、截顶上 / 滚到底 / 整页分段 / 元素,整理成交给模型的字
|
|
164
|
+
- `lib/system.js` —— 品牌设计系统:在网页里收集颜色 / 字体 / 圆角 / 阴影 / 组件,扫项目文件夹,按 OKLab 聚类定角色(对比度够不够也算),写 tokens.css / components.css / 样张 / DESIGN.md,库(默认那套)和给技能补的一节
|
|
165
|
+
- `lib/tweaks.js` —— 调节滑块:读 tweaks.json、写回(:root 上的默认值、<html> 属性)、查有没有接上
|
|
166
|
+
- `lib/handoff.js` —— 转成代码:认现有项目、交接说明和截图、compare_design 的逐像素比(在无头浏览器里算差异、找成片的差异块、拼图)
|
|
153
167
|
- `lib/bundle.js` —— 远程看:把一屏的样式表(含 `@import`)、脚本、图片、字体内联成一份 HTML,放 `<base>` 和 picker
|
|
154
168
|
- `lib/phone.js` —— 手机上看:局域网入口(口令换 Cookie、转发到预览服务器、补 viewport、跟随跳屏、WebSocket 透传、闲置自动关)
|
|
155
169
|
- `lib/qr.js` —— 二维码生成(字节模式、纠错 M、版本 1–10,不引第三方库)
|
|
@@ -171,6 +185,9 @@ node test/test-bundle.mjs # 远程看的打包:样式表 / @import / url() /
|
|
|
171
185
|
node test/test-phone.mjs # 手机上看:二维码结构、挑网卡、补 viewport、口令换 Cookie、没口令 / Host 不对 403、转发、跟随跳屏、WebSocket、停止、闲置自动关
|
|
172
186
|
node test/test-doc.mjs # PDF / PPT:JPEG 尺寸、PDF 结构和交叉引用、PPT 的各个部件(解压校验 CRC)、幻灯片比例和居中、接口存进 exports/、重名加序号、坏输入拒掉
|
|
173
187
|
node test/test-look.mjs # check_design / look_design:挑屏、尺寸、整理给模型的字;假浏览器走完工具和附图;本机有 Chrome / Edge 时真开页面:底栏压住最后一行(矮屏报、大屏不报)、App 壳里的滚动区、脚本报错、缺样式表、截图尺寸、元素裁剪、深色、调样式每项由哪条规则决定、严重问题附图(底栏压住、App 壳、叠字,浅色深色)
|
|
188
|
+
node test/test-system.mjs # 品牌设计系统:颜色解析和对比度、扫项目、定角色、写出来的文件、库和默认、给技能补的一节;有 Chrome / Edge 时真从一个网页提一套(品牌名、角色、字体、圆角、组件、截图、再提覆盖)
|
|
189
|
+
node test/test-tweaks.mjs # 调节滑块:读 tweaks.json(写错了怎么说)、值规整、写回 tokens.css(同一个变量写了几遍都改)/ <html> / tweaks.json、体检、写回走版本;真浏览器里拖了页面真变、撤掉还原
|
|
190
|
+
node test/test-handoff.mjs # 转成代码:认项目、路由、共用部分、只比本机地址、代码默认放哪(不放进设计目录,软链接别名也认)、交接包不跟软链接写到外面、交接说明的各节;真浏览器:交接包截图、一样的页面差异 < 1%、改过的页面标出差在哪、淡灰对白也算差异、滚到底连里面能滚的区域、data-theme 深色两边都切、本机地址跳到外网被拦下
|
|
174
191
|
node e2e/check-page.mjs # 设计体检(要本机 Chrome):十二类问题都查得出、该放过的放过(省略号、动画中的半透明字、深色页面、限宽的段落、object-fit 的图、正文里跟着折行的字…),干净的页面零问题;加 --dir <设计目录> 拿真设计稿试
|
|
175
192
|
node e2e/e2e-studio.mjs # 真机(要本机 Chrome,会从 npm 装一个临时 DSH):假模型调 preview_page 开三屏 App;干完一轮按钮上标出问题数,体检查出埋的问题、交给模型修、改完自动再量;面板开着时模型改坏别的屏,面板自己刷新、那屏挪出来;模型调 `check_design` 拿回清单和严重问题的局部截图;模型调 `look_design` 拿回一张真实渲染的图;导出的 PDF / PPT 里跳转能点;调样式拖滑块、写回、交给模型;换风格;换个地址打开(像手机走外网)时预览打包传过来、点得动、跟着改动刷新
|
|
176
193
|
```
|
package/cordis.patch.yml
CHANGED
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
config:
|
|
28
28
|
prefix: |-
|
|
29
29
|
You are a design agent powered by the {{model}} model. You design user interfaces and visuals — web pages, app and tablet screens, posters and social images, slides, emails, components — and build them as real HTML/CSS, or inside the user's front-end project.
|
|
30
|
-
Before designing, load the ui-design skill and follow its process and self-check list. For a new design, first ask the two or three questions that matter and show three clearly different directions of one key screen, as the skill describes, unless the user asked you to just build it. Once the first HTML file is written, or a dev server is up, call preview_page so the user can watch the design live in the Design Studio sidebar; later edits refresh on their own. After writing or changing screens, call check_design to measure them at real sizes and fix what it lists, and call look_design to see real screenshots for the visual pass; do not build your own inspection pages, servers or browser screenshots. Stop after at most three measure-and-fix rounds and tell the user what is left. When a message starts with an element or region the user selected in the preview, or with a design-check list, change exactly those parts in the source.
|
|
30
|
+
Before designing, load the ui-design skill and follow its process and self-check list. For a new design, first ask the two or three questions that matter and show three clearly different directions of one key screen, as the skill describes, unless the user asked you to just build it. Once the first HTML file is written, or a dev server is up, call preview_page so the user can watch the design live in the Design Studio sidebar; later edits refresh on their own. After writing or changing screens, call check_design to measure them at real sizes and fix what it lists, and call look_design to see real screenshots for the visual pass; do not build your own inspection pages, servers or browser screenshots. Stop after at most three measure-and-fix rounds and tell the user what is left. When a message starts with an element or region the user selected in the preview, or with a design-check list, change exactly those parts in the source. If the user points you at their own website or project as the brand to follow, call extract_design_system; when the ui-design skill names a default design system, build new designs on its tokens.css and components.css. When a message asks to turn the design into real code, call handoff_design, follow its HANDOFF.md, and after each screen call compare_design until it matches. If the user only wants an answer shown as a page (a comparison, table, checklist, chart or calculator) and the show_page tool is available, call show_page instead of this design process.
|
|
31
31
|
- id: agent-instructions
|
|
32
32
|
name: '@deepseek-ai/dsh-agent-instructions'
|
|
33
33
|
config:
|
package/lib/browser.js
CHANGED
|
@@ -116,6 +116,13 @@ export function createBrowser({ bin = findBrowser(), log = () => {}, idleMs = ID
|
|
|
116
116
|
return p
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
+
/** 一直听某个事件(不像 once 只等一次);返回取消的函数 */
|
|
120
|
+
function listen(method, sessionId, fn) {
|
|
121
|
+
const w = { method, sessionId, done: (v) => { if (v) fn(v) } }
|
|
122
|
+
waiters.add(w)
|
|
123
|
+
return () => waiters.delete(w)
|
|
124
|
+
}
|
|
125
|
+
|
|
119
126
|
// 宿主进程退出时浏览器来不及报「退出了」:那时同步删掉临时目录
|
|
120
127
|
let onHostExit = null
|
|
121
128
|
function cleanup() {
|
|
@@ -197,27 +204,40 @@ export function createBrowser({ bin = findBrowser(), log = () => {}, idleMs = ID
|
|
|
197
204
|
/**
|
|
198
205
|
* 开一个 w×h 的页面载入 url,fn(page) 里量 / 截图,完了关掉。
|
|
199
206
|
* page.eval(表达式):在页面里算(Promise 会等),返回 JSON 值
|
|
200
|
-
* page.shot({ clip }):截视口;clip({ x, y, width, height },CSS 像素,按整页坐标 = 视口位置 + 滚动距离)只截那一块 → JPEG Buffer
|
|
207
|
+
* page.shot({ clip, format }):截视口;clip({ x, y, width, height },CSS 像素,按整页坐标 = 视口位置 + 滚动距离)只截那一块 → JPEG Buffer(format: 'png' 无损)
|
|
208
|
+
* allow(网址):给了就只让它说行的页面载入(主页面、iframe,连跳转、脚本改地址都算),别的拦下,记在 page.blocked
|
|
201
209
|
*/
|
|
202
|
-
async function withPage({ url, w, h, scale = 1, dark = false }, fn) {
|
|
210
|
+
async function withPage({ url, w, h, scale = 1, dark = false, allow = null }, fn) {
|
|
203
211
|
if (dead) throw new Error('browser closed')
|
|
204
212
|
if (open >= MAX_PAGES) await new Promise((r) => queue.push(r))
|
|
205
213
|
if (dead) throw new Error('browser closed')
|
|
206
214
|
open++
|
|
207
215
|
clearTimeout(idle)
|
|
208
216
|
let targetId = ''
|
|
217
|
+
let unlisten = null
|
|
218
|
+
const blocked = []
|
|
209
219
|
try {
|
|
210
220
|
await start()
|
|
211
221
|
;({ targetId } = await call('Target.createTarget', { url: 'about:blank' }))
|
|
212
222
|
const { sessionId } = await call('Target.attachToTarget', { targetId, flatten: true })
|
|
213
223
|
const c = (m, p) => call(m, p, sessionId)
|
|
224
|
+
if (allow) {
|
|
225
|
+
// 每个页面请求(包括 302 之后的每一跳)先停下来问一遍,不行就当被拦了
|
|
226
|
+
unlisten = listen('Fetch.requestPaused', sessionId, (q) => {
|
|
227
|
+
let ok = false
|
|
228
|
+
try { ok = !!allow(q.request.url) } catch { ok = false }
|
|
229
|
+
if (!ok && blocked.length < 10) blocked.push(q.request.url)
|
|
230
|
+
c(ok ? 'Fetch.continueRequest' : 'Fetch.failRequest', ok ? { requestId: q.requestId } : { requestId: q.requestId, errorReason: 'BlockedByClient' }).catch(() => {})
|
|
231
|
+
})
|
|
232
|
+
await c('Fetch.enable', { patterns: [{ urlPattern: '*', resourceType: 'Document', requestStage: 'Request' }] })
|
|
233
|
+
}
|
|
214
234
|
await c('Page.enable')
|
|
215
235
|
// 和右侧栏里一样按桌面方式排版(mobile: false):页面宽就是 w,不看 <meta viewport>
|
|
216
236
|
await c('Emulation.setDeviceMetricsOverride', { width: w, height: h, deviceScaleFactor: scale, mobile: false })
|
|
217
237
|
await c('Emulation.setEmulatedMedia', { features: [{ name: 'prefers-color-scheme', value: dark ? 'dark' : 'light' }, { name: 'prefers-reduced-motion', value: 'reduce' }] })
|
|
218
238
|
const loaded = once('Page.loadEventFired', sessionId, LOAD_MS)
|
|
219
239
|
const nav = await c('Page.navigate', { url })
|
|
220
|
-
if (nav.errorText) throw new Error(nav.errorText)
|
|
240
|
+
if (nav.errorText) throw new Error(blocked.length ? `不是允许的地址,没打开:${blocked[0].slice(0, 120)}` : nav.errorText)
|
|
221
241
|
await loaded
|
|
222
242
|
const page = {
|
|
223
243
|
eval: async (expression) => {
|
|
@@ -225,13 +245,15 @@ export function createBrowser({ bin = findBrowser(), log = () => {}, idleMs = ID
|
|
|
225
245
|
if (r.exceptionDetails) throw new Error((r.exceptionDetails.exception && r.exceptionDetails.exception.description) || r.exceptionDetails.text || 'eval failed')
|
|
226
246
|
return r.result ? r.result.value : undefined
|
|
227
247
|
},
|
|
228
|
-
shot: async ({ clip, quality = 82 } = {}) => {
|
|
229
|
-
const r = await c('Page.captureScreenshot', { format
|
|
248
|
+
shot: async ({ clip, quality = 82, format = 'jpeg' } = {}) => {
|
|
249
|
+
const r = await c('Page.captureScreenshot', { format, ...(format === 'jpeg' ? { quality } : {}), ...(clip ? { clip: { ...clip, scale: 1 } } : {}) })
|
|
230
250
|
return Buffer.from(r.data, 'base64')
|
|
231
251
|
},
|
|
252
|
+
blocked,
|
|
232
253
|
}
|
|
233
254
|
return await fn(page)
|
|
234
255
|
} finally {
|
|
256
|
+
if (unlisten) unlisten()
|
|
235
257
|
if (targetId && proc) call('Target.closeTarget', { targetId }).catch(() => {})
|
|
236
258
|
open--
|
|
237
259
|
const next = queue.shift()
|