dsh-design-studio 0.3.2 → 0.4.0
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 +26 -0
- package/README.md +30 -3
- package/cordis.patch.yml +144 -0
- package/lib/auto.js +14 -0
- package/lib/core.js +23 -7
- package/lib/index.js +76 -68
- package/lib/preset.js +5 -0
- package/lib/skill.js +17 -0
- package/lib/tool.js +12 -0
- package/locale/auto/en.json +6 -0
- package/locale/auto/zh.json +6 -0
- package/locale/preset/en.json +6 -0
- package/locale/preset/zh.json +6 -0
- package/locale/skill/en.json +6 -0
- package/locale/skill/zh.json +6 -0
- package/locale/tool/en.json +6 -0
- package/locale/tool/zh.json +6 -0
- package/package.json +16 -1
package/README.en.md
CHANGED
|
@@ -15,6 +15,12 @@
|
|
|
15
15
|
|
|
16
16
|
</div>
|
|
17
17
|
|
|
18
|
+
> **What it is:** a DeepSeek Harness (DSH) plugin that shows the model's web pages, app screens, posters and slides live on a canvas in the right sidebar, in phone or browser frames. Click an element or drag a region, add a sentence, and the model edits it. Versions are saved every turn; export showcase images or preview on a phone.
|
|
19
|
+
>
|
|
20
|
+
> **Use it for:** "make a landing page", "design an app screen", "make a poster", "make a few slides".
|
|
21
|
+
>
|
|
22
|
+
> **Install:** `dsh plugin add https://github.com/OrderG-X/dsh-design-studio/releases/latest/download/dsh-design-studio.tgz`, then restart DSH.
|
|
23
|
+
|
|
18
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.
|
|
19
25
|
|
|
20
26
|

|
|
@@ -62,6 +68,22 @@ On a narrow sidebar the less-used toolbar buttons move into a "More" menu.
|
|
|
62
68
|
|
|
63
69
|
`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).
|
|
64
70
|
|
|
71
|
+
## Design mode and switches
|
|
72
|
+
|
|
73
|
+
New sessions get a **Design** mode (shown as 设计模式) in the mode menu: all of Standard mode's tools plus the design skill and sidebar previews, with a design-focused persona. Pick it for design work; Standard, Creator and other modes keep these features too.
|
|
74
|
+
|
|
75
|
+
The plugin is split into parts, each with its own switch under DSH Plugins → Design Studio. Changes apply right away, no restart:
|
|
76
|
+
|
|
77
|
+
| Part | What it does | Default |
|
|
78
|
+
| --- | --- | --- |
|
|
79
|
+
| Design Studio | The sidebar and preview servers (turning it off means not using the plugin) | On |
|
|
80
|
+
| 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 |
|
|
81
|
+
| Preview tool (other modes) | Standard, Creator and other modes can use `preview_page` | On |
|
|
82
|
+
| Design skill (other modes) | Standard, Creator and other modes can load the `ui-design` skill | On |
|
|
83
|
+
| Design mode | The Design entry in the mode menu | On |
|
|
84
|
+
|
|
85
|
+
To design only in Design mode and keep other modes clean, turn off the two "(other modes)" switches. Design mode carries its own tool and skill and ignores them.
|
|
86
|
+
|
|
65
87
|
## Security
|
|
66
88
|
|
|
67
89
|
Each preview gets its own random `127.0.0.1` port, which is a different origin from DSH.
|
|
@@ -84,6 +106,10 @@ node test/test-history.mjs
|
|
|
84
106
|
node test/test-phone.mjs
|
|
85
107
|
```
|
|
86
108
|
|
|
109
|
+
## Feedback
|
|
110
|
+
|
|
111
|
+
Found a bug or want a feature? [Open an issue](https://github.com/OrderG-X/dsh-design-studio/issues/new/choose). Including your DSH and plugin versions helps a lot.
|
|
112
|
+
|
|
87
113
|
## License
|
|
88
114
|
|
|
89
115
|
MIT
|
package/README.md
CHANGED
|
@@ -15,6 +15,12 @@
|
|
|
15
15
|
|
|
16
16
|
</div>
|
|
17
17
|
|
|
18
|
+
> **一句话**:DeepSeek Harness(DSH)插件,模型做网页、App 界面、海报、幻灯片时,右侧栏画布实时显示每一屏,套上手机 / 浏览器外框;点一下元素或框一块区域,补一句话就改。每轮自动存版本,能导出展示图、手机扫码看。
|
|
19
|
+
>
|
|
20
|
+
> **什么时候用**:「做个落地页」「设计一个 App 界面」「做张海报」「做几页幻灯片」。新会话可以直接选「设计模式」。
|
|
21
|
+
>
|
|
22
|
+
> **安装**:`dsh plugin add https://github.com/OrderG-X/dsh-design-studio/releases/latest/download/dsh-design-studio.tgz`,重启 DSH。
|
|
23
|
+
|
|
18
24
|
让 DSH(DeepSeek Harness)做界面设计时像 Google Stitch / Claude Code 桌面端那样:模型做网页、App 界面、海报、幻灯片时,右侧栏「设计工作台」实时显示——一屏一屏生成出来,在画布上并排摆好,套上手机 / 浏览器外框;看到哪里不对,点一下那个元素、或拖出一块区域,它就整理成一段文字放进输入框,补一句「改成橙色」发出去,模型照着源码改,改过的地方在预览里闪一下。
|
|
19
25
|
|
|
20
26
|

|
|
@@ -77,6 +83,22 @@ dsh plugin add https://github.com/OrderG-X/dsh-design-studio/releases/latest/dow
|
|
|
77
83
|
|
|
78
84
|
`preview_page` 工具的参数:`target`(文件路径 / 端口 / 地址)、`kind`(web / app / tablet / poster / slides / email)、`size`(如 `1080x1920`,可选)、`screens`(开发服务器上并排看的几个路由,可选)。
|
|
79
85
|
|
|
86
|
+
## 设计模式和开关
|
|
87
|
+
|
|
88
|
+
新会话的模式菜单里多了一个「设计模式」:标准模式的全部工具,加上设计技能和右侧工作台的预览,人设换成做设计的。做界面时选它;标准、创造等模式照常能用这些功能。
|
|
89
|
+
|
|
90
|
+
插件拆成几个组件,DSH「插件」→「设计工作台」里每个都能单独开关,马上生效,不用重启:
|
|
91
|
+
|
|
92
|
+
| 组件 | 管什么 | 默认 |
|
|
93
|
+
| --- | --- | --- |
|
|
94
|
+
| 设计工作台 | 右侧栏和预览服务器(关掉就等于不用这个插件) | 开 |
|
|
95
|
+
| 自动打开预览 | 做设计时写了 HTML、起了开发服务器,右侧自动打开;关掉后只在右侧栏给一个「预览刚写的 …」按钮 | 开 |
|
|
96
|
+
| 预览工具(其他模式) | 标准、创造等模式也能用 `preview_page` | 开 |
|
|
97
|
+
| 设计技能(其他模式) | 标准、创造等模式也能加载 `ui-design` 技能 | 开 |
|
|
98
|
+
| 设计模式 | 模式菜单里的「设计模式」 | 开 |
|
|
99
|
+
|
|
100
|
+
只想在设计模式里做设计、别的模式保持干净:关掉两个「(其他模式)」。设计模式自带工具和技能,不受这两个开关影响。
|
|
101
|
+
|
|
80
102
|
## 能预览什么
|
|
81
103
|
|
|
82
104
|
| 输入 | 怎么预览 |
|
|
@@ -111,7 +133,8 @@ dsh plugin add https://github.com/OrderG-X/dsh-design-studio/releases/latest/dow
|
|
|
111
133
|
客户端 右侧栏标签页(sidebarRightTabs)+ 标题栏按钮(session.header.utilities)
|
|
112
134
|
```
|
|
113
135
|
|
|
114
|
-
- `lib/index.js` ——
|
|
136
|
+
- `lib/index.js` —— 服务端:工具和技能的定义、接口、自动发现接线
|
|
137
|
+
- `lib/tool.js`、`lib/skill.js`、`lib/auto.js`、`lib/preset.js` —— 能单独开关的几个组件:挂工具、挂技能、自动打开预览、设计模式(`cordis.patch.yml` 里列着;设计模式照抄 DSH 标准模式的插件,再挂上工具和技能)
|
|
115
138
|
- `lib/core.js` —— 地址解析、自动发现、会话状态和存盘、每轮前后存版本、改字写回(只在看得到的文字里找,认 HTML 实体)
|
|
116
139
|
- `lib/history.js` —— 设计版本:按内容存(没改的文件只存一份),最多 40 版,回到某一版
|
|
117
140
|
- `lib/serve.js` —— 预览服务器:静态文件 / 代理 / 改动推送 / 注入
|
|
@@ -129,14 +152,18 @@ dsh plugin add https://github.com/OrderG-X/dsh-design-studio/releases/latest/dow
|
|
|
129
152
|
node test/test-serve.mjs # 静态文件、跳不出目录、Host 把门、改动推送、代理、WebSocket、只听 ::1 的开发服务器、连不上的提示页
|
|
130
153
|
node test/test-core.mjs # 地址解析、自动发现(只在做设计时,后台跑的开发服务器也认)、模型 / 用户指定的不被顶掉、重放不动手、存盘恢复(恢复中先不显示空状态)、类型 / 几屏 / 换屏、改字写回
|
|
131
154
|
node test/test-client.mjs # 右侧栏标签页 / 标题栏按钮注册、只给当前会话自动弹出、选中内容整理成的文字、页面 meta、画布排版、设计变量分组、原型箭头(隔屏的绕开别的屏)、多尺寸排版、矮屏手机没有灵动岛、参考图取色
|
|
132
|
-
node test/test-skill.mjs # 内置技能:名字 /
|
|
155
|
+
node test/test-skill.mjs # 内置技能:名字 / 来源合规、内容读得到、引用的细则文件都在;拆开的几个组件、设计模式带齐标准模式的工具
|
|
133
156
|
node test/test-history.mjs # 版本:存一版 / 没变不存 / 只存设计文件 / 回到某一版 / 上限、每轮前后存、版本名(点选 / 变量 / 参考图换成短名字)、旧版本文件、导出的图不算改动
|
|
134
157
|
node test/test-phone.mjs # 手机上看:二维码结构、挑网卡、补 viewport、口令换 Cookie、没口令 / Host 不对 403、转发、跟随跳屏、WebSocket、停止、闲置自动关
|
|
135
158
|
```
|
|
136
159
|
|
|
137
160
|
## 已验证
|
|
138
161
|
|
|
139
|
-
DeepSeek Harness 桌面端实测:让模型「设计一个咖啡外带 App 的三屏界面」,它先自己加载 `ui-design` 技能、建 `tokens.css`、一屏一个文件,右侧画布套手机外框一屏屏长出来(末尾带「生成中…」),写完按自查表找出文字重叠和对比度问题自己改掉;在「设计规范」面板点主色进输入框,模型问清方向后只改 `tokens.css` 一个变量,三屏一起变色、改动处高亮。之后又实测了第三期:每轮对话前后自动存版本(名字就是那句话)、版本面板、看第 1 版、左右拖动对比、导出整套展示图(3144×2541);点「再出两版」后模型没动原版和 tokens.css,写了 login-b / login-c 两个方向,画布上紧跟在登录屏后面。更早还测了:模型写好 HTML 后右侧栏自动弹出预览;地址栏手动打开;选择模式下点选元素后文字进输入框;改文件后预览自动刷新;DSH 重启后每个会话接着预览原来的页面。浏览器里另测了悬停框、点选、拖选区域、改 CSS 后自动刷新。测试台(插件真代码 + 仿 DSH 外壳)里测了:生成占位、一屏屏生成的动画、四屏 App 画布、画布里点选、改一屏只刷一屏、改共用 CSS 全部刷新、双击单看、类型切换、窄侧栏排版、设计规范面板(分组、点一个进输入框、没有变量时的提示)、导出(单屏带外框、深色页面、三屏合成展示图)、版本列表 / 看旧版 / 左右对比拖把手 / 回到这一版、深色模式切换、再出两版的提示和排序;手机上看:面板里的二维码用系统识别读得出链接,模拟 iPhone(390 宽)扫码打开,地址栏不留口令,「手机已打开」亮起,电脑上选别的屏手机跟着跳,改设计文件手机自动刷新,点停止后链接立刻失效。还测了第五期:原型箭头和演示里点按钮跳屏、多尺寸三档并排、点字改字写回文件并存版本(单页,和画布上的另一屏)、拖入 / 粘贴参考图后取色进输入框、窄侧栏的「更多」菜单。第五期又在 DSH 桌面端实测:非设计任务(命令里 curl 本机端口)不弹出;模型调 `preview_page` 后画布上带跳转箭头,侧栏窄时次要按钮进「更多」;演示里点「获取验证码」滑到首页;多尺寸三档并排;改字回车后写回源文件,版本里多一条「改字「…」」;手机二维码能识别出局域网链接、能打开,点停止后端口关掉;在右侧栏粘贴参考图后,图存进设计目录的 `refs/`,主要颜色和点缀色(如 `#C8763E 1%(点缀)`)进了输入框;发出去后模型先写 `tokens.css`,四屏一起换成参考图的深色加焦糖色;选图按钮能弹出系统选文件框。从访达拖图进来这一步模拟不出系统拖拽,只在测试台验过。之后在 DSH 里从零跑了一遍:模型自己加载技能、调 `preview_page`,三屏宠物领养 App 一屏屏长出来,页面之间自己连好了跳转;点选进输入框、模型改完高亮、版本 / 对比 / 回到第 1 版(文件确实回去了)、导出展示图、窗口在前台时导出也复制进剪贴板、设计规范面板、单页改字写回、多尺寸都正常。这一轮在 DSH 里找出并修了四个只在真 DSH 出现的问题:画布 iframe 刚载完时视口是 0×0,跳转箭头和演示认不出按钮(现在尺寸到了会补报);模型用后台任务(`run_in_background` + `job_output`)起的开发服务器认不出;新版 Vite 在 Mac 上只听 `::1`,代理只连 127.0.0.1,全是「连不上」;DSH 重启时右侧栏先闪一下空状态。修完后实测开发服务器:五个路由并排、改源文件热更新、开发服务器页面上改字变成一句请求、模型改完自动刷新、手机扫码打开(没口令 403
|
|
162
|
+
DeepSeek Harness 桌面端实测:让模型「设计一个咖啡外带 App 的三屏界面」,它先自己加载 `ui-design` 技能、建 `tokens.css`、一屏一个文件,右侧画布套手机外框一屏屏长出来(末尾带「生成中…」),写完按自查表找出文字重叠和对比度问题自己改掉;在「设计规范」面板点主色进输入框,模型问清方向后只改 `tokens.css` 一个变量,三屏一起变色、改动处高亮。之后又实测了第三期:每轮对话前后自动存版本(名字就是那句话)、版本面板、看第 1 版、左右拖动对比、导出整套展示图(3144×2541);点「再出两版」后模型没动原版和 tokens.css,写了 login-b / login-c 两个方向,画布上紧跟在登录屏后面。更早还测了:模型写好 HTML 后右侧栏自动弹出预览;地址栏手动打开;选择模式下点选元素后文字进输入框;改文件后预览自动刷新;DSH 重启后每个会话接着预览原来的页面。浏览器里另测了悬停框、点选、拖选区域、改 CSS 后自动刷新。测试台(插件真代码 + 仿 DSH 外壳)里测了:生成占位、一屏屏生成的动画、四屏 App 画布、画布里点选、改一屏只刷一屏、改共用 CSS 全部刷新、双击单看、类型切换、窄侧栏排版、设计规范面板(分组、点一个进输入框、没有变量时的提示)、导出(单屏带外框、深色页面、三屏合成展示图)、版本列表 / 看旧版 / 左右对比拖把手 / 回到这一版、深色模式切换、再出两版的提示和排序;手机上看:面板里的二维码用系统识别读得出链接,模拟 iPhone(390 宽)扫码打开,地址栏不留口令,「手机已打开」亮起,电脑上选别的屏手机跟着跳,改设计文件手机自动刷新,点停止后链接立刻失效。还测了第五期:原型箭头和演示里点按钮跳屏、多尺寸三档并排、点字改字写回文件并存版本(单页,和画布上的另一屏)、拖入 / 粘贴参考图后取色进输入框、窄侧栏的「更多」菜单。第五期又在 DSH 桌面端实测:非设计任务(命令里 curl 本机端口)不弹出;模型调 `preview_page` 后画布上带跳转箭头,侧栏窄时次要按钮进「更多」;演示里点「获取验证码」滑到首页;多尺寸三档并排;改字回车后写回源文件,版本里多一条「改字「…」」;手机二维码能识别出局域网链接、能打开,点停止后端口关掉;在右侧栏粘贴参考图后,图存进设计目录的 `refs/`,主要颜色和点缀色(如 `#C8763E 1%(点缀)`)进了输入框;发出去后模型先写 `tokens.css`,四屏一起换成参考图的深色加焦糖色;选图按钮能弹出系统选文件框。从访达拖图进来这一步模拟不出系统拖拽,只在测试台验过。之后在 DSH 里从零跑了一遍:模型自己加载技能、调 `preview_page`,三屏宠物领养 App 一屏屏长出来,页面之间自己连好了跳转;点选进输入框、模型改完高亮、版本 / 对比 / 回到第 1 版(文件确实回去了)、导出展示图、窗口在前台时导出也复制进剪贴板、设计规范面板、单页改字写回、多尺寸都正常。这一轮在 DSH 里找出并修了四个只在真 DSH 出现的问题:画布 iframe 刚载完时视口是 0×0,跳转箭头和演示认不出按钮(现在尺寸到了会补报);模型用后台任务(`run_in_background` + `job_output`)起的开发服务器认不出;新版 Vite 在 Mac 上只听 `::1`,代理只连 127.0.0.1,全是「连不上」;DSH 重启时右侧栏先闪一下空状态。修完后实测开发服务器:五个路由并排、改源文件热更新、开发服务器页面上改字变成一句请求、模型改完自动刷新、手机扫码打开(没口令 403)、停止后端口关掉。0.4.0 的设计模式和开关在一个全新的 DSH(0.2.1-rc.2)里实测:模式菜单里有「设计模式」,选它发消息,模型拿到 `preview_page`、`ui-design` 和做设计的人设,调 `preview_page` 后右侧工作台套手机外框打开页面;标准模式默认也有这两样;插件页关掉两个「(其他模式)」后,新开的标准模式会话里没有了,设计模式里照样有;关掉「设计模式」,模式菜单里就没有它,再打开又回来。再早一轮修了几个小毛病,也在 DSH 里验过:新屏播生成动画时底部按钮是透明的,跳转箭头漏了它(现在播动画的按钮也算,播完再补报一次位置);隔着一屏的箭头改成绕到标题上面走;点选后的版本名从「〔选中元素〕em…」变成「「3.2 km」 · 把这个距离文字改成绿色…」;先打字再点选时,选中的内容另起一行,不再粘在那句话后面;多尺寸里的小屏不再画灵动岛;提示条和顶上的提示消息不再叠在一起。
|
|
163
|
+
|
|
164
|
+
## 反馈
|
|
165
|
+
|
|
166
|
+
遇到问题或想要新功能,[提一个 issue](https://github.com/OrderG-X/dsh-design-studio/issues/new/choose)。报问题时写上 DSH 版本和插件版本,修起来最快。
|
|
140
167
|
|
|
141
168
|
## License
|
|
142
169
|
|
package/cordis.patch.yml
CHANGED
|
@@ -1,4 +1,148 @@
|
|
|
1
1
|
# Bundle patch for dsh-design-studio
|
|
2
|
+
# 每一行在 DSH「插件」页里都有自己的开关
|
|
2
3
|
- insert:
|
|
4
|
+
# 设计工作台本体:右侧栏、接口、预览服务器
|
|
3
5
|
- id: dsh-design-studio
|
|
4
6
|
name: dsh-design-studio
|
|
7
|
+
# 自动打开预览(模型写了设计用的 HTML、开发服务器起来时)
|
|
8
|
+
- id: dsh-design-studio-auto
|
|
9
|
+
name: dsh-design-studio/auto
|
|
10
|
+
# 其他模式(标准、创造 …)也能用预览工具、设计技能;设计模式里自带一份,不受这两行影响
|
|
11
|
+
- id: dsh-design-studio-tool
|
|
12
|
+
name: dsh-design-studio/tool
|
|
13
|
+
- id: dsh-design-studio-skill
|
|
14
|
+
name: dsh-design-studio/skill
|
|
15
|
+
# 设计模式:照抄 DSH 0.2.1 标准模式(web-app 的 presets/standard.patch.yml)的全套插件,
|
|
16
|
+
# 人设换成做设计的,再挂上预览工具和设计技能。DSH 标准模式有变动时跟着改
|
|
17
|
+
- id: preset-design
|
|
18
|
+
name: dsh-design-studio/preset
|
|
19
|
+
config:
|
|
20
|
+
id: design
|
|
21
|
+
name: 设计模式
|
|
22
|
+
description: 做网页、App 界面、海报、幻灯片:标准模式的全部工具,加上设计技能和右侧「设计工作台」实时预览。
|
|
23
|
+
order: 1.5
|
|
24
|
+
plugins:
|
|
25
|
+
- id: persona
|
|
26
|
+
name: '@deepseek-ai/dsh-persona'
|
|
27
|
+
config:
|
|
28
|
+
prefix: |-
|
|
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. 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. When a message starts with an element or region the user selected in the preview, change exactly that part in the source.
|
|
31
|
+
- id: agent-instructions
|
|
32
|
+
name: '@deepseek-ai/dsh-agent-instructions'
|
|
33
|
+
config:
|
|
34
|
+
maxBytes: 65536
|
|
35
|
+
- id: time-context
|
|
36
|
+
name: '@deepseek-ai/dsh-time-context'
|
|
37
|
+
- id: tool-bash
|
|
38
|
+
name: '@deepseek-ai/dsh-tool-bash'
|
|
39
|
+
disabled: !!js process.platform === 'win32'
|
|
40
|
+
- id: tool-pwsh
|
|
41
|
+
name: '@deepseek-ai/dsh-tool-pwsh'
|
|
42
|
+
disabled: !!js process.platform !== 'win32'
|
|
43
|
+
- id: tool-fs
|
|
44
|
+
name: '@deepseek-ai/dsh-tool-fs'
|
|
45
|
+
- id: tool-fs-search
|
|
46
|
+
name: '@deepseek-ai/dsh-tool-fs-search'
|
|
47
|
+
config:
|
|
48
|
+
sampleOverCapGlobResults: false
|
|
49
|
+
- id: tool-jobs
|
|
50
|
+
name: '@deepseek-ai/dsh-tool-jobs'
|
|
51
|
+
- id: tool-schedule
|
|
52
|
+
name: '@deepseek-ai/dsh-tool-schedule'
|
|
53
|
+
- id: skill-filesystem
|
|
54
|
+
name: '@deepseek-ai/dsh-skill-filesystem'
|
|
55
|
+
- id: tool-skill
|
|
56
|
+
name: '@deepseek-ai/dsh-tool-skill'
|
|
57
|
+
- id: command-goal
|
|
58
|
+
name: '@deepseek-ai/dsh-command-goal'
|
|
59
|
+
- id: tool-goal
|
|
60
|
+
name: '@deepseek-ai/dsh-tool-goal'
|
|
61
|
+
- id: planning
|
|
62
|
+
name: cordis:group
|
|
63
|
+
group: true
|
|
64
|
+
isolate:
|
|
65
|
+
planMode: true
|
|
66
|
+
config:
|
|
67
|
+
- id: plan-mode
|
|
68
|
+
name: '@deepseek-ai/dsh-plan-mode'
|
|
69
|
+
config:
|
|
70
|
+
section: |
|
|
71
|
+
You are in plan mode. Stay in plan mode until the user approves your plan through exit_plan_mode or switches the session mode. Imperative language to implement changes means plan the implementation, not execute it. A user's conversational agreement — including an answer confirming something you asked — approves nothing and does not end plan mode; fold the confirmed decision into the plan and submit it through exit_plan_mode.
|
|
72
|
+
|
|
73
|
+
Explore first. Use non-mutating reads, searches, static analysis, and checks to ground the plan in the actual repository. Do not edit or write files, change configuration, run formatters or code generation that rewrites tracked files, commit, or otherwise carry out the plan. Prefer existing functions and patterns over new machinery.
|
|
74
|
+
|
|
75
|
+
The tool catalog stays the same across modes for request-cache stability. These plan-mode rules override any later tool description or guidance that suggests using mutation tools; those tools remain listed to keep the tool catalog unchanged. Do not use todo_write to track this planning phase: it tracks implementation after an approved plan, while the plan itself belongs in exit_plan_mode.
|
|
76
|
+
|
|
77
|
+
Resolve discoverable facts by inspection. Use ask_user_question only for user-owned choices or material ambiguity that inspection cannot answer. Do not ask the user where code lives or how current behavior works when you can find out.
|
|
78
|
+
|
|
79
|
+
Make the plan decision-complete: state the goal and success criteria; group implementation changes by subsystem; identify public API, schema, and data-flow changes; cover edge cases, failure modes, tests, acceptance criteria, and explicit assumptions. Keep it concise enough to review but detailed enough that another engineer can implement it without making design decisions.
|
|
80
|
+
|
|
81
|
+
When ready, call exit_plan_mode with the complete plan markdown, starting with a # title. Make exit_plan_mode the only and final tool call in that assistant response: it presents the plan for approval, and implementation begins only in a later step after approval. Do not paste the final plan as a plain reply or ask "should I proceed?" through prose or ask_user_question. If review rejects it, incorporate the feedback and present again. If the review channel is unavailable or aborted, stay in plan mode and ask the user to switch modes manually; do not proceed with implementation.
|
|
82
|
+
- id: compaction
|
|
83
|
+
name: cordis:group
|
|
84
|
+
group: true
|
|
85
|
+
isolate:
|
|
86
|
+
compaction: true
|
|
87
|
+
toolResultPruner: true
|
|
88
|
+
config:
|
|
89
|
+
- id: compaction-basic
|
|
90
|
+
name: '@deepseek-ai/dsh-compaction-basic'
|
|
91
|
+
- id: command-compact
|
|
92
|
+
name: '@deepseek-ai/dsh-command-compact'
|
|
93
|
+
- id: tool-result-pruner
|
|
94
|
+
name: '@deepseek-ai/dsh-compaction-tool-result-pruner'
|
|
95
|
+
config:
|
|
96
|
+
thresholdChars: 8192
|
|
97
|
+
headChars: 4096
|
|
98
|
+
tailChars: 1024
|
|
99
|
+
- id: delegation
|
|
100
|
+
name: cordis:group
|
|
101
|
+
group: true
|
|
102
|
+
isolate:
|
|
103
|
+
workflowEngine: true
|
|
104
|
+
config:
|
|
105
|
+
- id: tool-subagent-control
|
|
106
|
+
name: '@deepseek-ai/dsh-tool-subagent-control'
|
|
107
|
+
- id: tool-subagent-list-agents
|
|
108
|
+
name: '@deepseek-ai/dsh-tool-subagent-control/list-agents'
|
|
109
|
+
- id: tool-subagent
|
|
110
|
+
name: '@deepseek-ai/dsh-tool-subagent'
|
|
111
|
+
config:
|
|
112
|
+
provider: spawn
|
|
113
|
+
toolName: subagent
|
|
114
|
+
modelSelectionSettings: true
|
|
115
|
+
- id: tool-subagent-fork
|
|
116
|
+
name: '@deepseek-ai/dsh-tool-subagent'
|
|
117
|
+
config:
|
|
118
|
+
provider: fork
|
|
119
|
+
toolName: subagent_fork
|
|
120
|
+
- id: workflow-ptc
|
|
121
|
+
name: '@deepseek-ai/dsh-workflow-ptc'
|
|
122
|
+
config:
|
|
123
|
+
provider: spawn
|
|
124
|
+
- id: tool-workflow
|
|
125
|
+
name: '@deepseek-ai/dsh-tool-workflow'
|
|
126
|
+
- id: tool-ask-user
|
|
127
|
+
name: '@deepseek-ai/dsh-tool-ask-user'
|
|
128
|
+
- id: tool-todo
|
|
129
|
+
name: '@deepseek-ai/dsh-tool-todo'
|
|
130
|
+
config:
|
|
131
|
+
allowParallelInProgress: true
|
|
132
|
+
- id: tool-web
|
|
133
|
+
name: '@deepseek-ai/dsh-tool-web'
|
|
134
|
+
config:
|
|
135
|
+
fetch: true
|
|
136
|
+
searchTimeoutMs: 60000
|
|
137
|
+
- id: present
|
|
138
|
+
name: '@deepseek-ai/dsh-tool-present'
|
|
139
|
+
- id: tool-plugin-manager
|
|
140
|
+
name: '@deepseek-ai/dsh-plugin-manager/tools'
|
|
141
|
+
disabled: true
|
|
142
|
+
- id: tool-plugin-market
|
|
143
|
+
name: '@deepseek-ai/dsh-plugin-market/tools'
|
|
144
|
+
disabled: true
|
|
145
|
+
- id: design-tool
|
|
146
|
+
name: dsh-design-studio/tool
|
|
147
|
+
- id: design-skill
|
|
148
|
+
name: dsh-design-studio/skill
|
package/lib/auto.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dsh-design-studio/auto:自动打开预览。
|
|
3
|
+
* 开着时,模型写了设计用的 HTML、或开发服务器起来了,右侧栏自动预览;关掉后只在右侧栏给个「预览刚写的 …」按钮
|
|
4
|
+
*/
|
|
5
|
+
import { studio } from './index.js'
|
|
6
|
+
|
|
7
|
+
export const name = 'dsh-design-studio-auto'
|
|
8
|
+
|
|
9
|
+
export function apply(ctx) {
|
|
10
|
+
ctx.effect(() => {
|
|
11
|
+
studio.autoOpen++
|
|
12
|
+
return () => { studio.autoOpen-- }
|
|
13
|
+
}, 'dsh-design-studio: auto open')
|
|
14
|
+
}
|
package/lib/core.js
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
import fs from 'node:fs'
|
|
10
10
|
import os from 'node:os'
|
|
11
11
|
import path from 'node:path'
|
|
12
|
+
import { fileURLToPath } from 'node:url'
|
|
12
13
|
|
|
13
14
|
const HTML_EXT = /\.html?$/i
|
|
14
15
|
const LOCAL_URL = /^(?:https?:\/\/)?(localhost|127\.0\.0\.1|0\.0\.0\.0|\[::1\]):(\d{2,5})(\/[^\s]*)?$/i
|
|
@@ -91,6 +92,13 @@ function normRoutes(list) {
|
|
|
91
92
|
return out.length ? out : null
|
|
92
93
|
}
|
|
93
94
|
|
|
95
|
+
/** Windows 上 DSH 用 Git Bash 跑命令,模型给的路径常是 /c/Users/… 这种写法:换成 C:\\Users\\…;别的系统原样 */
|
|
96
|
+
export function fromBashPath(p, platform = process.platform) {
|
|
97
|
+
if (platform !== 'win32') return p
|
|
98
|
+
const m = /^\/([a-zA-Z])(?:\/(.*))?$/.exec(p)
|
|
99
|
+
return m ? `${m[1].toUpperCase()}:\\${(m[2] || '').replace(/\//g, '\\')}` : p
|
|
100
|
+
}
|
|
101
|
+
|
|
94
102
|
/**
|
|
95
103
|
* @returns {{ kind: 'file', file, root } | { kind: 'proxy', port, path }}
|
|
96
104
|
* @throws Error 带中文说明
|
|
@@ -102,11 +110,17 @@ export function parseTarget(input, cwd = os.homedir()) {
|
|
|
102
110
|
const m = LOCAL_URL.exec(s)
|
|
103
111
|
if (m) return proxyTarget(Number(m[2]), m[3] || '/')
|
|
104
112
|
if (/^https?:\/\//i.test(s)) throw new Error('只能预览本机的页面:本地 HTML 文件,或 localhost 上的开发服务器')
|
|
105
|
-
let p =
|
|
106
|
-
|
|
107
|
-
|
|
113
|
+
let p = null
|
|
114
|
+
// 标准的 file:// 地址交给 Node 转(Windows 上是 file:///C:/…,直接去掉前缀会变成 /C:/…)
|
|
115
|
+
if (/^file:\/\//i.test(s)) try { p = fileURLToPath(s) } catch { /* file://~/… 之类的写法,按下面的老办法 */ }
|
|
116
|
+
if (p === null) {
|
|
117
|
+
p = s.replace(/^file:\/\//i, '')
|
|
118
|
+
if (p.includes('%')) {
|
|
119
|
+
try { p = decodeURIComponent(p) } catch { /* 原样用 */ }
|
|
120
|
+
}
|
|
108
121
|
}
|
|
109
|
-
|
|
122
|
+
p = fromBashPath(p)
|
|
123
|
+
if (p === '~' || p.startsWith('~/') || p.startsWith('~\\')) p = path.join(os.homedir(), p.slice(1))
|
|
110
124
|
p = path.resolve(cwd, p)
|
|
111
125
|
let st
|
|
112
126
|
try { st = fs.statSync(p) } catch { throw new Error(`找不到:${p}`) }
|
|
@@ -321,7 +335,7 @@ export function askOf(data) {
|
|
|
321
335
|
/**
|
|
322
336
|
* @param opts.alive (origin) → 这个预览服务器还开着吗(开的太多时旧的会被关掉;发现没了就重开)
|
|
323
337
|
*/
|
|
324
|
-
export function createTracker({ open, skipPorts = () => new Set(), now = Date.now, log = () => {}, store = null, history = null, alive = () => true }) {
|
|
338
|
+
export function createTracker({ open, skipPorts = () => new Set(), now = Date.now, log = () => {}, store = null, history = null, alive = () => true, autoOpen = () => true }) {
|
|
325
339
|
const states = new Map() // sessionId → state
|
|
326
340
|
const cwds = new Map() // sessionId → 最近一次工具的工作目录
|
|
327
341
|
let saved = {}
|
|
@@ -563,9 +577,11 @@ export function createTracker({ open, skipPorts = () => new Set(), now = Date.no
|
|
|
563
577
|
if (callId) st.calls.delete(callId)
|
|
564
578
|
if (pending && fs.existsSync(pending) && (!st.target || st.source === 'auto') && !(st.target && st.target.file === pending)) {
|
|
565
579
|
// 只有在做设计(加载了设计技能、或页面写了设计类型标记)才自动打开;别的任务写的网页只记下来,不弹
|
|
580
|
+
// 用户关了「自动打开预览」:也只记下来,右侧栏给个按钮
|
|
566
581
|
if (st.design || isDesignHtml(pending)) {
|
|
567
582
|
st.design = true
|
|
568
|
-
auto(sessionId, { kind: 'file', file: pending, root: path.dirname(pending) })
|
|
583
|
+
if (autoOpen()) auto(sessionId, { kind: 'file', file: pending, root: path.dirname(pending) })
|
|
584
|
+
else st.hint = pending
|
|
569
585
|
} else st.hint = pending
|
|
570
586
|
}
|
|
571
587
|
if (st.target && st.source !== 'auto') break
|
|
@@ -590,7 +606,7 @@ export function createTracker({ open, skipPorts = () => new Set(), now = Date.no
|
|
|
590
606
|
const found = devServerIn(command, text, skipPorts())
|
|
591
607
|
if (found) {
|
|
592
608
|
const t = { kind: 'proxy', port: found.port, path: '/' }
|
|
593
|
-
if (!sameTarget(st.target, t)) auto(sessionId, t)
|
|
609
|
+
if (!sameTarget(st.target, t) && autoOpen()) auto(sessionId, t)
|
|
594
610
|
break
|
|
595
611
|
}
|
|
596
612
|
}
|
package/lib/index.js
CHANGED
|
@@ -4,6 +4,14 @@
|
|
|
4
4
|
* preview_page 工具 模型做界面时调一次,右侧栏「设计工作台」打开这个页面(可以带类型:网页 / App / 海报 …)
|
|
5
5
|
* 自动发现 模型写了 HTML、或命令输出里出现 localhost:端口(开发服务器起来了),自动预览
|
|
6
6
|
* ui-design 技能 设计流程、设计原则、中文排版、各类型要点、避免 AI 味、自查清单(skills/ui-design/,DSH 有技能服务时才挂上)
|
|
7
|
+
*
|
|
8
|
+
* 拆成几行,每行在 DSH「插件」页里有自己的开关(见 cordis.patch.yml):
|
|
9
|
+
* dsh-design-studio 工作台本体:右侧栏、接口、预览服务器、跟踪会话(这个文件的 apply)
|
|
10
|
+
* dsh-design-studio/auto 自动打开预览(auto.js)
|
|
11
|
+
* dsh-design-studio/tool preview_page 工具(tool.js)
|
|
12
|
+
* dsh-design-studio/skill ui-design 技能(skill.js)
|
|
13
|
+
* preset-design 设计模式:标准模式的全套工具 + 上面两行,人设换成做设计的
|
|
14
|
+
* 工具和技能在顶层挂一份(所有模式都能用),设计模式里再挂一份(只关顶层那份,设计模式照样有)。
|
|
7
15
|
* 接口(DSH 自己的地址,要登录态):
|
|
8
16
|
* GET /dsh-design-studio/api/state?session= 右侧栏轮询:预览什么、有哪几屏、要不要弹出来、模型在不在干活
|
|
9
17
|
* POST /dsh-design-studio/api/open 地址栏输入新地址 { session, target }
|
|
@@ -33,21 +41,24 @@ import { createPhone } from './phone.js'
|
|
|
33
41
|
import { qrMatrix } from './qr.js'
|
|
34
42
|
|
|
35
43
|
export const name = 'dsh-design-studio'
|
|
36
|
-
export const inject = ['
|
|
44
|
+
export const inject = ['webServer']
|
|
37
45
|
|
|
38
46
|
const API = '/dsh-design-studio/api/'
|
|
39
47
|
const LOOPBACK = new Set(['127.0.0.1', '::1', '::ffff:127.0.0.1'])
|
|
40
48
|
const LOOPBACK_HOST = /^(127\.0\.0\.1|localhost|\[::1\])(:\d+)?$/i
|
|
41
49
|
const MAX_BODY = 64 * 1024
|
|
42
50
|
const MAX_EXPORT = 48 * 1024 * 1024 // 导出图片的请求体(base64)
|
|
43
|
-
const HISTORY_DIR = path.join(
|
|
51
|
+
const HISTORY_DIR = path.join(os.homedir(), '.dsh', 'cache', 'dsh-design-studio', 'history')
|
|
44
52
|
// 每个会话预览的是什么,存这里(DSH 重启后接着显示)
|
|
45
53
|
// 参考图:没有本地设计目录(开发服务器 / 还没开始)时存这里
|
|
46
|
-
const REFS_DIR = path.join(
|
|
47
|
-
const STORE_FILE = path.join(
|
|
54
|
+
const REFS_DIR = path.join(os.homedir(), '.dsh', 'cache', 'dsh-design-studio', 'refs')
|
|
55
|
+
const STORE_FILE = path.join(os.homedir(), '.dsh', 'cache', 'dsh-design-studio.json')
|
|
48
56
|
const SKILL_DIR = path.join(path.dirname(fileURLToPath(import.meta.url)), '..', 'skills', 'ui-design')
|
|
49
57
|
const SKILL_RANK = 600 // 和 DSH 自带的技能同一档;用户 / 项目里同名的技能优先
|
|
50
58
|
|
|
59
|
+
/** 几行之间靠这个互通(同一个包里的模块 Node 只加载一次):工作台起来后放 tracker;「自动打开预览」那行开着时 autoOpen > 0 */
|
|
60
|
+
export const studio = { tracker: null, autoOpen: 0 }
|
|
61
|
+
|
|
51
62
|
/** 设计技能:模型做界面设计时加载(DSH 的 skill 工具),也能让用户手动调 */
|
|
52
63
|
export const designSkill = {
|
|
53
64
|
name: 'ui-design',
|
|
@@ -72,6 +83,62 @@ export const skillProvider = {
|
|
|
72
83
|
},
|
|
73
84
|
}
|
|
74
85
|
|
|
86
|
+
/** preview_page 工具(tool.js 挂到 DSH;不在这个文件的 apply 里挂,好让它单独开关、也能挂进设计模式) */
|
|
87
|
+
export const previewTool = {
|
|
88
|
+
name: 'preview_page',
|
|
89
|
+
description:
|
|
90
|
+
'在右侧栏「设计工作台」里实时打开一个页面,用户能边看边点选要改的地方。' +
|
|
91
|
+
'做网页、App 界面、海报、幻灯片、邮件这类界面设计时用:写好第一个 HTML 文件、或启动开发服务器后调一次就行,之后改文件会自动刷新,不用再调。' +
|
|
92
|
+
'本地 HTML 写文件路径;开发服务器写地址或端口(如 http://localhost:5173)。只能预览本机页面。' +
|
|
93
|
+
'kind 说明是哪类设计,右侧按它的画幅显示(App 套手机外框、幻灯片 16:9 …)。' +
|
|
94
|
+
'动手设计前先加载 ui-design 技能(设计流程、规范和自查清单)。' +
|
|
95
|
+
'要做好几屏(App 的几个界面、网站的几个页面)时,每屏一个 HTML 文件放在同一个目录,右侧画布会按生成顺序并排显示,一屏一屏写就行。' +
|
|
96
|
+
'用户在预览里点选的内容会以「〔选中元素〕」或「〔选中区域〕」开头出现在消息里,带 CSS 路径、HTML、关键样式,' +
|
|
97
|
+
'拿得到时还有组件和源码位置:照它找到源码里对应的地方再改。',
|
|
98
|
+
parameters: specToJsonSchema({
|
|
99
|
+
target: { type: 'string', required: true, description: '本地 HTML 文件的绝对路径,或开发服务器地址 / 端口,例如 /Users/me/site/index.html、http://localhost:5173、5173' },
|
|
100
|
+
kind: {
|
|
101
|
+
type: 'string',
|
|
102
|
+
enum: KINDS,
|
|
103
|
+
description: '设计类型:web 网页(默认)、app 手机 App 界面(390×844)、tablet 平板、poster 海报 / 社媒图(1080×1350)、slides 幻灯片(16:9)、email 邮件',
|
|
104
|
+
},
|
|
105
|
+
size: { type: 'string', description: '画幅尺寸,可选,如 1080x1920;不填按类型的默认尺寸' },
|
|
106
|
+
screens: {
|
|
107
|
+
type: 'array',
|
|
108
|
+
items: { type: 'string' },
|
|
109
|
+
description: '开发服务器上要并排显示的几个路由,可选,如 ["/", "/login", "/settings"]。本地 HTML 不用填:同目录的 HTML 文件自动并排',
|
|
110
|
+
},
|
|
111
|
+
}),
|
|
112
|
+
output: {
|
|
113
|
+
schema: {
|
|
114
|
+
type: 'object',
|
|
115
|
+
additionalProperties: false,
|
|
116
|
+
properties: { text: { type: 'string' }, url: { type: 'string' } },
|
|
117
|
+
required: ['text'],
|
|
118
|
+
},
|
|
119
|
+
render: (_args, value) => [{ type: 'text', text: value.text }],
|
|
120
|
+
},
|
|
121
|
+
async execute(args, exec) {
|
|
122
|
+
const session = exec && exec.agent && exec.agent.session
|
|
123
|
+
const id = session && session.id
|
|
124
|
+
if (!id) throw new Error('拿不到当前会话,没法打开预览')
|
|
125
|
+
const tracker = studio.tracker
|
|
126
|
+
if (!tracker) throw new Error('「设计工作台」在 DSH 的插件页里关着,打开后再预览')
|
|
127
|
+
const target = parseTarget(args.target, tracker.cwdOf(id))
|
|
128
|
+
const opts = { source: 'tool' }
|
|
129
|
+
if (args.kind !== undefined) opts.kind = args.kind
|
|
130
|
+
if (args.size !== undefined) opts.size = args.size
|
|
131
|
+
if (args.screens !== undefined) opts.routes = args.screens
|
|
132
|
+
const st = await tracker.setTarget(id, target, opts)
|
|
133
|
+
const what = target.kind === 'file' ? target.file : `localhost:${target.port}${target.path}`
|
|
134
|
+
const many = target.kind === 'file' ? '同目录再写别的 HTML 文件,会作为新的一屏并排出现。' : ''
|
|
135
|
+
return {
|
|
136
|
+
text: `已在右侧「设计工作台」打开 ${what}。${target.kind === 'file' ? '这个目录里的文件一改就自动刷新。' + many : '开发服务器的热更新照常生效。'}`,
|
|
137
|
+
url: st.url,
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
}
|
|
141
|
+
|
|
75
142
|
const fileStore = {
|
|
76
143
|
load: () => JSON.parse(fs.readFileSync(STORE_FILE, 'utf8')),
|
|
77
144
|
save: (data) => {
|
|
@@ -169,6 +236,7 @@ export function apply(ctx) {
|
|
|
169
236
|
history,
|
|
170
237
|
store: fileStore,
|
|
171
238
|
alive: (origin) => hub.alive(origin),
|
|
239
|
+
autoOpen: () => studio.autoOpen > 0,
|
|
172
240
|
skipPorts: () => {
|
|
173
241
|
const s = new Set(previewPorts)
|
|
174
242
|
const own = ownHost(ctx).split(':')[1]
|
|
@@ -177,18 +245,13 @@ export function apply(ctx) {
|
|
|
177
245
|
},
|
|
178
246
|
})
|
|
179
247
|
ctx.effect(() => () => hub.closeAll(), 'dsh-design-studio: preview servers')
|
|
248
|
+
ctx.effect(() => {
|
|
249
|
+
studio.tracker = tracker
|
|
250
|
+
return () => { if (studio.tracker === tracker) studio.tracker = null }
|
|
251
|
+
}, 'dsh-design-studio: tracker')
|
|
180
252
|
const phone = createPhone({ upstream: (session) => tracker.snapshot(session).origin || '', log })
|
|
181
253
|
ctx.effect(() => () => phone.stopAll(), 'dsh-design-studio: phone links')
|
|
182
254
|
|
|
183
|
-
// 设计技能:等 DSH 的技能服务就绪再挂(老版本没有就算了),插件卸载时一起摘掉
|
|
184
|
-
if (typeof ctx.inject === 'function') {
|
|
185
|
-
try {
|
|
186
|
-
ctx.inject(['skills'], (sub) => { sub.skills.registerProvider(() => skillProvider) })
|
|
187
|
-
} catch (e) {
|
|
188
|
-
log(e)
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
|
|
192
255
|
// ── 接口 ──────────────────────────────────────────────────────────────────
|
|
193
256
|
|
|
194
257
|
function admit(req, res) {
|
|
@@ -401,61 +464,6 @@ export function apply(ctx) {
|
|
|
401
464
|
}), `dsh-design-studio: ${key} route`)
|
|
402
465
|
}
|
|
403
466
|
|
|
404
|
-
// ── 工具 ──────────────────────────────────────────────────────────────────
|
|
405
|
-
|
|
406
|
-
ctx.tools.register({
|
|
407
|
-
name: 'preview_page',
|
|
408
|
-
description:
|
|
409
|
-
'在右侧栏「设计工作台」里实时打开一个页面,用户能边看边点选要改的地方。' +
|
|
410
|
-
'做网页、App 界面、海报、幻灯片、邮件这类界面设计时用:写好第一个 HTML 文件、或启动开发服务器后调一次就行,之后改文件会自动刷新,不用再调。' +
|
|
411
|
-
'本地 HTML 写文件路径;开发服务器写地址或端口(如 http://localhost:5173)。只能预览本机页面。' +
|
|
412
|
-
'kind 说明是哪类设计,右侧按它的画幅显示(App 套手机外框、幻灯片 16:9 …)。' +
|
|
413
|
-
'动手设计前先加载 ui-design 技能(设计流程、规范和自查清单)。' +
|
|
414
|
-
'要做好几屏(App 的几个界面、网站的几个页面)时,每屏一个 HTML 文件放在同一个目录,右侧画布会按生成顺序并排显示,一屏一屏写就行。' +
|
|
415
|
-
'用户在预览里点选的内容会以「〔选中元素〕」或「〔选中区域〕」开头出现在消息里,带 CSS 路径、HTML、关键样式,' +
|
|
416
|
-
'拿得到时还有组件和源码位置:照它找到源码里对应的地方再改。',
|
|
417
|
-
parameters: specToJsonSchema({
|
|
418
|
-
target: { type: 'string', required: true, description: '本地 HTML 文件的绝对路径,或开发服务器地址 / 端口,例如 /Users/me/site/index.html、http://localhost:5173、5173' },
|
|
419
|
-
kind: {
|
|
420
|
-
type: 'string',
|
|
421
|
-
enum: KINDS,
|
|
422
|
-
description: '设计类型:web 网页(默认)、app 手机 App 界面(390×844)、tablet 平板、poster 海报 / 社媒图(1080×1350)、slides 幻灯片(16:9)、email 邮件',
|
|
423
|
-
},
|
|
424
|
-
size: { type: 'string', description: '画幅尺寸,可选,如 1080x1920;不填按类型的默认尺寸' },
|
|
425
|
-
screens: {
|
|
426
|
-
type: 'array',
|
|
427
|
-
items: { type: 'string' },
|
|
428
|
-
description: '开发服务器上要并排显示的几个路由,可选,如 ["/", "/login", "/settings"]。本地 HTML 不用填:同目录的 HTML 文件自动并排',
|
|
429
|
-
},
|
|
430
|
-
}),
|
|
431
|
-
output: {
|
|
432
|
-
schema: {
|
|
433
|
-
type: 'object',
|
|
434
|
-
additionalProperties: false,
|
|
435
|
-
properties: { text: { type: 'string' }, url: { type: 'string' } },
|
|
436
|
-
required: ['text'],
|
|
437
|
-
},
|
|
438
|
-
render: (_args, value) => [{ type: 'text', text: value.text }],
|
|
439
|
-
},
|
|
440
|
-
async execute(args, exec) {
|
|
441
|
-
const session = exec && exec.agent && exec.agent.session
|
|
442
|
-
const id = session && session.id
|
|
443
|
-
if (!id) throw new Error('拿不到当前会话,没法打开预览')
|
|
444
|
-
const target = parseTarget(args.target, tracker.cwdOf(id))
|
|
445
|
-
const opts = { source: 'tool' }
|
|
446
|
-
if (args.kind !== undefined) opts.kind = args.kind
|
|
447
|
-
if (args.size !== undefined) opts.size = args.size
|
|
448
|
-
if (args.screens !== undefined) opts.routes = args.screens
|
|
449
|
-
const st = await tracker.setTarget(id, target, opts)
|
|
450
|
-
const what = target.kind === 'file' ? target.file : `localhost:${target.port}${target.path}`
|
|
451
|
-
const many = target.kind === 'file' ? '同目录再写别的 HTML 文件,会作为新的一屏并排出现。' : ''
|
|
452
|
-
return {
|
|
453
|
-
text: `已在右侧「设计工作台」打开 ${what}。${target.kind === 'file' ? '这个目录里的文件一改就自动刷新。' + many : '开发服务器的热更新照常生效。'}`,
|
|
454
|
-
url: st.url,
|
|
455
|
-
}
|
|
456
|
-
},
|
|
457
|
-
})
|
|
458
|
-
|
|
459
467
|
// ── 自动发现 ──────────────────────────────────────────────────────────────
|
|
460
468
|
|
|
461
469
|
if (typeof ctx.on === 'function') {
|
package/lib/preset.js
ADDED
package/lib/skill.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dsh-design-studio/skill:把 ui-design 技能挂到 DSH 的技能服务(老版本没有就算了)。
|
|
3
|
+
* 放在 bundle 顶层 → 所有模式都能用;放进设计模式 → 只挂在那个模式里。技能本身见 index.js 的 designSkill
|
|
4
|
+
*/
|
|
5
|
+
import { skillProvider } from './index.js'
|
|
6
|
+
|
|
7
|
+
export const name = 'dsh-design-studio-skill'
|
|
8
|
+
|
|
9
|
+
export function apply(ctx) {
|
|
10
|
+
if (typeof ctx.inject !== 'function') return
|
|
11
|
+
try {
|
|
12
|
+
// 等技能服务就绪再挂,这一行关掉时一起摘掉
|
|
13
|
+
ctx.inject(['skills'], (sub) => { sub.skills.registerProvider(() => skillProvider) })
|
|
14
|
+
} catch (e) {
|
|
15
|
+
try { ctx.logger.warn(`dsh-design-studio: ${e && e.message ? e.message : e}`) } catch { /* 没 logger 就算了 */ }
|
|
16
|
+
}
|
|
17
|
+
}
|
package/lib/tool.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dsh-design-studio/tool:把 preview_page 工具挂给模型。
|
|
3
|
+
* 放在 bundle 顶层 → 所有模式都能用;放进设计模式 → 只挂在那个模式里。工具本身见 index.js 的 previewTool
|
|
4
|
+
*/
|
|
5
|
+
import { previewTool } from './index.js'
|
|
6
|
+
|
|
7
|
+
export const name = 'dsh-design-studio-tool'
|
|
8
|
+
export const inject = ['tools']
|
|
9
|
+
|
|
10
|
+
export function apply(ctx) {
|
|
11
|
+
ctx.tools.register({ ...previewTool })
|
|
12
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
{
|
|
2
|
+
"meta": {
|
|
3
|
+
"title": "Design mode",
|
|
4
|
+
"description": "Adds a Design mode for new sessions: all of Standard mode's tools plus the design skill and live previews in the Design Studio sidebar, with a design-focused persona. Turned off, the mode leaves the list."
|
|
5
|
+
}
|
|
6
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-design-studio",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"type": "module",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"test": "node --test --test-concurrency=1 test/*.mjs"
|
|
7
|
+
},
|
|
5
8
|
"description": "Design workbench in the DeepSeek Harness right sidebar: watch web / app / poster screens generate on a canvas with device frames, click an element to send it to the chat, tweak design tokens, compare versions, export share-ready images and scan to view on your phone.",
|
|
6
9
|
"license": "MIT",
|
|
7
10
|
"repository": {
|
|
@@ -19,6 +22,18 @@
|
|
|
19
22
|
"exports": {
|
|
20
23
|
".": "./lib/index.js",
|
|
21
24
|
"./client": "./lib/client.js",
|
|
25
|
+
"./auto": "./lib/auto.js",
|
|
26
|
+
"./auto/locale/*.json": "./locale/auto/*.json",
|
|
27
|
+
"./auto/icon": "./icon.svg",
|
|
28
|
+
"./tool": "./lib/tool.js",
|
|
29
|
+
"./tool/locale/*.json": "./locale/tool/*.json",
|
|
30
|
+
"./tool/icon": "./icon.svg",
|
|
31
|
+
"./skill": "./lib/skill.js",
|
|
32
|
+
"./skill/locale/*.json": "./locale/skill/*.json",
|
|
33
|
+
"./skill/icon": "./icon.svg",
|
|
34
|
+
"./preset": "./lib/preset.js",
|
|
35
|
+
"./preset/locale/*.json": "./locale/preset/*.json",
|
|
36
|
+
"./preset/icon": "./icon.svg",
|
|
22
37
|
"./package.json": "./package.json",
|
|
23
38
|
"./cordis.patch.yml": "./cordis.patch.yml",
|
|
24
39
|
"./icon.svg": "./icon.svg",
|