dsh-mac-computer-use 0.0.0-stage → 1.3.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/client.js +340 -0
- package/cordis.patch.yml +4 -0
- package/icon.svg +7 -0
- package/index.js +679 -0
- package/locale/en.json +6 -0
- package/locale/zh.json +6 -0
- package/package.json +43 -4
- package/panel.js +140 -0
- package/setup.js +110 -0
- package/README.md +0 -3
package/client.js
ADDED
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dsh-mac-computer-use 的网页端:DSH「插件」页里我们这张卡的设置页。
|
|
3
|
+
*
|
|
4
|
+
* 状态:能不能用、看得到几个窗口
|
|
5
|
+
* 清单:命令行工具、屏幕录制权限、辅助功能权限、光标浮层 —— 缺哪个就给哪个的按钮
|
|
6
|
+
* 开关:屏幕上显示操作光标
|
|
7
|
+
*
|
|
8
|
+
* 数据全走插件自己挂在 DSH webServer 上的路由(plugin/panel.js),每 2.5 秒刷一次。
|
|
9
|
+
* 走官方客户端插件机制:window.__ModuleLoader__.load({ id, factory }),factory 里 apply(ctx)
|
|
10
|
+
* → 注册到 plugins.bundle.config(包详情页)和 plugins.row.config(行详情页)两个 keyed slot。
|
|
11
|
+
* 拿不到 react 或 DSH 的组件就安静退出 / 用最朴素的替身,别把宿主页面搞崩。
|
|
12
|
+
*/
|
|
13
|
+
window.__ModuleLoader__.load({
|
|
14
|
+
id: 'dsh-mac-computer-use',
|
|
15
|
+
factory: (require) => {
|
|
16
|
+
var module = { exports: {} }
|
|
17
|
+
var exports = module.exports
|
|
18
|
+
|
|
19
|
+
const opt = (id) => { try { return require(id) } catch (_) { return null } }
|
|
20
|
+
const React = opt('react')
|
|
21
|
+
if (!React) {
|
|
22
|
+
exports.apply = () => {}
|
|
23
|
+
exports.inject = ['slots', 'locale']
|
|
24
|
+
return module.exports
|
|
25
|
+
}
|
|
26
|
+
const UI = opt('@deepseek-ai/dsh-client-ui-primitives') || {}
|
|
27
|
+
const h = React.createElement
|
|
28
|
+
const { useState, useEffect, useCallback, useRef } = React
|
|
29
|
+
|
|
30
|
+
const PKG = 'dsh-mac-computer-use'
|
|
31
|
+
const ROW = 'mac-computer-use'
|
|
32
|
+
const NS = 'dsh-mac-computer-use'
|
|
33
|
+
const ROUTE = '/dsh-mac-computer-use/panel'
|
|
34
|
+
const REPO = 'https://github.com/OrderG-X/dsh-mac-computer-use'
|
|
35
|
+
|
|
36
|
+
// 占位符用 %x:不跟 DSH 自己的 {name} 插值撞
|
|
37
|
+
const zh = {
|
|
38
|
+
checking: '正在检查…',
|
|
39
|
+
ready: '可以用了',
|
|
40
|
+
needsPerm: '还差系统权限',
|
|
41
|
+
notInstalled: '还没装好',
|
|
42
|
+
unsupported: '只支持 macOS',
|
|
43
|
+
windows: '能看到 %n 个窗口',
|
|
44
|
+
windowsUnknown: '命令行工具跑不起来,看不到窗口',
|
|
45
|
+
summaryOn: '可以用了 · 能看到 %n 个窗口',
|
|
46
|
+
summaryPerm: '缺少系统权限,点开看怎么开',
|
|
47
|
+
summaryOff: '还没装命令行工具,点开看怎么装',
|
|
48
|
+
binTitle: '命令行工具 dsh-cu',
|
|
49
|
+
binOk: '已装好',
|
|
50
|
+
binMissing: '还没装。在「终端」里运行下面这条(要先装 Xcode 命令行工具:xcode-select --install):',
|
|
51
|
+
srcInstalled: '~/.dsh/bin',
|
|
52
|
+
srcDev: '开发目录',
|
|
53
|
+
srcEnv: 'DSH_CU_BIN',
|
|
54
|
+
copyInstall: '复制安装命令',
|
|
55
|
+
copied: '安装命令已复制,到「终端」里粘贴回车,装完回来这里会自动更新',
|
|
56
|
+
binOld: '可以更新',
|
|
57
|
+
binOutdated: '新版引擎截图更准:窗口被别的窗口挡住时,给元素编号、按文字找也能看到窗口本身。在「终端」里运行下面这条更新(现在的也能用):',
|
|
58
|
+
copyUpdate: '复制更新命令',
|
|
59
|
+
updateCopied: '更新命令已复制,到「终端」里粘贴回车,装完回来这里会自动更新',
|
|
60
|
+
screenTitle: '屏幕录制权限',
|
|
61
|
+
screenHint: '截图、按文字找按钮都要用。',
|
|
62
|
+
axTitle: '辅助功能权限',
|
|
63
|
+
axHint: '点击、输入、按键、滚动、拖拽和按编号点都要用;没开的话这些操作会直接报错(系统会把它们丢掉)。',
|
|
64
|
+
permOk: '已开',
|
|
65
|
+
permMissing: '没开',
|
|
66
|
+
permUnknown: '查不出来',
|
|
67
|
+
openSettings: '打开系统设置',
|
|
68
|
+
settingsOpened: '已打开系统设置:在列表里打开 DeepSeek Harness 的开关。屏幕录制改完要重启 DSH 才生效。',
|
|
69
|
+
overlayTitle: '光标浮层',
|
|
70
|
+
overlayRunning: '正在显示',
|
|
71
|
+
overlayIdle: '已装,操作时自动出现',
|
|
72
|
+
overlayMissing: '没装:看不到光标,不影响操作(装命令行工具时会一起装)',
|
|
73
|
+
showCursor: '屏幕上显示操作光标',
|
|
74
|
+
showCursorHint: '关掉只是不画光标,点击、输入照做。',
|
|
75
|
+
plugin: '插件 v%v',
|
|
76
|
+
guide: '使用说明',
|
|
77
|
+
failed: '操作没成功:%e',
|
|
78
|
+
unreachable: '读不到插件状态,重启 DSH 后再试',
|
|
79
|
+
}
|
|
80
|
+
const en = {
|
|
81
|
+
checking: 'Checking…',
|
|
82
|
+
ready: 'Ready',
|
|
83
|
+
needsPerm: 'Missing system permissions',
|
|
84
|
+
notInstalled: 'Not installed yet',
|
|
85
|
+
unsupported: 'macOS only',
|
|
86
|
+
windows: 'Can see %n window(s)',
|
|
87
|
+
windowsUnknown: 'The command-line tool did not run, so no windows are visible',
|
|
88
|
+
summaryOn: 'Ready · can see %n window(s)',
|
|
89
|
+
summaryPerm: 'Missing system permissions — open for steps',
|
|
90
|
+
summaryOff: 'Command-line tool not installed — open for steps',
|
|
91
|
+
binTitle: 'Command-line tool dsh-cu',
|
|
92
|
+
binOk: 'Installed',
|
|
93
|
+
binMissing: 'Not installed. Run this in Terminal (needs Xcode Command Line Tools first: xcode-select --install):',
|
|
94
|
+
srcInstalled: '~/.dsh/bin',
|
|
95
|
+
srcDev: 'dev folder',
|
|
96
|
+
srcEnv: 'DSH_CU_BIN',
|
|
97
|
+
copyInstall: 'Copy install command',
|
|
98
|
+
copied: 'Install command copied. Paste it in Terminal; this page updates by itself once it is done',
|
|
99
|
+
binOld: 'Update available',
|
|
100
|
+
binOutdated: 'The newer engine captures windows more accurately: numbering elements and finding text also see the window itself when another window covers it. Run this in Terminal to update (the current one still works):',
|
|
101
|
+
copyUpdate: 'Copy update command',
|
|
102
|
+
updateCopied: 'Update command copied. Paste it in Terminal; this page updates by itself once it is done',
|
|
103
|
+
screenTitle: 'Screen Recording permission',
|
|
104
|
+
screenHint: 'Needed for screenshots and finding buttons by their text.',
|
|
105
|
+
axTitle: 'Accessibility permission',
|
|
106
|
+
axHint: 'Needed for clicking, typing, keys, scrolling, dragging and clicking by number; without it these fail with an error (macOS drops them).',
|
|
107
|
+
permOk: 'On',
|
|
108
|
+
permMissing: 'Off',
|
|
109
|
+
permUnknown: 'Unknown',
|
|
110
|
+
openSettings: 'Open System Settings',
|
|
111
|
+
settingsOpened: 'Opened System Settings: turn on DeepSeek Harness in the list. Screen Recording changes need a DSH restart.',
|
|
112
|
+
overlayTitle: 'Cursor overlay',
|
|
113
|
+
overlayRunning: 'Showing',
|
|
114
|
+
overlayIdle: 'Installed, appears while working',
|
|
115
|
+
overlayMissing: 'Not installed: no visible cursor, actions still work (installed together with the command-line tool)',
|
|
116
|
+
showCursor: 'Show the action cursor on screen',
|
|
117
|
+
showCursorHint: 'Off only hides the cursor; clicks and typing still happen.',
|
|
118
|
+
plugin: 'Plugin v%v',
|
|
119
|
+
guide: 'Guide',
|
|
120
|
+
failed: 'That did not work: %e',
|
|
121
|
+
unreachable: 'Could not read the plugin status; restart DSH and try again',
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const fmt = (s, vars) => String(s).replace(/%([a-z])/g, (m, k) => (vars && k in vars ? String(vars[k]) : m))
|
|
125
|
+
|
|
126
|
+
const CSS = `
|
|
127
|
+
.dcu{display:grid;gap:12px;color:var(--dsw-alias-label-primary);font-size:13px;line-height:1.5}
|
|
128
|
+
.dcu-card{border:1px solid var(--dsw-alias-settings-card-stroke,var(--dsw-alias-border-l));background:var(--dsw-alias-settings-card-fill,transparent);border-radius:12px;overflow:hidden}
|
|
129
|
+
.dcu-row{display:flex;align-items:flex-start;gap:12px;padding:12px 14px}
|
|
130
|
+
.dcu-row+.dcu-row{border-top:1px solid var(--dsw-alias-border-l)}
|
|
131
|
+
.dcu-main{flex:1;min-width:0;display:grid;gap:2px}
|
|
132
|
+
.dcu-title{font-weight:600;display:flex;align-items:center;gap:8px;flex-wrap:wrap}
|
|
133
|
+
.dcu-sub{color:var(--dsw-alias-label-secondary);font-size:12px}
|
|
134
|
+
.dcu-hint{color:var(--dsw-alias-label-tertiary);font-size:12px;margin:0}
|
|
135
|
+
.dcu-dot{width:9px;height:9px;border-radius:50%;flex:none;margin-top:6px;background:var(--dsw-alias-label-tertiary)}
|
|
136
|
+
.dcu-dot[data-s=on]{background:var(--dsw-alias-state-success-primary,#34c759);box-shadow:0 0 0 3px color-mix(in srgb,var(--dsw-alias-state-success-primary,#34c759) 22%,transparent)}
|
|
137
|
+
.dcu-dot[data-s=warn]{background:var(--dsw-alias-state-warn-primary,#ff9f0a)}
|
|
138
|
+
.dcu-dot[data-s=off]{background:var(--dsw-alias-state-error-primary,#ff453a)}
|
|
139
|
+
.dcu-dot[data-s=idle]{background:var(--dsw-alias-label-tertiary)}
|
|
140
|
+
.dcu-cmd{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;padding:4px 8px;margin-top:4px;border-radius:6px;background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary);user-select:all;word-break:break-all}
|
|
141
|
+
.dcu-note{font-size:12px;padding:8px 12px;border-radius:10px;background:color-mix(in srgb,var(--dsw-alias-state-warn-primary,#ff9f0a) 12%,transparent);color:var(--dsw-alias-label-primary)}
|
|
142
|
+
.dcu-note[data-tone=ok]{background:color-mix(in srgb,var(--dsw-alias-state-success-primary,#34c759) 12%,transparent)}
|
|
143
|
+
.dcu-note[data-tone=err]{background:color-mix(in srgb,var(--dsw-alias-state-error-primary,#ff453a) 12%,transparent)}
|
|
144
|
+
.dcu-foot{display:flex;gap:10px;align-items:center;color:var(--dsw-alias-label-tertiary);font-size:12px}
|
|
145
|
+
.dcu-foot a{color:var(--dsw-alias-link);text-decoration:none}
|
|
146
|
+
.dcu-foot a:hover{text-decoration:underline}
|
|
147
|
+
.dcu-tag{font-size:11px;font-weight:500;padding:0 6px;border-radius:6px;border:1px solid var(--dsw-alias-border-l);color:var(--dsw-alias-label-secondary)}
|
|
148
|
+
.dcu-btn{font:inherit;font-size:12px;padding:4px 12px;border-radius:8px;border:1px solid var(--dsw-alias-border-l);background:transparent;color:var(--dsw-alias-label-primary);cursor:pointer;white-space:nowrap}
|
|
149
|
+
.dcu-btn:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}
|
|
150
|
+
.dcu-btn:disabled{opacity:.45;cursor:default}
|
|
151
|
+
.dcu-switch{flex:none;margin-top:2px}`
|
|
152
|
+
function ensureCss() {
|
|
153
|
+
if (typeof document === 'undefined' || document.querySelector('style[data-plugin-css="dsh-mac-computer-use"]')) return
|
|
154
|
+
const tag = document.createElement('style')
|
|
155
|
+
tag.dataset.plugin = PKG
|
|
156
|
+
tag.dataset.pluginCss = 'dsh-mac-computer-use'
|
|
157
|
+
tag.textContent = CSS
|
|
158
|
+
document.head.appendChild(tag)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// ── DSH 组件,拿不到就用朴素替身 ────────────────────────────────────────
|
|
162
|
+
function Toggle({ checked, disabled, label, onChange }) {
|
|
163
|
+
if (UI.Switch) return h('span', { className: 'dcu-switch' }, h(UI.Switch, { checked, disabled, label, onChange }))
|
|
164
|
+
return h('input', { className: 'dcu-switch', type: 'checkbox', role: 'switch', 'aria-label': label, checked, disabled, onChange: (e) => onChange(e.target.checked) })
|
|
165
|
+
}
|
|
166
|
+
function Btn({ onClick, disabled, children, primary }) {
|
|
167
|
+
if (UI.Button) return h(UI.Button, { variant: primary ? 'primary' : 'outline', size: 'sm', disabled, onClick }, children)
|
|
168
|
+
return h('button', { type: 'button', className: 'dcu-btn', disabled, onClick }, children)
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// ── 数据 ──────────────────────────────────────────────────────────────
|
|
172
|
+
async function fetchState(action) {
|
|
173
|
+
const res = await fetch(ROUTE, action
|
|
174
|
+
? { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(action), credentials: 'same-origin' }
|
|
175
|
+
: { credentials: 'same-origin', cache: 'no-store' })
|
|
176
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`)
|
|
177
|
+
return res.json()
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/** 2.5 秒刷一次;页面藏起来时不刷。 */
|
|
181
|
+
function useDesktopState() {
|
|
182
|
+
const [state, setState] = useState(null)
|
|
183
|
+
const [error, setError] = useState('')
|
|
184
|
+
const alive = useRef(true)
|
|
185
|
+
const load = useCallback(async () => {
|
|
186
|
+
try {
|
|
187
|
+
const s = await fetchState()
|
|
188
|
+
if (alive.current) { setState(s); setError('') }
|
|
189
|
+
} catch (e) {
|
|
190
|
+
if (alive.current) setError(String((e && e.message) || e))
|
|
191
|
+
}
|
|
192
|
+
}, [])
|
|
193
|
+
useEffect(() => {
|
|
194
|
+
alive.current = true
|
|
195
|
+
load()
|
|
196
|
+
const timer = setInterval(() => {
|
|
197
|
+
if (typeof document === 'undefined' || document.visibilityState !== 'hidden') load()
|
|
198
|
+
}, 2500)
|
|
199
|
+
return () => { alive.current = false; clearInterval(timer) }
|
|
200
|
+
}, [load])
|
|
201
|
+
const act = useCallback(async (action) => {
|
|
202
|
+
const s = await fetchState(action)
|
|
203
|
+
if (alive.current) setState(s)
|
|
204
|
+
return s
|
|
205
|
+
}, [])
|
|
206
|
+
return { state, error, act }
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function phaseOf(s) {
|
|
210
|
+
if (!s) return 'checking'
|
|
211
|
+
if (s.platform && s.platform !== 'darwin') return 'unsupported'
|
|
212
|
+
if (!s.bin) return 'off'
|
|
213
|
+
const p = s.perms || {}
|
|
214
|
+
if (p.screen === false || p.ax === false || s.windows == null) return 'warn'
|
|
215
|
+
return 'on'
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// ── 概要(行卡片上的一句话)────────────────────────────────────────────
|
|
219
|
+
function Summary({ t }) {
|
|
220
|
+
const { state } = useDesktopState()
|
|
221
|
+
const p = phaseOf(state)
|
|
222
|
+
if (p === 'checking') return t('checking')
|
|
223
|
+
if (p === 'unsupported') return t('unsupported')
|
|
224
|
+
if (p === 'off') return t('summaryOff')
|
|
225
|
+
if (p === 'warn') return t('summaryPerm')
|
|
226
|
+
return fmt(t('summaryOn'), { n: state.windows })
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// ── 设置页 ────────────────────────────────────────────────────────────
|
|
230
|
+
function Page({ t }) {
|
|
231
|
+
const { state, error, act } = useDesktopState()
|
|
232
|
+
const [busy, setBusy] = useState(false)
|
|
233
|
+
const [note, setNote] = useState(null)
|
|
234
|
+
const p = phaseOf(state)
|
|
235
|
+
|
|
236
|
+
const run = async (action, ok) => {
|
|
237
|
+
setBusy(true)
|
|
238
|
+
try {
|
|
239
|
+
const s = await act(action)
|
|
240
|
+
if (s.actionError) setNote({ tone: 'err', text: fmt(t('failed'), { e: s.actionError }) })
|
|
241
|
+
else setNote(ok ? { tone: 'ok', text: ok } : null)
|
|
242
|
+
} catch (e) {
|
|
243
|
+
setNote({ tone: 'err', text: fmt(t('failed'), { e: String((e && e.message) || e) }) })
|
|
244
|
+
} finally {
|
|
245
|
+
setBusy(false)
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const statusTitle = { checking: t('checking'), on: t('ready'), warn: t('needsPerm'), off: t('notInstalled'), unsupported: t('unsupported') }[p]
|
|
250
|
+
const status = h('div', { className: 'dcu-card' },
|
|
251
|
+
h('div', { className: 'dcu-row' },
|
|
252
|
+
h('span', { className: 'dcu-dot', 'data-s': p === 'unsupported' ? 'off' : p === 'checking' ? 'idle' : p }),
|
|
253
|
+
h('div', { className: 'dcu-main' },
|
|
254
|
+
h('div', { className: 'dcu-title' }, statusTitle),
|
|
255
|
+
state && state.bin
|
|
256
|
+
? h('div', { className: 'dcu-sub' }, state.windows == null ? t('windowsUnknown') : fmt(t('windows'), { n: state.windows }))
|
|
257
|
+
: null)))
|
|
258
|
+
|
|
259
|
+
// 一行清单:状态点 + 标题 + 说明 + 右侧按钮
|
|
260
|
+
const item = (key, dot, title, sub, extra, button) => h('div', { key, className: 'dcu-row' },
|
|
261
|
+
h('span', { className: 'dcu-dot', 'data-s': dot }),
|
|
262
|
+
h('div', { className: 'dcu-main' },
|
|
263
|
+
h('div', { className: 'dcu-title' }, title, sub ? h('span', { className: 'dcu-tag' }, sub) : null),
|
|
264
|
+
extra),
|
|
265
|
+
button)
|
|
266
|
+
|
|
267
|
+
const permItem = (key, value, title, hint) => item(key,
|
|
268
|
+
value === true ? 'on' : value === false ? 'off' : 'idle',
|
|
269
|
+
title,
|
|
270
|
+
value === true ? t('permOk') : value === false ? t('permMissing') : t('permUnknown'),
|
|
271
|
+
h('p', { className: 'dcu-hint' }, hint),
|
|
272
|
+
value === false ? h(Btn, { disabled: busy, onClick: () => run({ action: 'openSettings', pane: key }, t('settingsOpened')) }, t('openSettings')) : null)
|
|
273
|
+
|
|
274
|
+
const checklist = state && state.platform === 'darwin' ? h('div', { className: 'dcu-card' },
|
|
275
|
+
state.bin && state.bin.outdated
|
|
276
|
+
? item('bin', 'warn', t('binTitle'), t('binOld'),
|
|
277
|
+
h('div', null, h('p', { className: 'dcu-hint' }, t('binOutdated')), h('div', { className: 'dcu-cmd' }, state.updateCmd)),
|
|
278
|
+
h(Btn, { disabled: busy, onClick: () => run({ action: 'copyUpdate' }, t('updateCopied')) }, t('copyUpdate')))
|
|
279
|
+
: state.bin
|
|
280
|
+
? item('bin', 'on', t('binTitle'), t('binOk') + ' · ' + t({ installed: 'srcInstalled', dev: 'srcDev', env: 'srcEnv' }[state.bin.source] || 'srcInstalled'))
|
|
281
|
+
: item('bin', 'off', t('binTitle'), null,
|
|
282
|
+
h('div', null, h('p', { className: 'dcu-hint' }, t('binMissing')), h('div', { className: 'dcu-cmd' }, state.installCmd)),
|
|
283
|
+
h(Btn, { primary: true, disabled: busy, onClick: () => run({ action: 'copyInstall' }, t('copied')) }, t('copyInstall'))),
|
|
284
|
+
permItem('screen', state.perms && state.perms.screen, t('screenTitle'), t('screenHint')),
|
|
285
|
+
permItem('ax', state.perms && state.perms.ax, t('axTitle'), t('axHint')),
|
|
286
|
+
item('overlay',
|
|
287
|
+
state.overlay && state.overlay.running ? 'on' : state.overlay && state.overlay.installed ? 'idle' : 'warn',
|
|
288
|
+
t('overlayTitle'), null,
|
|
289
|
+
h('p', { className: 'dcu-hint' }, state.overlay && state.overlay.running ? t('overlayRunning') : state.overlay && state.overlay.installed ? t('overlayIdle') : t('overlayMissing')),
|
|
290
|
+
null)) : null
|
|
291
|
+
|
|
292
|
+
const switches = state && state.platform === 'darwin' ? h('div', { className: 'dcu-card' },
|
|
293
|
+
h('div', { className: 'dcu-row' },
|
|
294
|
+
h('div', { className: 'dcu-main' },
|
|
295
|
+
h('div', { className: 'dcu-title' }, t('showCursor')),
|
|
296
|
+
h('p', { className: 'dcu-hint' }, t('showCursorHint'))),
|
|
297
|
+
h(Toggle, { label: t('showCursor'), checked: state.showCursor !== false, disabled: busy, onChange: (on) => run({ action: 'cursor', on }) }))) : null
|
|
298
|
+
|
|
299
|
+
const notes = [
|
|
300
|
+
error && !state ? { tone: 'err', text: t('unreachable') } : null,
|
|
301
|
+
note,
|
|
302
|
+
].filter(Boolean)
|
|
303
|
+
|
|
304
|
+
return h('div', { className: 'dcu' },
|
|
305
|
+
status,
|
|
306
|
+
checklist,
|
|
307
|
+
switches,
|
|
308
|
+
...notes.map((n, i) => h('div', { key: `n${i}`, className: 'dcu-note', 'data-tone': n.tone }, n.text)),
|
|
309
|
+
h('div', { className: 'dcu-foot' },
|
|
310
|
+
state && state.plugin ? h('span', null, fmt(t('plugin'), { v: state.plugin })) : null,
|
|
311
|
+
h('a', { href: REPO, target: '_blank', rel: 'noopener noreferrer' }, t('guide'))))
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
function makeCard(boundT) {
|
|
315
|
+
return function DesktopControlCard(props) {
|
|
316
|
+
ensureCss()
|
|
317
|
+
const t = typeof props.t === 'function' ? props.t : boundT
|
|
318
|
+
return props.view === 'summary' ? h(Summary, { t }) : h(Page, { t })
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
function apply(ctx) {
|
|
323
|
+
const t = ctx.locale && typeof ctx.locale.bind === 'function' ? ctx.locale.bind(NS) : (k) => zh[k] || k
|
|
324
|
+
if (ctx.locale && typeof ctx.locale.register === 'function') {
|
|
325
|
+
ctx.effect(() => ctx.locale.register(NS, { zh, en }), 'dsh-mac-computer-use: dictionaries')
|
|
326
|
+
}
|
|
327
|
+
const Card = makeCard(t)
|
|
328
|
+
const mount = (name, key) => {
|
|
329
|
+
const reg = () => ctx.slots.register({ name, key, locale: NS }, Card)
|
|
330
|
+
ctx.effect(() => (typeof ctx.slots.inject === 'function' ? ctx.slots.inject(name, reg) : reg()), `dsh-mac-computer-use: ${name}`)
|
|
331
|
+
}
|
|
332
|
+
mount('plugins.bundle.config', PKG)
|
|
333
|
+
mount('plugins.row.config', `${PKG}#${ROW}`)
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
exports.apply = apply
|
|
337
|
+
exports.inject = ['slots', 'locale']
|
|
338
|
+
return module.exports
|
|
339
|
+
},
|
|
340
|
+
})
|
package/cordis.patch.yml
ADDED
package/icon.svg
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128" width="128" height="128">
|
|
2
|
+
<rect width="128" height="128" rx="28" fill="#4D6BFE"/>
|
|
3
|
+
<rect x="20" y="24" width="88" height="62" rx="9" fill="none" stroke="#FFFFFF" stroke-width="7"/>
|
|
4
|
+
<path d="M64 86 V100 M50 102 H78" stroke="#FFFFFF" stroke-width="7" stroke-linecap="round"/>
|
|
5
|
+
<path d="M56 38 L56 72 L64.5 63.5 L71 78 L78 75 L71.5 60.5 L83 60 Z"
|
|
6
|
+
fill="#FFFFFF" stroke="#FFFFFF" stroke-width="3" stroke-linejoin="round"/>
|
|
7
|
+
</svg>
|