dsh-desktop-windows 0.1.7 → 0.1.8
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/package.json +1 -1
- package/src/main.js +34 -1
- package/src/preload.js +54 -24
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-desktop-windows",
|
|
3
3
|
"productName": "DeepSeek Harness Desktop",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.8",
|
|
5
5
|
"description": "DeepSeek Harness 桌面版(Windows)· Electron desktop shell for DeepSeek Harness (dsh web) — 双击即用,无需终端 / double-click to run the harness in a standalone window",
|
|
6
6
|
"main": "src/main.js",
|
|
7
7
|
"license": "MIT",
|
package/src/main.js
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* 不修改 dsh 任何代码;服务端用全局安装的 dsh(可用 DSH_BIN 环境变量覆盖路径)。
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
-
const { app, BrowserWindow, dialog, shell, Tray, Menu, nativeImage, ipcMain } = require('electron')
|
|
16
|
+
const { app, BrowserWindow, dialog, shell, Tray, Menu, nativeImage, ipcMain, desktopCapturer, clipboard, screen } = require('electron')
|
|
17
17
|
const { spawn, execFile } = require('node:child_process')
|
|
18
18
|
const http = require('node:http')
|
|
19
19
|
const fs = require('node:fs')
|
|
@@ -552,6 +552,39 @@ if (!gotLock) {
|
|
|
552
552
|
ipcMain.on('dsh-desktop:reload', () => {
|
|
553
553
|
if (mainWindow) mainWindow.webContents.reload()
|
|
554
554
|
})
|
|
555
|
+
// 截图:截当前屏幕 → 写剪贴板 → 聚焦聊天输入框并粘贴
|
|
556
|
+
ipcMain.handle('dsh-desktop:capture', async () => {
|
|
557
|
+
try {
|
|
558
|
+
const display = screen.getPrimaryDisplay()
|
|
559
|
+
const size = display.size
|
|
560
|
+
const sources = await desktopCapturer.getSources({
|
|
561
|
+
types: ['screen'],
|
|
562
|
+
thumbnailSize: { width: size.width, height: size.height },
|
|
563
|
+
})
|
|
564
|
+
if (!sources.length) return { ok: false, error: '未找到屏幕源' }
|
|
565
|
+
const image = sources[0].thumbnail
|
|
566
|
+
if (image.isEmpty()) return { ok: false, error: '截图为空' }
|
|
567
|
+
clipboard.writeImage(image)
|
|
568
|
+
// 聚焦聊天输入框并触发粘贴
|
|
569
|
+
if (mainWindow && !mainWindow.isDestroyed()) {
|
|
570
|
+
const focused = await mainWindow.webContents
|
|
571
|
+
.executeJavaScript(
|
|
572
|
+
`(() => { const el = document.querySelector('textarea, [contenteditable="true"]'); if (el) { el.focus(); return true } return false })()`
|
|
573
|
+
)
|
|
574
|
+
.catch(() => false)
|
|
575
|
+
if (focused) mainWindow.webContents.paste()
|
|
576
|
+
}
|
|
577
|
+
return { ok: true }
|
|
578
|
+
} catch (e) {
|
|
579
|
+
return { ok: false, error: String((e && e.message) || e) }
|
|
580
|
+
}
|
|
581
|
+
})
|
|
582
|
+
// 轻提示(截图失败等)
|
|
583
|
+
ipcMain.on('dsh-desktop:toast', (_e, msg) => {
|
|
584
|
+
if (mainWindow && !mainWindow.isDestroyed()) {
|
|
585
|
+
dialog.showMessageBox(mainWindow, { type: 'info', message: String(msg), buttons: ['好'] })
|
|
586
|
+
}
|
|
587
|
+
})
|
|
555
588
|
if (external) log('reusing external dsh service on port ' + port)
|
|
556
589
|
})
|
|
557
590
|
|
package/src/preload.js
CHANGED
|
@@ -1,38 +1,68 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
//
|
|
3
|
+
// preload:注入底部工具条(截图 + 刷新)。
|
|
4
4
|
// 页面(dsh Web UI)直接走 HTTP/WebSocket 与本地服务通信,无需 IPC。
|
|
5
5
|
|
|
6
6
|
const { ipcRenderer } = require('electron')
|
|
7
7
|
|
|
8
|
-
// 注入一个悬浮"刷新"按钮(右下角,半透明,鼠标悬停变清晰)
|
|
9
8
|
window.addEventListener('DOMContentLoaded', () => {
|
|
10
9
|
setTimeout(() => {
|
|
11
10
|
if (!document.body) return
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
|
|
12
|
+
// 底部工具条容器
|
|
13
|
+
const bar = document.createElement('div')
|
|
14
|
+
bar.style.cssText = `
|
|
16
15
|
position: fixed;
|
|
17
|
-
right:
|
|
18
|
-
bottom:
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
border-radius: 10px;
|
|
22
|
-
border: none;
|
|
23
|
-
background: rgba(30, 41, 59, 0.72);
|
|
24
|
-
color: #fff;
|
|
25
|
-
font-size: 18px;
|
|
26
|
-
line-height: 1;
|
|
27
|
-
cursor: pointer;
|
|
28
|
-
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.35);
|
|
29
|
-
opacity: 0.45;
|
|
30
|
-
transition: opacity 0.2s;
|
|
16
|
+
right: 12px;
|
|
17
|
+
bottom: 12px;
|
|
18
|
+
display: flex;
|
|
19
|
+
gap: 8px;
|
|
31
20
|
z-index: 2147483647;
|
|
32
21
|
`
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
22
|
+
|
|
23
|
+
const makeBtn = (text, title, onClick) => {
|
|
24
|
+
const b = document.createElement('button')
|
|
25
|
+
b.textContent = text
|
|
26
|
+
b.title = title
|
|
27
|
+
b.style.cssText = `
|
|
28
|
+
width: 34px;
|
|
29
|
+
height: 34px;
|
|
30
|
+
border-radius: 10px;
|
|
31
|
+
border: none;
|
|
32
|
+
background: rgba(30, 41, 59, 0.72);
|
|
33
|
+
color: #fff;
|
|
34
|
+
font-size: 17px;
|
|
35
|
+
line-height: 1;
|
|
36
|
+
cursor: pointer;
|
|
37
|
+
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.35);
|
|
38
|
+
opacity: 0.45;
|
|
39
|
+
transition: opacity 0.2s;
|
|
40
|
+
`
|
|
41
|
+
b.onmouseenter = () => (b.style.opacity = '1')
|
|
42
|
+
b.onmouseleave = () => (b.style.opacity = '0.45')
|
|
43
|
+
b.onclick = onClick
|
|
44
|
+
return b
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// 截图按钮:截屏 → 剪贴板 → 自动粘贴到聊天框
|
|
48
|
+
const shotBtn = makeBtn('📸', '截图并提问(截取当前屏幕,自动粘贴到聊天框)', () => {
|
|
49
|
+
shotBtn.style.opacity = '1'
|
|
50
|
+
shotBtn.textContent = '⏳'
|
|
51
|
+
ipcRenderer.invoke('dsh-desktop:capture').then((r) => {
|
|
52
|
+
shotBtn.textContent = '📸'
|
|
53
|
+
if (!r || !r.ok) {
|
|
54
|
+
ipcRenderer.send('dsh-desktop:toast', (r && r.error) || '截图失败')
|
|
55
|
+
}
|
|
56
|
+
})
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
// 刷新按钮
|
|
60
|
+
const reloadBtn = makeBtn('⟳', '刷新页面(等价 F5)', () => {
|
|
61
|
+
ipcRenderer.send('dsh-desktop:reload')
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
bar.appendChild(shotBtn)
|
|
65
|
+
bar.appendChild(reloadBtn)
|
|
66
|
+
document.body.appendChild(bar)
|
|
37
67
|
}, 1500)
|
|
38
68
|
})
|