@guowenzhang/dsh-whiteboard 0.2.0 → 0.2.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.md +37 -29
- package/README.zh.md +37 -29
- package/docs/images/editor.png +0 -0
- package/docs/images/gallery.png +0 -0
- package/docs/images/new-board.png +0 -0
- package/lib/client.js +63 -5
- package/package.json +64 -20
package/README.md
CHANGED
|
@@ -1,29 +1,37 @@
|
|
|
1
|
-
# dsh-whiteboard
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
##
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
1
|
+
# dsh-whiteboard
|
|
2
|
+
|
|
3
|
+
Whiteboards for DeepSeek Harness: a board gallery in the main panel and draw.io editing in the Sidebar, with boards stored inside the plugin. No workspace selection is needed: a dedicated session grants write access to the plugin's `files/` directory.
|
|
4
|
+
|
|
5
|
+
## Screenshots
|
|
6
|
+
|
|
7
|
+

|
|
8
|
+
|
|
9
|
+

|
|
10
|
+
|
|
11
|
+

|
|
12
|
+
|
|
13
|
+
## Install
|
|
14
|
+
|
|
15
|
+
Install and enable [`@guowenzhang/dsh-drawioedit`](../dsh-drawioedit) first, then this plugin:
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
npx @deepseek-ai/dsh plugin --profile web add @guowenzhang/dsh-drawioedit
|
|
19
|
+
npx @deepseek-ai/dsh plugin --profile web add @guowenzhang/dsh-whiteboard
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
From the npm registry: <https://www.npmjs.com/package/@guowenzhang/dsh-whiteboard> — restart the host afterwards; local checkouts, git sources and troubleshooting are in [AGENTS.md](AGENTS.md).
|
|
23
|
+
|
|
24
|
+
Restart DSH Web and open **Whiteboards** in the left navigation. **New whiteboard** first opens a dialog with an editable timestamp-based name. Only **Create** writes the `.drawio` file under the plugin's `files/` directory and opens it in drawioedit. Drawioedit autosaves changes. Each card shows its name, a first-page preview, and last modification time. Click the card to edit, or click the top-right X and confirm to delete the file. The persistent search box in the toolbar filters the loaded cards by name and shows an empty-result hint when nothing matches. Returning to the **Whiteboards** page goes straight back to the board whose editor tab is still open — collapsing the Sidebar or switching pages keeps it — and only an explicit tab close, a deleted board or a replaced file leaves you on the gallery. Oversized or unreadable diagrams show a preview placeholder. On desktop, opening a board expands the editor column to fullscreen so draw.io can show its own left shapes palette and right format panel; leaving fullscreen shows the board gallery on the left and keeps the current editor on the right, rather than exposing a blank Conversation. Collapsing the editor also keeps the gallery available; click a card to continue editing.
|
|
25
|
+
|
|
26
|
+
New whiteboards have a single `.drawio` file. Legacy UUID files and their sidecars remain visible. Back up `files/` before replacing or uninstalling the plugin.
|
|
27
|
+
|
|
28
|
+
## Development
|
|
29
|
+
|
|
30
|
+
```sh
|
|
31
|
+
npm ci --legacy-peer-deps
|
|
32
|
+
npm run typecheck
|
|
33
|
+
npm run build
|
|
34
|
+
npm test
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Commit the generated `lib/` with source changes. `dsh-drawioedit` supplies the editor assets at runtime.
|
package/README.zh.md
CHANGED
|
@@ -1,29 +1,37 @@
|
|
|
1
|
-
# dsh-whiteboard
|
|
2
|
-
|
|
3
|
-
DeepSeek Harness
|
|
4
|
-
|
|
5
|
-
##
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
1
|
+
# dsh-whiteboard
|
|
2
|
+
|
|
3
|
+
为 DeepSeek Harness 提供白板:主面板是白板卡片列表,右侧边栏用 draw.io 编辑,白板文件保存在插件内。无需选择工作区:白板为该目录创建专用会话并授予写入权限。
|
|
4
|
+
|
|
5
|
+
## 界面截图
|
|
6
|
+
|
|
7
|
+

|
|
8
|
+
|
|
9
|
+

|
|
10
|
+
|
|
11
|
+

|
|
12
|
+
|
|
13
|
+
## 安装
|
|
14
|
+
|
|
15
|
+
先安装并启用 [`@guowenzhang/dsh-drawioedit`](../dsh-drawioedit),再安装本插件:
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
npx @deepseek-ai/dsh plugin --profile web add @guowenzhang/dsh-drawioedit
|
|
19
|
+
npx @deepseek-ai/dsh plugin --profile web add @guowenzhang/dsh-whiteboard
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
来自 npm 官方源:<https://www.npmjs.com/package/@guowenzhang/dsh-whiteboard>。装完重启宿主;本地目录开发安装、git 源与排查见 [AGENTS.md](AGENTS.md)。
|
|
23
|
+
|
|
24
|
+
重启 DSH Web 后,打开左侧导航中的“白板”。点击“新建白板”会先显示命名对话框,默认填入时间名称,可直接修改;只有点击“确认创建”才会在插件 `files/` 目录创建 `.drawio` 文件并交给 drawioedit 打开。绘图内容由 drawioedit 自动保存。卡片显示名称、第一页缩略图和最近修改时间;点击卡片可继续编辑,点击右上角叉号并确认可删除文件。工具条上的搜索框按名称筛选当前卡片列表,不匹配时显示空结果提示。再次进入“白板”页时,如果上一块白板的编辑标签仍开着(只是收起过侧边栏或切到过别的页面),会直接回到那块白板;只有主动关闭标签、或该文件已被删除或替换,才会停在白板列表。过大或无法解析的图表显示预览占位内容。桌面端打开白板时右侧编辑列展开为全屏,编辑器可以完整显示自己的左侧形状面板和右侧格式面板;取消全屏后,左侧显示白板列表、右侧保留当前编辑器,不会露出“新建会话”页面;收起编辑列时也保留白板列表,再点卡片可继续编辑。
|
|
25
|
+
|
|
26
|
+
新白板只有一个 `.drawio` 文件;旧版 UUID 文件和元数据仍可显示。替换或卸载插件前请备份 `files/` 目录。
|
|
27
|
+
|
|
28
|
+
## 开发
|
|
29
|
+
|
|
30
|
+
```sh
|
|
31
|
+
npm ci --legacy-peer-deps
|
|
32
|
+
npm run typecheck
|
|
33
|
+
npm run build
|
|
34
|
+
npm test
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
修改源码后须重新构建并提交 `lib/`。`dsh-drawioedit` 在运行时提供编辑器资源。
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/lib/client.js
CHANGED
|
@@ -187,7 +187,7 @@ window.__ModuleLoader__.load({
|
|
|
187
187
|
};
|
|
188
188
|
//#endregion
|
|
189
189
|
//#region src/client/last-board.ts
|
|
190
|
-
const STORAGE_KEY = "dsh.whiteboard.v1.last-board";
|
|
190
|
+
const STORAGE_KEY$1 = "dsh.whiteboard.v1.last-board";
|
|
191
191
|
function storage() {
|
|
192
192
|
try {
|
|
193
193
|
return typeof window === "undefined" ? void 0 : window.localStorage;
|
|
@@ -200,7 +200,7 @@ window.__ModuleLoader__.load({
|
|
|
200
200
|
const store = storage();
|
|
201
201
|
if (!store) return void 0;
|
|
202
202
|
try {
|
|
203
|
-
const raw = store.getItem(STORAGE_KEY);
|
|
203
|
+
const raw = store.getItem(STORAGE_KEY$1);
|
|
204
204
|
if (raw === null) return void 0;
|
|
205
205
|
const value = JSON.parse(raw);
|
|
206
206
|
if (typeof value !== "object" || value === null) return void 0;
|
|
@@ -220,7 +220,7 @@ window.__ModuleLoader__.load({
|
|
|
220
220
|
const store = storage();
|
|
221
221
|
if (!store) return;
|
|
222
222
|
try {
|
|
223
|
-
store.setItem(STORAGE_KEY, JSON.stringify({
|
|
223
|
+
store.setItem(STORAGE_KEY$1, JSON.stringify({
|
|
224
224
|
id: board.id,
|
|
225
225
|
title: board.title,
|
|
226
226
|
updatedAt: board.updatedAt
|
|
@@ -232,7 +232,7 @@ window.__ModuleLoader__.load({
|
|
|
232
232
|
const store = storage();
|
|
233
233
|
if (!store) return;
|
|
234
234
|
try {
|
|
235
|
-
store.removeItem(STORAGE_KEY);
|
|
235
|
+
store.removeItem(STORAGE_KEY$1);
|
|
236
236
|
} catch {}
|
|
237
237
|
}
|
|
238
238
|
/**
|
|
@@ -30894,6 +30894,60 @@ segment: 30 };
|
|
|
30894
30894
|
});
|
|
30895
30895
|
}
|
|
30896
30896
|
//#endregion
|
|
30897
|
+
//#region src/client/board-session.ts
|
|
30898
|
+
const STORAGE_KEY = "dsh.whiteboard.v1.session";
|
|
30899
|
+
/** The dedicated editor Session survives reloads; it is not a chat destination. */
|
|
30900
|
+
function readBoardSession() {
|
|
30901
|
+
try {
|
|
30902
|
+
return window.localStorage?.getItem(STORAGE_KEY) || void 0;
|
|
30903
|
+
} catch {
|
|
30904
|
+
return;
|
|
30905
|
+
}
|
|
30906
|
+
}
|
|
30907
|
+
function writeBoardSession(sessionId) {
|
|
30908
|
+
try {
|
|
30909
|
+
window.localStorage?.setItem(STORAGE_KEY, sessionId);
|
|
30910
|
+
} catch {}
|
|
30911
|
+
}
|
|
30912
|
+
/**
|
|
30913
|
+
* Replace only a known whiteboard Session's central occupant, not its navigation
|
|
30914
|
+
* or rightbar binding. Selecting the global whiteboard panel here would hide the
|
|
30915
|
+
* rightbar: the Host only exposes it while the Conversation main key is selected.
|
|
30916
|
+
* The normal Conversation registration stays installed underneath this shadow.
|
|
30917
|
+
*/
|
|
30918
|
+
function installBoardSessionPanel(ctx, owned, face) {
|
|
30919
|
+
let reconcile = () => {};
|
|
30920
|
+
ctx.slots.inject("main", () => {
|
|
30921
|
+
let release;
|
|
30922
|
+
reconcile = () => {
|
|
30923
|
+
const sessionId = ctx.sidebarRight.mounted.getSnapshot();
|
|
30924
|
+
const showList = sessionId !== void 0 && owned(sessionId);
|
|
30925
|
+
if (showList && !release) release = ctx.slots.register({
|
|
30926
|
+
name: "main",
|
|
30927
|
+
key: "conversation",
|
|
30928
|
+
priority: -1,
|
|
30929
|
+
locale: NS,
|
|
30930
|
+
inject: () => ({
|
|
30931
|
+
...face,
|
|
30932
|
+
restore: async () => "none"
|
|
30933
|
+
})
|
|
30934
|
+
}, WhiteboardPanel);
|
|
30935
|
+
else if (!showList && release) {
|
|
30936
|
+
release();
|
|
30937
|
+
release = void 0;
|
|
30938
|
+
}
|
|
30939
|
+
};
|
|
30940
|
+
const unsubscribe = ctx.sidebarRight.mounted.subscribe(() => reconcile());
|
|
30941
|
+
reconcile();
|
|
30942
|
+
return () => {
|
|
30943
|
+
unsubscribe();
|
|
30944
|
+
release?.();
|
|
30945
|
+
reconcile = () => {};
|
|
30946
|
+
};
|
|
30947
|
+
});
|
|
30948
|
+
return () => reconcile();
|
|
30949
|
+
}
|
|
30950
|
+
//#endregion
|
|
30897
30951
|
//#region src/client/index.tsx
|
|
30898
30952
|
async function unwrap(call) {
|
|
30899
30953
|
const result = await call;
|
|
@@ -30941,7 +30995,8 @@ segment: 30 };
|
|
|
30941
30995
|
return service;
|
|
30942
30996
|
};
|
|
30943
30997
|
const sessions = ctx.sessions;
|
|
30944
|
-
let lastSessionId;
|
|
30998
|
+
let lastSessionId = readBoardSession();
|
|
30999
|
+
let syncBoardPanel = () => {};
|
|
30945
31000
|
/** The drawio editor tab open for the mounted session: the active tab or a background one. */
|
|
30946
31001
|
const openEditorTab = (sessionId) => {
|
|
30947
31002
|
const known = ctx.sidebarRight.openTabs.getSnapshot().find((tab) => tab.sessionId === sessionId && tab.kind === "drawio-edit");
|
|
@@ -30968,6 +31023,8 @@ segment: 30 };
|
|
|
30968
31023
|
if (!sessionId) sessionId = await sessions.create({ cwd: board.directory });
|
|
30969
31024
|
await unwrap(remote().grantBoardSession({ sessionId }));
|
|
30970
31025
|
lastSessionId = sessionId;
|
|
31026
|
+
writeBoardSession(sessionId);
|
|
31027
|
+
syncBoardPanel();
|
|
30971
31028
|
writeLastBoard(board);
|
|
30972
31029
|
if (ctx.sidebarRight.mounted.getSnapshot() !== sessionId) {
|
|
30973
31030
|
ctx.uiWorkspace.openSession(sessionId);
|
|
@@ -30995,6 +31052,7 @@ segment: 30 };
|
|
|
30995
31052
|
return "reopened";
|
|
30996
31053
|
}
|
|
30997
31054
|
};
|
|
31055
|
+
syncBoardPanel = installBoardSessionPanel(ctx, (id) => id === lastSessionId, face);
|
|
30998
31056
|
ctx.slots.inject("main", () => ctx.slots.register({
|
|
30999
31057
|
name: "main",
|
|
31000
31058
|
key: "whiteboard",
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@guowenzhang/dsh-whiteboard",
|
|
3
|
-
"version": "0.2.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.2.1",
|
|
4
|
+
"description": "Whiteboards for DeepSeek Harness: a board gallery in the main panel and draw.io editing in the Sidebar, with boards stored inside the plugin",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"main": "lib/index.mjs",
|
|
@@ -11,9 +11,14 @@
|
|
|
11
11
|
"./package.json": "./package.json",
|
|
12
12
|
"./cordis.patch.yml": "./cordis.patch.yml"
|
|
13
13
|
},
|
|
14
|
-
"engines": {
|
|
14
|
+
"engines": {
|
|
15
|
+
"node": "^22.19.0 || >=24.0.0",
|
|
16
|
+
"dsh": ">=0.2.0-rc.1"
|
|
17
|
+
},
|
|
15
18
|
"dsh": {
|
|
16
|
-
"bundle": {
|
|
19
|
+
"bundle": {
|
|
20
|
+
"patch": "./cordis.patch.yml"
|
|
21
|
+
},
|
|
17
22
|
"client": {
|
|
18
23
|
"inject": [
|
|
19
24
|
"@deepseek-ai/dsh-api-remotes",
|
|
@@ -29,7 +34,16 @@
|
|
|
29
34
|
"platform": "web"
|
|
30
35
|
}
|
|
31
36
|
},
|
|
32
|
-
"files": [
|
|
37
|
+
"files": [
|
|
38
|
+
"lib",
|
|
39
|
+
"docs",
|
|
40
|
+
"files/README.md",
|
|
41
|
+
"cordis.patch.yml",
|
|
42
|
+
"README.md",
|
|
43
|
+
"README.zh.md",
|
|
44
|
+
"LICENSE",
|
|
45
|
+
"NOTICE"
|
|
46
|
+
],
|
|
33
47
|
"scripts": {
|
|
34
48
|
"build": "tsdown -c tsdown.config.ts && node build-client.mjs",
|
|
35
49
|
"typecheck": "tsc --noEmit -p tsconfig.json",
|
|
@@ -54,21 +68,51 @@
|
|
|
54
68
|
"react": "*"
|
|
55
69
|
},
|
|
56
70
|
"peerDependenciesMeta": {
|
|
57
|
-
"@deepseek-ai/cordis": {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
"@deepseek-ai/dsh-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
"@deepseek-ai/dsh-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
"@deepseek-ai/dsh-client-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
"@deepseek-ai/dsh-
|
|
70
|
-
|
|
71
|
-
|
|
71
|
+
"@deepseek-ai/cordis": {
|
|
72
|
+
"optional": true
|
|
73
|
+
},
|
|
74
|
+
"@deepseek-ai/dsh-api-remotes": {
|
|
75
|
+
"optional": true
|
|
76
|
+
},
|
|
77
|
+
"@deepseek-ai/dsh-api-session-controller": {
|
|
78
|
+
"optional": true
|
|
79
|
+
},
|
|
80
|
+
"@deepseek-ai/dsh-client-locale": {
|
|
81
|
+
"optional": true
|
|
82
|
+
},
|
|
83
|
+
"@deepseek-ai/dsh-client-ui-renderer": {
|
|
84
|
+
"optional": true
|
|
85
|
+
},
|
|
86
|
+
"@deepseek-ai/dsh-client-ui-slots": {
|
|
87
|
+
"optional": true
|
|
88
|
+
},
|
|
89
|
+
"@deepseek-ai/dsh-client-ui-layout": {
|
|
90
|
+
"optional": true
|
|
91
|
+
},
|
|
92
|
+
"@deepseek-ai/dsh-client-ui-sidebar": {
|
|
93
|
+
"optional": true
|
|
94
|
+
},
|
|
95
|
+
"@deepseek-ai/dsh-client-ui-sidebar-right": {
|
|
96
|
+
"optional": true
|
|
97
|
+
},
|
|
98
|
+
"@deepseek-ai/dsh-client-ui-workspace": {
|
|
99
|
+
"optional": true
|
|
100
|
+
},
|
|
101
|
+
"@deepseek-ai/dsh-sandbox-policy": {
|
|
102
|
+
"optional": true
|
|
103
|
+
},
|
|
104
|
+
"@deepseek-ai/dsh-session": {
|
|
105
|
+
"optional": true
|
|
106
|
+
},
|
|
107
|
+
"@deepseek-ai/dsh-util-workspace-path": {
|
|
108
|
+
"optional": true
|
|
109
|
+
},
|
|
110
|
+
"@deepseek-ai/dsh-typert-protocol": {
|
|
111
|
+
"optional": true
|
|
112
|
+
},
|
|
113
|
+
"react": {
|
|
114
|
+
"optional": true
|
|
115
|
+
}
|
|
72
116
|
},
|
|
73
117
|
"devDependencies": {
|
|
74
118
|
"@deepseek-ai/cordis": "^4.0.4",
|