@exccoder/dsh-media-workbench 0.0.0-stage → 0.2.2
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/CHANGELOG.md +60 -0
- package/LICENSE +21 -0
- package/README.en.md +108 -0
- package/README.md +138 -2
- package/SECURITY.md +29 -0
- package/cordis.patch.yml +4 -0
- package/docs/screenshot-graph.webp +0 -0
- package/docs/screenshot-image.webp +0 -0
- package/docs/screenshot-video.webp +0 -0
- package/docs/screenshot-write.webp +0 -0
- package/lib/client.js +138 -0
- package/package.json +79 -4
- package/src/graph.js +304 -0
- package/src/image.js +150 -0
- package/src/index.js +865 -0
- package/src/llm.js +60 -0
- package/src/settings.js +233 -0
- package/src/store.js +241 -0
- package/src/tools.js +354 -0
- package/src/util.js +217 -0
- package/src/video.js +245 -0
- package/src/writing.js +112 -0
- package/web/app.js +268 -0
- package/web/favicon.svg +12 -0
- package/web/index.html +16 -0
- package/web/lib/api.js +79 -0
- package/web/lib/constants.js +69 -0
- package/web/lib/dom.js +126 -0
- package/web/lib/icons.js +65 -0
- package/web/lib/state.js +42 -0
- package/web/styles.css +1143 -0
- package/web/views/constellation-model.js +63 -0
- package/web/views/constellation.js +1110 -0
- package/web/views/image.js +652 -0
- package/web/views/settings.js +269 -0
- package/web/views/video.js +363 -0
- package/web/views/write.js +513 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented here. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the project uses [Semantic Versioning](https://semver.org/).
|
|
4
|
+
|
|
5
|
+
## [0.2.2] - 2026-11-09
|
|
6
|
+
|
|
7
|
+
Image workflow and storage update.
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- Reference queue for Image Studio: up to 8 images, Ctrl+V paste, multi-file drop/select, per-image up/down reorder and removal, with「图一 / 图二」labels.
|
|
12
|
+
- Multi-reference image edits use ordered `image[]` fields; single references keep the existing `image` field.
|
|
13
|
+
- Reuse now carries the original reference images. If the source image had references, a confirmation asks whether to replace the current queue or reuse the prompt only.
|
|
14
|
+
- Custom **Library folder**: image/video files can move to another drive. Saving migrates existing files, removes them from the old folder, and rejects invalid, unwritable, nested, or name-conflicting targets.
|
|
15
|
+
- Image right-click menu: copy image to clipboard, download original, copy prompt, and open the containing folder (file is selected in Explorer/Finder).
|
|
16
|
+
- Settings cleanup: removed the read-only workbench data card; maintenance actions now live under「维护」.
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- Workbench height now fills the full DSH panel, including the bottom of the rail and composer.
|
|
21
|
+
- Settings copy now distinguishes workbench records from the actual media library folder.
|
|
22
|
+
|
|
23
|
+
## [0.1.4] - 2026-11-07
|
|
24
|
+
|
|
25
|
+
Fixed video downloads that returned 401 from gateways which require the same Bearer token on the media URL. The downloader now retries the provider URL with authentication and falls back to the configured content endpoint.
|
|
26
|
+
|
|
27
|
+
## [0.1.3] - 2026-11-07
|
|
28
|
+
|
|
29
|
+
Removed external inspiration attribution and the legacy data-directory migration from earlier prototypes. The four workbenches are unchanged.
|
|
30
|
+
|
|
31
|
+
## [0.1.2] - 2026-11-07
|
|
32
|
+
|
|
33
|
+
First npm publication as **@exccoder/dsh-media-workbench**. The package was renamed from the `@modern` scope before publishing; there are no functional changes since 0.1.1. The GitHub `v0.1.1` release is superseded by `v0.1.2`.
|
|
34
|
+
|
|
35
|
+
## [0.1.1] - 2026-11-07
|
|
36
|
+
|
|
37
|
+
Initial GitHub release under `@modern/dsh-media-workbench`; not published to npm. Superseded by 0.1.2.
|
|
38
|
+
|
|
39
|
+
### Added
|
|
40
|
+
|
|
41
|
+
- Package name `@modern/dsh-media-workbench`, sidebar title「摩登-媒体工作室」with the English label `Modern-MediaStudio`, following the DSH locale.
|
|
42
|
+
- **Image Studio**: prompt, negative prompt, nine style presets, six aspect ratios, 1–4 images, reference-image editing through `/images/edits`, favorites, search, history, lightbox, retry/download/reuse.
|
|
43
|
+
- **Writing Studio**: local document library, autosave, Markdown export, selection-aware continue/polish/expand/rewrite/outline/title actions, streaming output with stop/apply/discard.
|
|
44
|
+
- **Star Map**: typed node graph (prompt, writing, image, video, preview, note), drag-to-connect ports, type/single-input/cycle validation, topological parallel execution, run-to-node, undo/redo, templates, user blueprints, JSON import/export, responsive inspector.
|
|
45
|
+
- **Video Studio**: text-to-video, image-to-video through a generic async task API, and a no-video-provider **Storyboard** mode that generates four keyframes and plays them in the browser.
|
|
46
|
+
- Five model tools: `modern_media_generate_image`, `modern_media_save_document`, `modern_media_generate_video`, `modern_media_run_star_map`, `modern_media_workspace_overview`.
|
|
47
|
+
- Local-first storage under `$DSH_HOME/media-workbench-modern/`, masked API keys, same-origin/DSH-auth checks, whitelisted static files, and SSRF protection for remote media.
|
|
48
|
+
- Light/dark theme and Chinese/English UI synced from DSH.
|
|
49
|
+
- Offline verification suite (`npm test`) and a standalone dev server with mock providers (`npm run dev`).
|
|
50
|
+
|
|
51
|
+
### Known limitations
|
|
52
|
+
|
|
53
|
+
- Video providers vary; the current adapter expects the common create → poll → download shape. Paths and extra parameters are configurable.
|
|
54
|
+
- Without a video provider only Storyboard mode is available; there is no local mp4 encoding.
|
|
55
|
+
- One active image provider configuration (no multi-key rotation).
|
|
56
|
+
- Narrow layouts collapse the document list, node palette and inspector.
|
|
57
|
+
|
|
58
|
+
## [0.1.0]
|
|
59
|
+
|
|
60
|
+
Internal prototype used during development. Not published.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ExcCoder
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.en.md
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# Modern-MediaStudio · @exccoder/dsh-media-workbench
|
|
2
|
+
|
|
3
|
+
A [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (DSH) plugin that adds a **Modern-MediaStudio** to the sidebar with four connected workbenches:
|
|
4
|
+
|
|
5
|
+
- **Image Studio** — prompt to image, nine style presets, six aspect ratios, reference-image editing, favorites and history.
|
|
6
|
+
- **Writing Studio** — local document library, selection-aware continue / polish / expand / rewrite / outline / title, streaming output.
|
|
7
|
+
- **Star Map** — a typed DAG of prompt, writing, image, video and preview nodes; cycle checks, parallel topological execution, templates and reusable blueprints.
|
|
8
|
+
- **Video Studio** — text-to-video, image-to-video, and a **Storyboard** mode that turns four keyframes into a moving preview without a video provider.
|
|
9
|
+
|
|
10
|
+
Writing uses DSH's currently selected model. Image and video providers are configured separately. All works, images, videos and Star Maps stay on this machine. The UI is available in Chinese and English and follows DSH's language and light/dark theme.
|
|
11
|
+
|
|
12
|
+
[中文说明](README.md)
|
|
13
|
+
|
|
14
|
+
## Install
|
|
15
|
+
|
|
16
|
+
Requires DSH `0.2.x` (verified on `0.2.2-rc.1`).
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# after the package is published
|
|
20
|
+
dsh plugin --profile desktop add @exccoder/dsh-media-workbench
|
|
21
|
+
|
|
22
|
+
# or from a local checkout
|
|
23
|
+
dsh plugin --profile desktop add /absolute/path/to/dsh-media-workbench
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
You can also use **Plugins → Add plugin** in DSH and point it at the directory or a packed `.tgz`. Fully quit and reopen DSH after installing; the sidebar entry should then appear.
|
|
27
|
+
|
|
28
|
+
## Configure
|
|
29
|
+
|
|
30
|
+
Open **Modern-MediaStudio → Settings**.
|
|
31
|
+
|
|
32
|
+
### Image provider
|
|
33
|
+
|
|
34
|
+
Any service compatible with the OpenAI Images API works:
|
|
35
|
+
|
|
36
|
+
- generate: `POST {baseUrl}/images/generations`
|
|
37
|
+
- edit with a reference image: `POST {baseUrl}/images/edits` (multipart, field `image`)
|
|
38
|
+
|
|
39
|
+
Presets are included for OpenAI, SiliconFlow, Zhipu BigModel and Volcano Ark. Responses in `data[0].b64_json` and `images[0].url` shapes are supported. Use **Test image** to verify the endpoint.
|
|
40
|
+
|
|
41
|
+
### Video provider
|
|
42
|
+
|
|
43
|
+
The adapter expects the common asynchronous shape:
|
|
44
|
+
|
|
45
|
+
```text
|
|
46
|
+
POST {baseUrl}{createPath} -> task id
|
|
47
|
+
GET {baseUrl}{statusPath} -> queued / in_progress / completed / failed
|
|
48
|
+
GET {baseUrl}{contentPath} -> video bytes (or a URL in the status response)
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
`{id}` is replaced with the task id. Both paths are configurable. If you do not have a video provider, switch to **Storyboard**: it generates four keyframes with the image provider and plays them in the browser.
|
|
52
|
+
|
|
53
|
+
### Writing
|
|
54
|
+
|
|
55
|
+
No extra key. Writing uses the model selected in DSH. The plugin does not store DSH credentials.
|
|
56
|
+
|
|
57
|
+
## Data and security
|
|
58
|
+
|
|
59
|
+
- Data directory: `$DSH_HOME/media-workbench-modern/` (defaults to `~/.dsh/media-workbench-modern/`)
|
|
60
|
+
- `state.json` — images, videos, documents, Star Maps, blueprints
|
|
61
|
+
- `settings.json` — provider endpoints, model names and keys, mode `600`
|
|
62
|
+
- `files/` — generated media and uploaded references
|
|
63
|
+
- Provider keys never reach the browser; the UI only receives `hasKey` and the last four characters.
|
|
64
|
+
- Write routes validate the DSH connection service and same-origin headers. Static files are whitelisted. Generated files use a strict name pattern.
|
|
65
|
+
- Remote image/video URLs are checked before download; loopback, private, link-local and metadata addresses are rejected.
|
|
66
|
+
- Imported Star Maps are normalized: unknown nodes, dangling/duplicate/type-incompatible/cyclic edges are dropped.
|
|
67
|
+
|
|
68
|
+
See [SECURITY.md](SECURITY.md) for the full model.
|
|
69
|
+
|
|
70
|
+
## Model tools
|
|
71
|
+
|
|
72
|
+
The plugin registers five tools so DSH can use the workbench from a conversation:
|
|
73
|
+
|
|
74
|
+
| Tool | Purpose |
|
|
75
|
+
| --- | --- |
|
|
76
|
+
| `modern_media_generate_image` | Generate 1–2 images into the image history and return local paths |
|
|
77
|
+
| `modern_media_save_document` | Save a manuscript into Writing Studio |
|
|
78
|
+
| `modern_media_generate_video` | Generate a video or Storyboard, waiting by default |
|
|
79
|
+
| `modern_media_run_star_map` | Run an existing Star Map or create one from a template and run it |
|
|
80
|
+
| `modern_media_workspace_overview` | List recent images, videos, documents and Star Maps |
|
|
81
|
+
|
|
82
|
+
## Development
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
node tools/dev-server.mjs # standalone preview, http://127.0.0.1:7788/media-workbench-modern/
|
|
86
|
+
node --test tools/verify.mjs # offline tests: DAG, import repair, storage, key masking, prompts
|
|
87
|
+
npm pack # build an installable .tgz
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
The preview does not start DSH and needs no keys: image/video use local mocks and writing uses a mock stream. Preview data lives in `.dev-home/`.
|
|
91
|
+
|
|
92
|
+
```text
|
|
93
|
+
src/ host half: routes, storage, providers, writing prompts, Star Map execution, model tools
|
|
94
|
+
lib/client.js browser half: sidebar entry + iframe panel
|
|
95
|
+
web/ workbench UI as native ES modules (no build step)
|
|
96
|
+
tools/ standalone preview and offline tests
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Known limitations
|
|
100
|
+
|
|
101
|
+
- Video provider APIs differ; the generic adapter may need custom paths or extra JSON for a specific vendor.
|
|
102
|
+
- Without a video provider there is no local mp4 encoding — Storyboard is the fallback.
|
|
103
|
+
- One active image provider configuration (no multi-key rotation).
|
|
104
|
+
- Narrow layouts collapse the document list, node palette and inspector.
|
|
105
|
+
|
|
106
|
+
## License
|
|
107
|
+
|
|
108
|
+
MIT. Not affiliated with DeepSeek; DSH names and marks belong to their owners.
|
package/README.md
CHANGED
|
@@ -1,3 +1,139 @@
|
|
|
1
|
-
#
|
|
1
|
+
# 摩登-媒体工作室 · @exccoder/dsh-media-workbench
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
一个 DeepSeek Harness(DSH)插件。装上之后,DSH 侧栏会多一个「摩登-媒体工作室」,里面是四个连在一起的工作台:
|
|
4
|
+
|
|
5
|
+
- **生图工作台**:一句话出图,风格、画幅、数量、最多 8 张参考图队列、收藏与历史。
|
|
6
|
+
- **视频工作台**:文生视频、图生视频,以及不消耗视频额度的「分镜短片」。
|
|
7
|
+
- **写作工作台**:作品库、长文编辑器、续写/润色/扩写/改写/大纲/起标题,流式生成。
|
|
8
|
+
- **星图工作台**:把提示词、写作、图像、视频接成 DAG,逐波并行运行,可存成蓝图复用。
|
|
9
|
+
|
|
10
|
+
写作走 DSH 当前默认模型;生图和视频各自配置自己的接口。作品、图片、视频、星图都留在本机,不上传云端。界面支持中文 / English,并跟随 DSH 的语言和明暗主题。
|
|
11
|
+
|
|
12
|
+
GitHub:[ExcCoder/modern-dsh-media-workbench](https://github.com/ExcCoder/modern-dsh-media-workbench)
|
|
13
|
+
|
|
14
|
+
## 界面
|
|
15
|
+
|
|
16
|
+
| 生图工作台 | 写作工作台 |
|
|
17
|
+
| --- | --- |
|
|
18
|
+
|  |  |
|
|
19
|
+
| **星图工作台** | **视频工作台** |
|
|
20
|
+
|  |  |
|
|
21
|
+
|
|
22
|
+
> 截图里的画是本地 mock 生图生成的占位图,用来演示链路;接上真实生图服务后就是模型出的图。
|
|
23
|
+
|
|
24
|
+
## 安装
|
|
25
|
+
|
|
26
|
+
要求 DSH `0.2.x`(插件在 `0.2.2-rc.1` 上验证)。
|
|
27
|
+
|
|
28
|
+
**方式一:插件管理。** 在 DSH 里打开「插件 → 添加插件」,选择本目录(或打包后的 tgz)。
|
|
29
|
+
|
|
30
|
+
**方式二:命令行。**
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
# 发布到 npm 之后
|
|
34
|
+
dsh plugin --profile desktop add @exccoder/dsh-media-workbench
|
|
35
|
+
|
|
36
|
+
# 从本地目录安装
|
|
37
|
+
dsh plugin --profile desktop add /absolute/path/to/dsh-media-workbench
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
装好后**完全退出 DSH 再打开**,侧栏出现「摩登-媒体工作室」。卸载用 `remove @exccoder/dsh-media-workbench`;你的作品在 `~/.dsh/media-workbench-modern/`,不会跟着删。
|
|
41
|
+
|
|
42
|
+
> 本地目录安装会以 `link:` 方式直接引用源码;想把插件挪到别处或打包分发,用 `npm pack` 生成 tgz 再安装。
|
|
43
|
+
|
|
44
|
+
## 第一次使用
|
|
45
|
+
|
|
46
|
+
### 生图
|
|
47
|
+
|
|
48
|
+
1. 打开「设置 → 生图服务」,选一个预设(OpenAI / 硅基流动 / 智谱 / 火山方舟),或选「自定义」。
|
|
49
|
+
2. 填接口地址、模型和密钥,保存,点「试画一张」确认能通。
|
|
50
|
+
3. 回生图工作台写提示词,选风格和画幅,生成。
|
|
51
|
+
|
|
52
|
+
任何兼容 OpenAI Images API 的服务都能用:`POST {baseUrl}/images/generations`;上传参考图时走 `POST {baseUrl}/images/edits`(multipart,单张字段 `image`,多张按顺序用 `image[]`)。返回 `data[0].b64_json`、`images[0].url` 两种常见形状都支持。
|
|
53
|
+
|
|
54
|
+
参考图支持拖入、文件多选和 **Ctrl+V 粘贴**,最多 8 张,按「图一、图二…」编号,可以上移/下移。图片右键可以复制图片到剪贴板、下载原图、复制提示词或打开所在目录;复用带参考图的记录时会询问是覆盖当前参考图,还是只复用提示词。
|
|
55
|
+
|
|
56
|
+
### 视频
|
|
57
|
+
|
|
58
|
+
- **文生视频 / 图生视频**:填接口地址、模型、密钥,默认按 `POST /videos` 创建、`GET /videos/{id}` 轮询、`GET /videos/{id}/content` 取文件。路径可以在设置里改,`{id}` 会替换成任务 id。
|
|
59
|
+
- **分镜短片**:不需要视频服务,用生图服务画 4 张关键帧,在浏览器里按节奏交叉淡入播放,也可以逐张下载。
|
|
60
|
+
|
|
61
|
+
视频任务在后台继续跑,离开这一页不会中断。
|
|
62
|
+
|
|
63
|
+
### 写作
|
|
64
|
+
|
|
65
|
+
写作不需要额外密钥,直接用 DSH 里选好的模型。左边是作品库,中间写,右边是写作搭档:
|
|
66
|
+
|
|
67
|
+
- 选中一段文字,勾上「只处理选中文字」,点「润色」「扩写」「改写」就只改这一段。
|
|
68
|
+
- 生成是流式的,可以随时停;结果可以追加、替换、插入光标、复制或丢弃。
|
|
69
|
+
- 正文自动保存到本机,导出为 Markdown。
|
|
70
|
+
|
|
71
|
+
### 星图
|
|
72
|
+
|
|
73
|
+
- 左侧节点库点一下加节点;从节点右侧圆点拖到另一个节点的输入端口就连线。
|
|
74
|
+
- 连线会检查类型(文本 / 图像 / 视频 / 作品)、单输入限制和环路,不合法会直接说明原因。
|
|
75
|
+
- 「运行」按拓扑波次并行;失败的上游只阻断它的后代,其他分支继续跑。
|
|
76
|
+
- 选中节点可以「运行到这里」,只跑它和它的祖先。
|
|
77
|
+
- 「更多 → 保存为蓝图」把当前结构存下来(不含运行结果),之后从「更多 → 我的蓝图」整张复用。
|
|
78
|
+
|
|
79
|
+
快捷键:`Ctrl/Cmd+Enter` 运行,`Delete` 删除选中的节点或连线,`Ctrl/Cmd+Z` 撤销,`F` 适应画布,滚轮缩放,拖空白平移,双击画布加提示词节点。
|
|
80
|
+
|
|
81
|
+
## 给智能体的工具
|
|
82
|
+
|
|
83
|
+
插件同时注册了 5 个模型工具,所以 DSH 在对话里也能直接用工作台:
|
|
84
|
+
|
|
85
|
+
| 工具 | 作用 |
|
|
86
|
+
| --- | --- |
|
|
87
|
+
| `modern_media_generate_image` | 按提示词生成 1–2 张图,存进生图历史,返回本机路径 |
|
|
88
|
+
| `modern_media_save_document` | 把稿子保存进写作工作台 |
|
|
89
|
+
| `modern_media_generate_video` | 生成视频或分镜短片,默认等到完成 |
|
|
90
|
+
| `modern_media_run_star_map` | 运行一张星图,或从模板新建后运行 |
|
|
91
|
+
| `modern_media_workspace_overview` | 看最近的作品、文档和星图,方便接着做 |
|
|
92
|
+
|
|
93
|
+
## 数据与安全
|
|
94
|
+
|
|
95
|
+
- 数据目录:`$DSH_HOME/media-workbench-modern/`(默认 `~/.dsh/media-workbench-modern/`)。图片和视频的文件主目录可以在「设置 → 作品文件目录」换到其他盘,保存时会迁移已有文件并删除旧文件;作品记录和设置仍留在默认数据目录。
|
|
96
|
+
- `state.json`:图片/视频记录、写作文档、星图、蓝图
|
|
97
|
+
- `settings.json`:接口地址、模型、密钥,权限 `600`
|
|
98
|
+
- `files/`:生成的图片、视频和上传的参考图
|
|
99
|
+
- 密钥只存在本机,返回浏览器时只给「有没有密钥」和尾四位。
|
|
100
|
+
- 所有写接口校验同源与 DSH 登录凭据;静态文件只服务 `web/` 白名单;文件下载只接受 `files/` 下的安全文件名。
|
|
101
|
+
- 下载远端图片/视频前会拒绝本机、内网和云元数据地址,避免 SSRF。
|
|
102
|
+
- 模型输出、导入的星图都按固定字段和数量上限收敛;星图导入会丢弃悬空、重复、类型不符和成环的连线。
|
|
103
|
+
|
|
104
|
+
## 开发
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
node tools/dev-server.mjs # 本地预览:http://127.0.0.1:7788/media-workbench-modern/
|
|
108
|
+
node --test tools/verify.mjs # 离线验证:DAG、导入修复、存储、密钥脱敏、提示词
|
|
109
|
+
npm pack # 打出可安装的 tgz
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
本地预览不启动 DSH,也不需要密钥:生图和视频走内置 mock,写作走本地假流。预览数据在 `.dev-home/`,删掉即可重来。
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
src/ host 半片:HTTP 路由、本机存储、生图/视频/写作/星图执行、模型工具
|
|
116
|
+
lib/client.js 浏览器半片:侧栏入口 + 主区域 iframe
|
|
117
|
+
web/ 工作台界面(原生 ES modules,无构建步骤)
|
|
118
|
+
tools/ 本地预览和离线验证脚本
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## 已知限制
|
|
122
|
+
|
|
123
|
+
- 视频接口各家差异较大。当前按「异步任务 + 轮询」的通用形状实现,特殊服务商需要在设置里改路径或参数;不兼容时会给出明确错误,不会静默降级。
|
|
124
|
+
- 没有视频服务时,只有「分镜短片」模式可用(4 张关键帧),不会在本地合成 mp4。
|
|
125
|
+
- 生图密钥只支持单个当前配置,不做多账号轮换。
|
|
126
|
+
- 移动端窄屏会收起作品库、星图节点库和检查器;它们的主要操作仍可在画布或设置里完成。
|
|
127
|
+
|
|
128
|
+
## 开源与发布
|
|
129
|
+
|
|
130
|
+
- 许可证:MIT,见 [LICENSE](LICENSE)。
|
|
131
|
+
- 变更记录:[CHANGELOG.md](CHANGELOG.md)。
|
|
132
|
+
- 安全问题:[SECURITY.md](SECURITY.md)。
|
|
133
|
+
- 参与开发:[CONTRIBUTING.md](CONTRIBUTING.md)。
|
|
134
|
+
- 发布到 npm / GitHub 的步骤:[PUBLISHING.md](PUBLISHING.md)。
|
|
135
|
+
- npm 包名 `@exccoder/dsh-media-workbench` 使用 npm 账号 `exccoder` 的用户 scope,发布不需要组织权限;改用其他 scope 时需要同步四处包名,见 [PUBLISHING.md](PUBLISHING.md)。
|
|
136
|
+
|
|
137
|
+
## 许可
|
|
138
|
+
|
|
139
|
+
MIT。与 DeepSeek 官方无关;DSH 的名称和标识归其所有者。
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
## Supported versions
|
|
4
|
+
|
|
5
|
+
| Version | Supported |
|
|
6
|
+
| --- | --- |
|
|
7
|
+
| 0.1.x | Yes |
|
|
8
|
+
|
|
9
|
+
## Reporting a vulnerability
|
|
10
|
+
|
|
11
|
+
Please **do not** open a public issue for a vulnerability. Use the repository's **Security → Report a vulnerability** (GitHub Security Advisories) so the report stays private until a fix is ready.
|
|
12
|
+
|
|
13
|
+
Include the version, a minimal reproduction, the affected endpoint or file, and whether an API key or local file could be exposed. We aim to acknowledge reports within a few days.
|
|
14
|
+
|
|
15
|
+
## Security model
|
|
16
|
+
|
|
17
|
+
- API keys for image/video providers are stored only in `$DSH_HOME/media-workbench-modern/settings.json` with mode `600`. They are never returned to the browser; the UI receives only `hasKey` and the last four characters.
|
|
18
|
+
- Writing uses the DSH-selected model. The plugin does not store DSH credentials.
|
|
19
|
+
- Every write request checks the DSH connection service and same-origin `Origin`/`Sec-Fetch-Site` headers.
|
|
20
|
+
- Static files are served from a whitelist under `web/`; generated files are served only from `files/` with a strict file-name pattern.
|
|
21
|
+
- Remote image/video URLs are checked before download and private, loopback, link-local and cloud-metadata addresses are rejected.
|
|
22
|
+
- Imported Star Maps are normalized: unknown node types, dangling/duplicate/type-incompatible/cyclic edges, and oversized collections are dropped.
|
|
23
|
+
- The plugin has no telemetry and makes no network request except to the provider endpoints and media URLs the user configured.
|
|
24
|
+
|
|
25
|
+
## User responsibilities
|
|
26
|
+
|
|
27
|
+
- Treat provider API keys as secrets; do not paste them into issue reports, screenshots or prompts.
|
|
28
|
+
- Review a Star Map before running it if it was imported from an untrusted source.
|
|
29
|
+
- Provider-side retention, pricing and content policies are outside this plugin's control.
|
package/cordis.patch.yml
ADDED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/lib/client.js
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
// @exccoder/dsh-media-workbench · 浏览器半片
|
|
2
|
+
// 在侧栏加一个「摩登-媒体工作室」入口,主区域是插件自己的页面(同源 iframe)。
|
|
3
|
+
// 主题和语言从 DSH 服务同步,页面内不再重复判断。
|
|
4
|
+
window.__ModuleLoader__.load({
|
|
5
|
+
id: '@exccoder/dsh-media-workbench',
|
|
6
|
+
factory: (require) => {
|
|
7
|
+
const module = { exports: {} }
|
|
8
|
+
const exports = module.exports
|
|
9
|
+
const React = require('react')
|
|
10
|
+
const h = React.createElement
|
|
11
|
+
const PANEL = 'media-workbench-modern'
|
|
12
|
+
const SRC = '/media-workbench-modern/'
|
|
13
|
+
|
|
14
|
+
const LABEL = { zh: '摩登-媒体工作室', en: 'Modern-MediaStudio' }
|
|
15
|
+
const TITLE = { zh: '摩登-媒体工作室:生图、写作、星图与视频', en: 'Modern-MediaStudio: image, writing, star map and video' }
|
|
16
|
+
|
|
17
|
+
let lang = /^en\b/i.test(navigator.language) ? 'en' : 'zh'
|
|
18
|
+
let scheme = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
|
|
19
|
+
const frames = new Set()
|
|
20
|
+
|
|
21
|
+
function post(frame, message) {
|
|
22
|
+
try {
|
|
23
|
+
if (frame && frame.contentWindow) frame.contentWindow.postMessage(message, location.origin)
|
|
24
|
+
} catch { /* iframe 还没加载好 */ }
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function pushTheme(frame) {
|
|
28
|
+
post(frame, { type: 'media-workbench-modern:theme', scheme })
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function pushLocale(frame) {
|
|
32
|
+
post(frame, { type: 'media-workbench-modern:locale', lang })
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function StudioIcon({ size }) {
|
|
36
|
+
const s = size || 18
|
|
37
|
+
return h(
|
|
38
|
+
'svg',
|
|
39
|
+
{ width: s, height: s, viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: 1.6, strokeLinecap: 'round', strokeLinejoin: 'round', 'aria-hidden': 'true' },
|
|
40
|
+
h('path', { d: 'M12 3.2 13.7 8.3 18.8 10 13.7 11.7 12 16.8 10.3 11.7 5.2 10 10.3 8.3z' }),
|
|
41
|
+
h('path', { d: 'M18.4 15.2 19.2 17.6 21.6 18.4 19.2 19.2 18.4 21.6 17.6 19.2 15.2 18.4 17.6 17.6z' }),
|
|
42
|
+
h('path', { d: 'M5.6 15.6 6.2 17.2 7.8 17.8 6.2 18.4 5.6 20 5 18.4 3.4 17.8 5 17.2z' }),
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function StudioPanel() {
|
|
47
|
+
const ref = React.useRef(null)
|
|
48
|
+
const [src] = React.useState(() => `${SRC}?lang=${lang}&theme=${scheme}`)
|
|
49
|
+
React.useEffect(() => {
|
|
50
|
+
const host = ref.current
|
|
51
|
+
if (!host) return
|
|
52
|
+
const frame = document.createElement('iframe')
|
|
53
|
+
frame.src = src
|
|
54
|
+
frame.title = TITLE[lang]
|
|
55
|
+
frame.allow = 'clipboard-write; fullscreen'
|
|
56
|
+
frame.style.border = '0'
|
|
57
|
+
frame.style.display = 'block'
|
|
58
|
+
frame.style.background = 'transparent'
|
|
59
|
+
frame.style.position = 'fixed'
|
|
60
|
+
frame.style.zIndex = '1'
|
|
61
|
+
frame.addEventListener('load', () => {
|
|
62
|
+
pushTheme(frame)
|
|
63
|
+
pushLocale(frame)
|
|
64
|
+
})
|
|
65
|
+
document.body.appendChild(frame)
|
|
66
|
+
frames.add(frame)
|
|
67
|
+
const fit = () => {
|
|
68
|
+
const box = host.getBoundingClientRect()
|
|
69
|
+
if (box.width < 200 || box.height < 80) {
|
|
70
|
+
frame.style.display = 'none'
|
|
71
|
+
return
|
|
72
|
+
}
|
|
73
|
+
frame.style.display = 'block'
|
|
74
|
+
frame.style.top = `${box.top}px`
|
|
75
|
+
frame.style.left = `${box.left}px`
|
|
76
|
+
frame.style.width = `${box.width}px`
|
|
77
|
+
frame.style.height = `${Math.max(200, window.innerHeight - box.top)}px`
|
|
78
|
+
}
|
|
79
|
+
requestAnimationFrame(fit)
|
|
80
|
+
const timer = setTimeout(fit, 80)
|
|
81
|
+
const observer = new ResizeObserver(fit)
|
|
82
|
+
observer.observe(host)
|
|
83
|
+
window.addEventListener('resize', fit)
|
|
84
|
+
return () => {
|
|
85
|
+
clearTimeout(timer)
|
|
86
|
+
observer.disconnect()
|
|
87
|
+
window.removeEventListener('resize', fit)
|
|
88
|
+
frames.delete(frame)
|
|
89
|
+
frame.remove()
|
|
90
|
+
}
|
|
91
|
+
}, [])
|
|
92
|
+
return h('div', { ref, style: { width: '100%', height: '100%', minHeight: '100%' } })
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function apply(ctx) {
|
|
96
|
+
// 主题跟随:拿到快照后同步给 iframe,切换时再推一次
|
|
97
|
+
try {
|
|
98
|
+
ctx.inject(['theme'], c => {
|
|
99
|
+
const push = snapshot => {
|
|
100
|
+
const next = snapshot?.active?.colorScheme
|
|
101
|
+
if (next === 'dark' || next === 'light') scheme = next
|
|
102
|
+
frames.forEach(pushTheme)
|
|
103
|
+
}
|
|
104
|
+
push(c.theme.getTheme())
|
|
105
|
+
c.on('theme/change', push)
|
|
106
|
+
})
|
|
107
|
+
} catch { /* 旧版本没有 theme 服务 */ }
|
|
108
|
+
|
|
109
|
+
// 语言跟随
|
|
110
|
+
try {
|
|
111
|
+
ctx.inject(['locale'], c => {
|
|
112
|
+
const push = snapshot => {
|
|
113
|
+
const active = snapshot?.active
|
|
114
|
+
const value = typeof active === 'string' ? active : active?.lang ?? active?.id
|
|
115
|
+
if (typeof value === 'string') lang = value.toLowerCase().startsWith('en') ? 'en' : 'zh'
|
|
116
|
+
frames.forEach(pushLocale)
|
|
117
|
+
}
|
|
118
|
+
push(c.locale.getSnapshot())
|
|
119
|
+
c.on('locale/change', push)
|
|
120
|
+
})
|
|
121
|
+
} catch { /* 旧版本没有 locale 服务 */ }
|
|
122
|
+
|
|
123
|
+
ctx.slots.inject('sidebar.panellist', () => ctx.slots.register({
|
|
124
|
+
name: 'sidebar.panellist',
|
|
125
|
+
id: PANEL,
|
|
126
|
+
order: 4,
|
|
127
|
+
label: () => LABEL[lang],
|
|
128
|
+
}, StudioIcon))
|
|
129
|
+
|
|
130
|
+
ctx.slots.inject('main', () => ctx.slots.register({ name: 'main', key: PANEL }, StudioPanel))
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
exports.isPlugin = true
|
|
134
|
+
exports.inject = ['slots']
|
|
135
|
+
exports.apply = apply
|
|
136
|
+
return module.exports
|
|
137
|
+
},
|
|
138
|
+
})
|
package/package.json
CHANGED
|
@@ -1,6 +1,81 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exccoder/dsh-media-workbench",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.2.2",
|
|
4
|
+
"description": "DeepSeek Harness 插件「摩登-媒体工作室」:生图、写作、星图、视频四个工作台,带本机作品库与星图 DAG 编排。",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "src/index.js",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./src/index.js",
|
|
9
|
+
"./client": "./lib/client.js",
|
|
10
|
+
"./cordis.patch.yml": "./cordis.patch.yml",
|
|
11
|
+
"./package.json": "./package.json"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"src",
|
|
15
|
+
"lib",
|
|
16
|
+
"web",
|
|
17
|
+
"docs",
|
|
18
|
+
"cordis.patch.yml",
|
|
19
|
+
"README.md",
|
|
20
|
+
"README.en.md",
|
|
21
|
+
"CHANGELOG.md",
|
|
22
|
+
"SECURITY.md",
|
|
23
|
+
"LICENSE"
|
|
24
|
+
],
|
|
25
|
+
"icon": "./web/favicon.svg",
|
|
26
|
+
"publishConfig": {
|
|
27
|
+
"access": "public"
|
|
28
|
+
},
|
|
29
|
+
"dsh": {
|
|
30
|
+
"bundle": {
|
|
31
|
+
"patch": "./cordis.patch.yml"
|
|
32
|
+
},
|
|
33
|
+
"client": {
|
|
34
|
+
"platform": "web",
|
|
35
|
+
"inject": []
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"engines": {
|
|
39
|
+
"node": ">=20",
|
|
40
|
+
"dsh": ">=0.2.1-rc.5 <0.3.0"
|
|
41
|
+
},
|
|
42
|
+
"keywords": [
|
|
43
|
+
"dsh",
|
|
44
|
+
"deepseek-harness",
|
|
45
|
+
"dsh-plugin",
|
|
46
|
+
"creative-studio",
|
|
47
|
+
"modern-media",
|
|
48
|
+
"media-studio",
|
|
49
|
+
"image-generation",
|
|
50
|
+
"writing",
|
|
51
|
+
"video",
|
|
52
|
+
"storyboard",
|
|
53
|
+
"workflow",
|
|
54
|
+
"dag",
|
|
55
|
+
"constellation"
|
|
56
|
+
],
|
|
57
|
+
"license": "MIT",
|
|
58
|
+
"author": "ExcCoder",
|
|
59
|
+
"repository": {
|
|
60
|
+
"type": "git",
|
|
61
|
+
"url": "git+https://github.com/ExcCoder/modern-dsh-media-workbench.git"
|
|
62
|
+
},
|
|
63
|
+
"homepage": "https://github.com/ExcCoder/modern-dsh-media-workbench#readme",
|
|
64
|
+
"bugs": {
|
|
65
|
+
"url": "https://github.com/ExcCoder/modern-dsh-media-workbench/issues"
|
|
66
|
+
},
|
|
67
|
+
"scripts": {
|
|
68
|
+
"dev": "node tools/dev-server.mjs",
|
|
69
|
+
"verify": "node --test tools/verify.mjs",
|
|
70
|
+
"test": "node --test tools/verify.mjs",
|
|
71
|
+
"pack": "npm pack"
|
|
72
|
+
},
|
|
73
|
+
"peerDependencies": {
|
|
74
|
+
"react": "^18.2.0 || ^19.0.0"
|
|
75
|
+
},
|
|
76
|
+
"peerDependenciesMeta": {
|
|
77
|
+
"react": {
|
|
78
|
+
"optional": true
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|