dsh-status-bar-plugin 0.0.0-stage → 0.2.4

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 wfz2006
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.md CHANGED
@@ -1,3 +1,100 @@
1
- # Temporary Holding Version
1
+ # dsh-status-bar
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ DSH bundle for **DSH Status Bar** — a floating glass status bar for DeepSeek Harness.
4
+ The npm name and the bundle row id are `dsh-status-bar-plugin`. npm already hosts an unrelated `dsh-statusbar`, so the registry rejects the shorter name as too similar.
5
+
6
+ ## What it does
7
+
8
+ The plugin mounts one host row in DSH. At boot it waits for the local web server,
9
+ asks the `connection` service for the authenticated host URL
10
+ (`connection.authenticatedUrl(origin)`), and starts the desktop app with that link:
11
+
12
+ ```text
13
+ electron <app dir> --dsh-link=<authenticated url> --launcher-pid=<host pid>
14
+ ```
15
+
16
+ The companion connects with that link on launch, so nothing has to be pasted. The
17
+ link travels only in the process arguments and is never logged — the plugin prints
18
+ `[dsh-status-bar] Glass desktop companion launched (authenticated link redacted)`.
19
+ The app rejects non-loopback links, credentials, hashes and sub-paths before it
20
+ touches the network. `--launcher-pid` makes the companion exit when the DSH
21
+ process it belongs to disappears; disposing the plugin kills the spawned tree.
22
+
23
+ If the companion is already running, the second launch hits its single-instance
24
+ lock: the existing window is focused and re-connected with the new link.
25
+
26
+ ## Install
27
+
28
+ From npm, from the plugin market (once listed), or straight from the release
29
+ tarball:
30
+
31
+ ```sh
32
+ # npm: ~870 kB, fetches the 155 MB runtime once on first launch
33
+ dsh plugin --profile web add dsh-status-bar-plugin
34
+
35
+ # release tarball: 155 MB, self-contained, nothing downloaded later
36
+ dsh plugin --profile web add https://github.com/wfz2006/dsh-status-bar/releases/latest/download/dsh-status-bar.tgz
37
+ ```
38
+
39
+ Both end up as the same companion: the built desktop app plus an Electron
40
+ runtime. The tarball carries them; the npm package reads the download URL from its
41
+ own manifest (`dsh.statusBar.runtime`), fetches that tarball the first time DSH
42
+ starts it — progress goes to the host log, roughly
43
+ `[dsh-status-bar] downloading the Glass runtime: 40% of 155 MB` — and unpacks it
44
+ into a per-version cache: `%LOCALAPPDATA%\dsh-status-bar\runtime-<version>` on
45
+ Windows, `~/.cache/dsh-status-bar/runtime-<version>` elsewhere. Later launches
46
+ reuse that cache, so the download happens once per version.
47
+
48
+ > Renamed in 0.2.3. The old package id was `dsh-glass-plugin`; it still resolves
49
+ > to the same app, but new installs should use `dsh-status-bar-plugin`.
50
+
51
+ ### From a checkout (development)
52
+
53
+ The desktop profile can link the package instead of installing it:
54
+
55
+ ```jsonc
56
+ // <profile>/package.json
57
+ "dependencies": { "dsh-status-bar-plugin": "link:D:/codexwork/dsh/dsh-glass-spec/packages/dsh-status-bar" },
58
+ "dsh": { "profile": { "bundles": [/* ... */ "dsh-status-bar-plugin"] } }
59
+ ```
60
+
61
+ In a checkout the plugin uses `apps/desktop/out` as the app directory and the
62
+ workspace `electron` package, so run `pnpm build` first. Point a junction or
63
+ symlink at `node_modules/dsh-status-bar-plugin` if pnpm did not run, then restart DSH.
64
+
65
+ ## Configuration
66
+
67
+ The bundle patch sets `autoLaunch: true`. To keep the plugin installed but stop it
68
+ from launching the companion, override the row config in the profile patch:
69
+
70
+ ```yaml
71
+ - id: dsh-status-bar-plugin
72
+ config:
73
+ autoLaunch: false
74
+ ```
75
+
76
+ Other overrides, all optional:
77
+
78
+ | key | meaning |
79
+ |:--|:--|
80
+ | `appDir` | directory holding `out/main/index.js` |
81
+ | `electronBinary` | path to an Electron executable |
82
+ | `runtimeDir` | where the downloaded runtime is cached |
83
+ | `downloadUrl` | override the runtime tarball URL |
84
+ | `autoReload` | relaunch the companion when the desktop bundle changes (default `true`) |
85
+
86
+ The same settings are available through the environment:
87
+ `DSH_STATUS_BAR_APP`, `DSH_STATUS_BAR_ELECTRON`, `DSH_STATUS_BAR_RUNTIME`,
88
+ `DSH_STATUS_BAR_RUNTIME_URL`. The pre-0.2.3 names (`DSH_GLASS_*`) still work as
89
+ fallbacks.
90
+
91
+ ## Requirements
92
+
93
+ - Windows 11 x64 (the glass refraction reads the screen behind the window).
94
+ - The desktop app is a separate Electron process; it needs a GPU-backed Electron
95
+ runtime, which the release tarball provides.
96
+
97
+ ## License
98
+
99
+ MIT. The bundled Electron runtime keeps its own license files
100
+ (`electron/dist/LICENSE`, `LICENSES.chromium.html`).
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,12 @@
1
+ # dsh-status-bar-plugin bundle patch
2
+ #
3
+ # This is the `dsh.bundle.patch` layer of the local bundle package. When the
4
+ # package is declared in a profile's dependencies, adding it to
5
+ # `dsh.profile.bundles` mounts the row below at boot. The row resolves
6
+ # `dsh-status-bar-plugin` from the profile's node_modules, where the `link:`
7
+ # dependency points back at this directory.
8
+ - insert:
9
+ - id: dsh-status-bar-plugin
10
+ name: 'dsh-status-bar-plugin'
11
+ config:
12
+ autoLaunch: true
package/lib/index.js ADDED
@@ -0,0 +1,350 @@
1
+ // DSH bundle entry for the Glass companion.
2
+ //
3
+ // The desktop app is its own Electron process. This host plugin starts it once
4
+ // the local web server is up, handing over the authenticated URL through
5
+ // `--dsh-link` so Glass connects without the user pasting anything. When Glass
6
+ // is already running, its single-instance lock focuses the existing window and
7
+ // re-connects it with the new link.
8
+ //
9
+ // Three install shapes have to work:
10
+ //
11
+ // - the release tarball, which ships the built app in `app/` and an Electron
12
+ // runtime in `electron/dist/` (self-contained, nothing to build);
13
+ // - the npm package, which ships only this plugin and fetches the same
14
+ // tarball once into a cache directory on first launch;
15
+ // - a checkout of the repository, where both live outside this package
16
+ // (`apps/desktop/out` and the workspace `electron` dependency).
17
+ //
18
+ // The child also receives `--launcher-pid`; Glass exits when that host process
19
+ // disappears, and disposal kills the spawned tree so the companion follows DSH.
20
+ import { spawn, spawnSync } from 'node:child_process';
21
+ import { createWriteStream, existsSync, mkdirSync, readFileSync, renameSync, rmSync, statSync } from 'node:fs';
22
+ import { get as httpsGet } from 'node:https';
23
+ import { createRequire } from 'node:module';
24
+ import { homedir, tmpdir } from 'node:os';
25
+ import { dirname, join } from 'node:path';
26
+ import { fileURLToPath } from 'node:url';
27
+
28
+ export const name = 'dsh-status-bar-plugin';
29
+ export const inject = ['connection', 'webServer'];
30
+
31
+ /** Package root: `lib/index.js` -> the directory that holds `package.json`. */
32
+ const pluginRoot = fileURLToPath(new URL('../', import.meta.url));
33
+
34
+ /** Where the light npm package writes the runtime it downloads on first run. */
35
+ const DEFAULT_RUNTIME_URL = 'https://github.com/wfz2006/dsh-status-bar/releases/latest/download/dsh-status-bar.tgz';
36
+
37
+ /** The download URL the published manifest advertises, if any. */
38
+ function manifestRuntimeUrl() {
39
+ try {
40
+ const manifest = JSON.parse(readFileSync(join(pluginRoot, 'package.json'), 'utf8'));
41
+ const url = manifest?.dsh?.statusBar?.runtime;
42
+ return typeof url === 'string' && url.length > 0 ? url : undefined;
43
+ } catch {
44
+ return undefined;
45
+ }
46
+ }
47
+
48
+ /** Electron's binary sits at these relative paths inside a `dist/` directory. */
49
+ function electronExecutables() {
50
+ if (process.platform === 'win32') return ['electron.exe'];
51
+ if (process.platform === 'darwin') return [join('Electron.app', 'Contents', 'MacOS', 'Electron')];
52
+ return ['electron'];
53
+ }
54
+
55
+ function firstFile(candidates) {
56
+ for (const candidate of candidates) {
57
+ if (typeof candidate === 'string' && candidate.length > 0 && existsSync(candidate)) return candidate;
58
+ }
59
+ return undefined;
60
+ }
61
+
62
+ function hasApp(candidate) {
63
+ return typeof candidate === 'string' && candidate.length > 0 && existsSync(join(candidate, 'out', 'main', 'index.js'));
64
+ }
65
+
66
+ function distBinary(distDir) {
67
+ return firstFile(electronExecutables().map(name => join(distDir, name)));
68
+ }
69
+
70
+ function packageVersion() {
71
+ try {
72
+ const manifest = JSON.parse(readFileSync(join(pluginRoot, 'package.json'), 'utf8'));
73
+ return typeof manifest.version === 'string' ? manifest.version : '0.0.0';
74
+ } catch {
75
+ return '0.0.0';
76
+ }
77
+ }
78
+
79
+ /**
80
+ * The app directory holds `out/main/index.js`. The packaged copy wins, then an
81
+ * explicit override, then the checkout layout used while developing.
82
+ */
83
+ function resolveAppDir(config) {
84
+ return firstFile([
85
+ config.appDir,
86
+ process.env.DSH_STATUS_BAR_APP,
87
+ process.env.DSH_GLASS_APP,
88
+ join(pluginRoot, 'app'),
89
+ join(pluginRoot, '..', '..', 'apps', 'desktop'),
90
+ ].filter(hasApp));
91
+ }
92
+
93
+ function resolveElectron(config, appDir) {
94
+ const explicit = firstFile([config.electronBinary, process.env.DSH_STATUS_BAR_ELECTRON, process.env.DSH_GLASS_ELECTRON].filter(value => typeof value === 'string'));
95
+ if (explicit) return explicit;
96
+
97
+ // Release tarball: the runtime travels with the package.
98
+ const bundled = distBinary(join(pluginRoot, 'electron', 'dist'));
99
+ if (bundled) return bundled;
100
+
101
+ // Source install: use the `electron` package installed next to the app (the
102
+ // workspace checkout) or next to this package (a registry dependency).
103
+ for (const base of [appDir, pluginRoot]) {
104
+ if (!base) continue;
105
+ try {
106
+ const manifest = createRequire(join(base, 'package.json')).resolve('electron/package.json');
107
+ const binary = distBinary(join(dirname(manifest), 'dist'));
108
+ if (binary) return binary;
109
+ } catch {
110
+ // Not installed this way; try the next base.
111
+ }
112
+ }
113
+ return undefined;
114
+ }
115
+
116
+ /** A layout that already has both halves of the companion. */
117
+ function resolveInstalled(config) {
118
+ const appDir = resolveAppDir(config);
119
+ if (!appDir) return undefined;
120
+ const electron = resolveElectron(config, appDir);
121
+ return electron ? { appDir, electron } : undefined;
122
+ }
123
+
124
+ function runtimeRoot(config) {
125
+ const base = config.runtimeDir
126
+ ?? process.env.DSH_STATUS_BAR_RUNTIME
127
+ ?? process.env.DSH_GLASS_RUNTIME
128
+ ?? (process.platform === 'win32'
129
+ ? join(process.env.LOCALAPPDATA ?? join(homedir(), 'AppData', 'Local'), 'dsh-status-bar')
130
+ : join(process.env.XDG_CACHE_HOME ?? join(homedir(), '.cache'), 'dsh-status-bar'));
131
+ return join(base, `runtime-${packageVersion()}`);
132
+ }
133
+
134
+ function describeError(error) {
135
+ return error instanceof Error ? error.message : String(error);
136
+ }
137
+
138
+ /** Follows redirects; GitHub's release download resolves to a CDN host. */
139
+ function download(url, destination, { redirects = 5 } = {}) {
140
+ return new Promise((resolve, reject) => {
141
+ const request = httpsGet(url, (response) => {
142
+ const status = response.statusCode ?? 0;
143
+ if (status >= 300 && status < 400 && response.headers.location) {
144
+ response.resume();
145
+ if (redirects <= 0) {
146
+ reject(new Error(`too many redirects while downloading ${url}`));
147
+ return;
148
+ }
149
+ const next = new URL(response.headers.location, url).href;
150
+ download(next, destination, { redirects: redirects - 1 }).then(resolve, reject);
151
+ return;
152
+ }
153
+ if (status !== 200) {
154
+ response.resume();
155
+ reject(new Error(`download failed with HTTP ${status}: ${url}`));
156
+ return;
157
+ }
158
+ const total = Number(response.headers['content-length'] ?? 0);
159
+ let received = 0;
160
+ let reported = 0;
161
+ const file = createWriteStream(destination);
162
+ response.on('data', (chunk) => {
163
+ received += chunk.length;
164
+ if (total > 0) {
165
+ const percent = Math.floor((received / total) * 100);
166
+ if (percent >= reported + 10) {
167
+ reported = percent - (percent % 10);
168
+ console.info(`[dsh-status-bar] downloading the Glass runtime: ${reported}% of ${Math.round(total / (1024 * 1024))} MB`);
169
+ }
170
+ }
171
+ });
172
+ response.pipe(file);
173
+ file.on('finish', () => file.close(() => resolve(received)));
174
+ file.on('error', (error) => {
175
+ rmSync(destination, { force: true });
176
+ reject(error);
177
+ });
178
+ });
179
+ request.on('error', (error) => {
180
+ rmSync(destination, { force: true });
181
+ reject(error);
182
+ });
183
+ request.setTimeout(15 * 60 * 1000, () => request.destroy(new Error(`timed out downloading ${url}`)));
184
+ });
185
+ }
186
+
187
+ /** `tar` ships with Windows 10+ (bsdtar), macOS and every mainstream Linux. */
188
+ function extract(tarball, directory) {
189
+ const result = spawnSync('tar', ['-xzf', tarball, '-C', directory], { stdio: 'ignore', windowsHide: true });
190
+ if (result.status !== 0) {
191
+ throw new Error(`could not unpack ${tarball} (tar exited with ${result.status ?? result.signal}); extract it manually to ${directory}`);
192
+ }
193
+ }
194
+
195
+ /**
196
+ * Downloads and unpacks the release tarball into the per-version cache, then
197
+ * returns the same `{ appDir, electron }` shape as a bundled install.
198
+ */
199
+ async function fetchRuntime(config) {
200
+ const url = config.downloadUrl ?? process.env.DSH_STATUS_BAR_RUNTIME_URL ?? process.env.DSH_GLASS_RUNTIME_URL ?? manifestRuntimeUrl() ?? DEFAULT_RUNTIME_URL;
201
+ const root = runtimeRoot(config);
202
+ const cached = { appDir: join(root, 'app'), electron: distBinary(join(root, 'electron', 'dist')) };
203
+ if (hasApp(cached.appDir) && cached.electron) return cached;
204
+
205
+ const staging = `${root}.staging`;
206
+ const tarball = join(tmpdir(), `dsh-status-bar-${process.pid}-${Date.now()}.tgz`);
207
+ rmSync(staging, { recursive: true, force: true });
208
+ mkdirSync(staging, { recursive: true });
209
+ console.info(`[dsh-status-bar] first run: fetching the ~155 MB Glass runtime from ${url}`);
210
+ try {
211
+ const bytes = await download(url, tarball);
212
+ console.info(`[dsh-status-bar] unpacking the Glass runtime (${Math.round(bytes / (1024 * 1024))} MB)`);
213
+ extract(tarball, staging);
214
+ const unpacked = join(staging, 'package');
215
+ if (!hasApp(join(unpacked, 'app')) || !distBinary(join(unpacked, 'electron', 'dist'))) {
216
+ throw new Error('the downloaded archive does not contain app/ and electron/dist/');
217
+ }
218
+ rmSync(root, { recursive: true, force: true });
219
+ mkdirSync(root, { recursive: true });
220
+ renameSync(join(unpacked, 'app'), join(root, 'app'));
221
+ renameSync(join(unpacked, 'electron'), join(root, 'electron'));
222
+ } finally {
223
+ rmSync(tarball, { force: true });
224
+ rmSync(staging, { recursive: true, force: true });
225
+ }
226
+
227
+ const electron = distBinary(join(root, 'electron', 'dist'));
228
+ if (!electron) throw new Error(`the runtime in ${root} has no Electron executable`);
229
+ return { appDir: join(root, 'app'), electron };
230
+ }
231
+
232
+ function killChild(child) {
233
+ if (!child || child.exitCode !== null || child.pid === undefined) return;
234
+ try { child.kill(); } catch { /* already gone */ }
235
+ if (process.platform === 'win32') spawn('taskkill', ['/pid', String(child.pid), '/t', '/f'], { stdio: 'ignore', windowsHide: true });
236
+ }
237
+
238
+ function bundleMtimeOf(appDir) {
239
+ try { return statSync(join(appDir, 'out', 'main', 'index.js')).mtimeMs; } catch { return 0; }
240
+ }
241
+
242
+ export function apply(ctx, config = {}) {
243
+ if (config.autoLaunch === false) return;
244
+ let child;
245
+ let attempts = 0;
246
+ let timer;
247
+ let watcher;
248
+ let bundleStamp = 0;
249
+ let target = resolveInstalled(config);
250
+ let preparing = false;
251
+ let fatal;
252
+
253
+ const stopClock = () => {
254
+ if (timer) clearInterval(timer);
255
+ timer = undefined;
256
+ };
257
+
258
+ const startClock = () => {
259
+ if (!timer) timer = setInterval(tryLaunch, 250);
260
+ };
261
+
262
+ const useTarget = (next) => {
263
+ target = next;
264
+ bundleStamp = bundleMtimeOf(next.appDir);
265
+ startClock();
266
+ };
267
+
268
+ const prepare = () => {
269
+ if (preparing || target || fatal) return;
270
+ preparing = true;
271
+ fetchRuntime(config).then((next) => {
272
+ preparing = false;
273
+ console.info(`[dsh-status-bar] Glass runtime ready at ${next.appDir}`);
274
+ useTarget(next);
275
+ }, (error) => {
276
+ preparing = false;
277
+ fatal = `[dsh-status-bar] could not prepare the Glass runtime: ${describeError(error)}`;
278
+ console.warn(fatal);
279
+ stopClock();
280
+ });
281
+ };
282
+
283
+ const tryLaunch = () => {
284
+ if (fatal) return;
285
+ if (!target) {
286
+ // The npm build has no app yet: fetch it once, then keep waiting for the
287
+ // web server in the background instead of counting down against it.
288
+ prepare();
289
+ return;
290
+ }
291
+ attempts += 1;
292
+ if (attempts > 600) {
293
+ stopClock();
294
+ console.warn('[dsh-status-bar] no web server origin after 150s; the Glass companion was not started');
295
+ return;
296
+ }
297
+ let origin;
298
+ try { origin = ctx.webServer.getOrigin(); } catch { return; }
299
+ let link;
300
+ try { link = ctx.connection.authenticatedUrl(origin); } catch { return; }
301
+ if (!link || !/^https?:\/\//.test(link)) return;
302
+
303
+ const env = { ...process.env };
304
+ delete env.ELECTRON_RUN_AS_NODE;
305
+ const spawned = spawn(target.electron, [target.appDir, `--dsh-link=${link}`, `--launcher-pid=${process.pid}`], {
306
+ cwd: target.appDir,
307
+ detached: true,
308
+ stdio: 'ignore',
309
+ env,
310
+ });
311
+ child = spawned;
312
+ spawned.on('exit', () => { if (child === spawned) child = undefined; });
313
+ spawned.unref();
314
+ bundleStamp = bundleMtimeOf(target.appDir);
315
+ stopClock();
316
+ console.info('[dsh-status-bar] Glass desktop companion launched (authenticated link redacted)');
317
+ };
318
+
319
+ if (typeof ctx.effect === 'function') {
320
+ ctx.effect(() => () => {
321
+ stopClock();
322
+ if (watcher) clearInterval(watcher);
323
+ watcher = undefined;
324
+ killChild(child);
325
+ child = undefined;
326
+ });
327
+ }
328
+
329
+ if (target) {
330
+ startClock();
331
+ } else {
332
+ prepare();
333
+ }
334
+
335
+ if (config.autoReload !== false) {
336
+ // Rebuild-and-reload loop: when the desktop bundle changes, relaunch the
337
+ // running companion with the current authenticated link. A user-initiated
338
+ // quit leaves `child` empty, so it is never resurrected by a build.
339
+ watcher = setInterval(() => {
340
+ if (!target) return;
341
+ const stamp = bundleMtimeOf(target.appDir);
342
+ if (!child || !stamp || bundleStamp === 0 || stamp === bundleStamp) return;
343
+ bundleStamp = stamp;
344
+ console.info('[dsh-status-bar] desktop bundle changed; relaunching the Glass companion');
345
+ killChild(child);
346
+ child = undefined;
347
+ startClock();
348
+ }, 1500);
349
+ }
350
+ }
package/package.json CHANGED
@@ -1,6 +1,50 @@
1
1
  {
2
2
  "name": "dsh-status-bar-plugin",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.2.4",
4
+ "description": "Floating glass status bar for DeepSeek Harness: a frameless always-on-top window that shows session progress, pending approvals and questions.",
5
+ "license": "MIT",
6
+ "author": "wfz2006",
7
+ "type": "module",
8
+ "main": "lib/index.js",
9
+ "engines": {
10
+ "node": ">=22"
11
+ },
12
+ "keywords": [
13
+ "dsh",
14
+ "dsh-plugin",
15
+ "dsh-status-bar",
16
+ "deepseek-harness",
17
+ "glass",
18
+ "glassmorphism",
19
+ "status-bar",
20
+ "approval",
21
+ "desktop",
22
+ "electron",
23
+ "windows"
24
+ ],
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "git+https://github.com/wfz2006/dsh-status-bar.git",
28
+ "directory": "packages/dsh-status-bar"
29
+ },
30
+ "homepage": "https://github.com/wfz2006/dsh-status-bar",
31
+ "files": [
32
+ "lib",
33
+ "cordis.patch.yml",
34
+ "README.md",
35
+ "LICENSE",
36
+ "assets",
37
+ "screenshots.json"
38
+ ],
39
+ "scripts": {
40
+ "pack:release": "node ../../scripts/pack-plugin-release.mjs"
41
+ },
42
+ "dsh": {
43
+ "bundle": {
44
+ "patch": "./cordis.patch.yml"
45
+ },
46
+ "statusBar": {
47
+ "runtime": "https://github.com/wfz2006/dsh-status-bar/releases/latest/download/dsh-status-bar.tgz"
48
+ }
49
+ }
50
+ }
@@ -0,0 +1,7 @@
1
+ [
2
+ "assets/capsule.png",
3
+ "assets/peek.png",
4
+ "assets/expanded.png",
5
+ "assets/approval.png",
6
+ "assets/settings.png"
7
+ ]