@elizaos/capacitor-desktop 1.0.0 → 2.0.3-beta.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.
@@ -1,708 +0,0 @@
1
- /**
2
- * Desktop Plugin for Electrobun compatibility
3
- *
4
- * This module provides native desktop features for the desktop shell including:
5
- * - System tray management
6
- * - Global keyboard shortcuts
7
- * - Auto-launch on system startup
8
- * - Window management
9
- * - Native notifications
10
- * - Power monitoring
11
- * - Clipboard operations
12
- * - Shell operations
13
- *
14
- * This file should be loaded in the desktop main process and
15
- * its API exposed to the renderer via IPC.
16
- */
17
-
18
- import type { PluginListenerHandle } from "@capacitor/core";
19
- import {
20
- invokeDesktopBridgeRequest,
21
- subscribeDesktopBridgeEvent,
22
- } from "@elizaos/app-core";
23
- import type {
24
- EventCallback,
25
- ListenerEntry as BaseListenerEntry,
26
- } from "../../../shared-types.js";
27
- import type {
28
- AutoLaunchOptions,
29
- DesktopPlugin,
30
- GlobalShortcut,
31
- GlobalShortcutEvent,
32
- NotificationEvent,
33
- NotificationOptions,
34
- PowerMonitorState,
35
- TrayClickEvent,
36
- TrayMenuClickEvent,
37
- TrayMenuItem,
38
- TrayOptions,
39
- WindowBounds,
40
- WindowOptions,
41
- } from "../../src/definitions";
42
-
43
- type DesktopEventPayloads = {
44
- trayClick: TrayClickEvent;
45
- trayDoubleClick: TrayClickEvent;
46
- trayRightClick: TrayClickEvent;
47
- trayMenuClick: TrayMenuClickEvent;
48
- shortcutPressed: GlobalShortcutEvent;
49
- notificationClick: NotificationEvent;
50
- notificationAction: NotificationEvent;
51
- notificationReply: NotificationEvent;
52
- windowFocus: undefined;
53
- windowBlur: undefined;
54
- windowMaximize: undefined;
55
- windowUnmaximize: undefined;
56
- windowMinimize: undefined;
57
- windowRestore: undefined;
58
- windowClose: undefined;
59
- powerSuspend: undefined;
60
- powerResume: undefined;
61
- powerOnAC: undefined;
62
- powerOnBattery: undefined;
63
- };
64
-
65
- type DesktopEventName = keyof DesktopEventPayloads;
66
- type DesktopEventData = DesktopEventPayloads[DesktopEventName];
67
-
68
- type ListenerEntry = BaseListenerEntry<DesktopEventName, DesktopEventData>;
69
-
70
- type AlwaysOnTopLevel = Parameters<DesktopPlugin["setAlwaysOnTop"]>[0]["level"];
71
- type DesktopPathName = Parameters<DesktopPlugin["getPath"]>[0]["name"];
72
- type DesktopVersionResult =
73
- | {
74
- version: string;
75
- name: string;
76
- runtime: string;
77
- }
78
- | {
79
- version: string;
80
- name: string;
81
- runtime: string;
82
- chrome: string;
83
- node: string;
84
- };
85
-
86
- const DESKTOP_RPC_EVENTS: Partial<
87
- Record<DesktopEventName, { rpcMessage: string; ipcChannel: string }>
88
- > = {
89
- trayClick: {
90
- rpcMessage: "desktopTrayClick",
91
- ipcChannel: "desktop:trayClick",
92
- },
93
- trayMenuClick: {
94
- rpcMessage: "desktopTrayMenuClick",
95
- ipcChannel: "desktop:trayMenuClick",
96
- },
97
- shortcutPressed: {
98
- rpcMessage: "desktopShortcutPressed",
99
- ipcChannel: "desktop:shortcutPressed",
100
- },
101
- windowFocus: {
102
- rpcMessage: "desktopWindowFocus",
103
- ipcChannel: "desktop:windowFocus",
104
- },
105
- windowBlur: {
106
- rpcMessage: "desktopWindowBlur",
107
- ipcChannel: "desktop:windowBlur",
108
- },
109
- windowMaximize: {
110
- rpcMessage: "desktopWindowMaximize",
111
- ipcChannel: "desktop:windowMaximize",
112
- },
113
- windowUnmaximize: {
114
- rpcMessage: "desktopWindowUnmaximize",
115
- ipcChannel: "desktop:windowUnmaximize",
116
- },
117
- windowClose: {
118
- rpcMessage: "desktopWindowClose",
119
- ipcChannel: "desktop:windowClose",
120
- },
121
- };
122
-
123
- /**
124
- * Helper to throw when the desktop bridge is unavailable.
125
- * Desktop plugin features require the Electrobun native runtime.
126
- */
127
- function requireIPC(feature: string): never {
128
- throw new Error(
129
- `${feature} is not available: desktop bridge not found. ` +
130
- "The Desktop plugin requires the Electrobun main process with properly configured handlers.",
131
- );
132
- }
133
-
134
- /**
135
- * Desktop Plugin implementation for Electrobun
136
- * Uses IPC to communicate with the main process
137
- */
138
- export class DesktopElectrobun implements DesktopPlugin {
139
- private listeners: ListenerEntry[] = [];
140
- private internalSubscriptions: Array<() => void> = [];
141
-
142
- constructor() {
143
- this.setupDesktopListeners();
144
- }
145
-
146
- private async invokeBridge<T>(
147
- feature: string,
148
- rpcMethod: string,
149
- ipcChannel: string,
150
- params?: unknown,
151
- ): Promise<T> {
152
- const result = await invokeDesktopBridgeRequest<T>({
153
- rpcMethod,
154
- ipcChannel,
155
- params,
156
- });
157
- if (result === null) {
158
- requireIPC(feature);
159
- }
160
- return result as T;
161
- }
162
-
163
- private setupDesktopListeners(): void {
164
- const events: DesktopEventName[] = [
165
- "trayClick",
166
- "trayDoubleClick",
167
- "trayRightClick",
168
- "trayMenuClick",
169
- "shortcutPressed",
170
- "notificationClick",
171
- "notificationAction",
172
- "notificationReply",
173
- "windowFocus",
174
- "windowBlur",
175
- "windowMaximize",
176
- "windowUnmaximize",
177
- "windowMinimize",
178
- "windowRestore",
179
- "windowClose",
180
- "powerSuspend",
181
- "powerResume",
182
- "powerOnAC",
183
- "powerOnBattery",
184
- ];
185
-
186
- for (const eventName of events) {
187
- const rpcEvent = DESKTOP_RPC_EVENTS[eventName];
188
- if (!rpcEvent) {
189
- continue;
190
- }
191
-
192
- const unsubscribe = subscribeDesktopBridgeEvent({
193
- rpcMessage: rpcEvent.rpcMessage,
194
- ipcChannel: rpcEvent.ipcChannel,
195
- listener: (data) => {
196
- this.notifyListeners(
197
- eventName,
198
- data as DesktopEventPayloads[typeof eventName],
199
- );
200
- },
201
- });
202
- this.internalSubscriptions.push(unsubscribe);
203
- }
204
- }
205
-
206
- // System Tray
207
- async createTray(options: TrayOptions): Promise<void> {
208
- await this.invokeBridge(
209
- "createTray",
210
- "desktopCreateTray",
211
- "desktop:createTray",
212
- options,
213
- );
214
- }
215
-
216
- async updateTray(options: Partial<TrayOptions>): Promise<void> {
217
- await this.invokeBridge(
218
- "updateTray",
219
- "desktopUpdateTray",
220
- "desktop:updateTray",
221
- options,
222
- );
223
- }
224
-
225
- async destroyTray(): Promise<void> {
226
- await this.invokeBridge(
227
- "destroyTray",
228
- "desktopDestroyTray",
229
- "desktop:destroyTray",
230
- );
231
- }
232
-
233
- async setTrayMenu(options: { menu: TrayMenuItem[] }): Promise<void> {
234
- await this.invokeBridge(
235
- "setTrayMenu",
236
- "desktopSetTrayMenu",
237
- "desktop:setTrayMenu",
238
- options,
239
- );
240
- }
241
-
242
- // Global Shortcuts
243
- async registerShortcut(
244
- options: GlobalShortcut,
245
- ): Promise<{ success: boolean }> {
246
- return await this.invokeBridge<{ success: boolean }>(
247
- "registerShortcut",
248
- "desktopRegisterShortcut",
249
- "desktop:registerShortcut",
250
- options,
251
- );
252
- }
253
-
254
- async unregisterShortcut(options: { id: string }): Promise<void> {
255
- await this.invokeBridge(
256
- "unregisterShortcut",
257
- "desktopUnregisterShortcut",
258
- "desktop:unregisterShortcut",
259
- options,
260
- );
261
- }
262
-
263
- async unregisterAllShortcuts(): Promise<void> {
264
- await this.invokeBridge(
265
- "unregisterAllShortcuts",
266
- "desktopUnregisterAllShortcuts",
267
- "desktop:unregisterAllShortcuts",
268
- );
269
- }
270
-
271
- async isShortcutRegistered(options: {
272
- accelerator: string;
273
- }): Promise<{ registered: boolean }> {
274
- return await this.invokeBridge<{ registered: boolean }>(
275
- "isShortcutRegistered",
276
- "desktopIsShortcutRegistered",
277
- "desktop:isShortcutRegistered",
278
- options,
279
- );
280
- }
281
-
282
- // Auto Launch
283
- async setAutoLaunch(options: AutoLaunchOptions): Promise<void> {
284
- await this.invokeBridge(
285
- "setAutoLaunch",
286
- "desktopSetAutoLaunch",
287
- "desktop:setAutoLaunch",
288
- options,
289
- );
290
- }
291
-
292
- async getAutoLaunchStatus(): Promise<{
293
- enabled: boolean;
294
- openAsHidden: boolean;
295
- }> {
296
- return await this.invokeBridge<{
297
- enabled: boolean;
298
- openAsHidden: boolean;
299
- }>(
300
- "getAutoLaunchStatus",
301
- "desktopGetAutoLaunchStatus",
302
- "desktop:getAutoLaunchStatus",
303
- );
304
- }
305
-
306
- // Window Management
307
- async setWindowOptions(options: WindowOptions): Promise<void> {
308
- await this.invokeBridge(
309
- "setWindowOptions",
310
- "desktopSetWindowOptions",
311
- "desktop:setWindowOptions",
312
- options,
313
- );
314
- }
315
-
316
- async getWindowBounds(): Promise<WindowBounds> {
317
- return await this.invokeBridge<WindowBounds>(
318
- "getWindowBounds",
319
- "desktopGetWindowBounds",
320
- "desktop:getWindowBounds",
321
- );
322
- }
323
-
324
- async setWindowBounds(options: WindowBounds): Promise<void> {
325
- await this.invokeBridge(
326
- "setWindowBounds",
327
- "desktopSetWindowBounds",
328
- "desktop:setWindowBounds",
329
- options,
330
- );
331
- }
332
-
333
- async minimizeWindow(): Promise<void> {
334
- await this.invokeBridge(
335
- "minimizeWindow",
336
- "desktopMinimizeWindow",
337
- "desktop:minimizeWindow",
338
- );
339
- }
340
-
341
- async maximizeWindow(): Promise<void> {
342
- await this.invokeBridge(
343
- "maximizeWindow",
344
- "desktopMaximizeWindow",
345
- "desktop:maximizeWindow",
346
- );
347
- }
348
-
349
- async unmaximizeWindow(): Promise<void> {
350
- await this.invokeBridge(
351
- "unmaximizeWindow",
352
- "desktopUnmaximizeWindow",
353
- "desktop:unmaximizeWindow",
354
- );
355
- }
356
-
357
- async closeWindow(): Promise<void> {
358
- await this.invokeBridge(
359
- "closeWindow",
360
- "desktopCloseWindow",
361
- "desktop:closeWindow",
362
- );
363
- }
364
-
365
- async showWindow(): Promise<void> {
366
- await this.invokeBridge(
367
- "showWindow",
368
- "desktopShowWindow",
369
- "desktop:showWindow",
370
- );
371
- }
372
-
373
- async hideWindow(): Promise<void> {
374
- await this.invokeBridge(
375
- "hideWindow",
376
- "desktopHideWindow",
377
- "desktop:hideWindow",
378
- );
379
- }
380
-
381
- async focusWindow(): Promise<void> {
382
- await this.invokeBridge(
383
- "focusWindow",
384
- "desktopFocusWindow",
385
- "desktop:focusWindow",
386
- );
387
- }
388
-
389
- async isWindowMaximized(): Promise<{ maximized: boolean }> {
390
- return await this.invokeBridge<{ maximized: boolean }>(
391
- "isWindowMaximized",
392
- "desktopIsWindowMaximized",
393
- "desktop:isWindowMaximized",
394
- );
395
- }
396
-
397
- async isWindowMinimized(): Promise<{ minimized: boolean }> {
398
- return await this.invokeBridge<{ minimized: boolean }>(
399
- "isWindowMinimized",
400
- "desktopIsWindowMinimized",
401
- "desktop:isWindowMinimized",
402
- );
403
- }
404
-
405
- async isWindowVisible(): Promise<{ visible: boolean }> {
406
- return await this.invokeBridge<{ visible: boolean }>(
407
- "isWindowVisible",
408
- "desktopIsWindowVisible",
409
- "desktop:isWindowVisible",
410
- );
411
- }
412
-
413
- async isWindowFocused(): Promise<{ focused: boolean }> {
414
- return await this.invokeBridge<{ focused: boolean }>(
415
- "isWindowFocused",
416
- "desktopIsWindowFocused",
417
- "desktop:isWindowFocused",
418
- );
419
- }
420
-
421
- async setAlwaysOnTop(options: {
422
- flag: boolean;
423
- level?: AlwaysOnTopLevel;
424
- }): Promise<void> {
425
- await this.invokeBridge(
426
- "setAlwaysOnTop",
427
- "desktopSetAlwaysOnTop",
428
- "desktop:setAlwaysOnTop",
429
- options,
430
- );
431
- }
432
-
433
- async setFullscreen(options: { flag: boolean }): Promise<void> {
434
- await this.invokeBridge(
435
- "setFullscreen",
436
- "desktopSetFullscreen",
437
- "desktop:setFullscreen",
438
- options,
439
- );
440
- }
441
-
442
- async setOpacity(options: { opacity: number }): Promise<void> {
443
- await this.invokeBridge(
444
- "setOpacity",
445
- "desktopSetOpacity",
446
- "desktop:setOpacity",
447
- options,
448
- );
449
- }
450
-
451
- // Notifications
452
- async showNotification(
453
- options: NotificationOptions,
454
- ): Promise<{ id: string }> {
455
- return await this.invokeBridge<{ id: string }>(
456
- "showNotification",
457
- "desktopShowNotification",
458
- "desktop:showNotification",
459
- options,
460
- );
461
- }
462
-
463
- async closeNotification(options: { id: string }): Promise<void> {
464
- await this.invokeBridge(
465
- "closeNotification",
466
- "desktopCloseNotification",
467
- "desktop:closeNotification",
468
- options,
469
- );
470
- }
471
-
472
- // Power Monitor
473
- async getPowerState(): Promise<PowerMonitorState> {
474
- return await this.invokeBridge<PowerMonitorState>(
475
- "getPowerState",
476
- "desktopGetPowerState",
477
- "desktop:getPowerState",
478
- );
479
- }
480
-
481
- // App
482
- async quit(): Promise<void> {
483
- await this.invokeBridge("quit", "desktopQuit", "desktop:quit");
484
- }
485
-
486
- async relaunch(): Promise<void> {
487
- await this.invokeBridge("relaunch", "desktopRelaunch", "desktop:relaunch");
488
- }
489
-
490
- async getVersion(): Promise<{
491
- version: string;
492
- name: string;
493
- runtime: string;
494
- chrome: string;
495
- node: string;
496
- }> {
497
- const version = await this.invokeBridge<DesktopVersionResult>(
498
- "getVersion",
499
- "desktopGetVersion",
500
- "desktop:getVersion",
501
- );
502
- if ("runtime" in version) {
503
- return {
504
- version: version.version,
505
- name: version.name,
506
- runtime: version.runtime,
507
- chrome: "N/A",
508
- node: "N/A",
509
- };
510
- }
511
- return version;
512
- }
513
-
514
- async isPackaged(): Promise<{ packaged: boolean }> {
515
- return await this.invokeBridge<{ packaged: boolean }>(
516
- "isPackaged",
517
- "desktopIsPackaged",
518
- "desktop:isPackaged",
519
- );
520
- }
521
-
522
- async getPath(options: { name: DesktopPathName }): Promise<{ path: string }> {
523
- return await this.invokeBridge<{ path: string }>(
524
- "getPath",
525
- "desktopGetPath",
526
- "desktop:getPath",
527
- options,
528
- );
529
- }
530
-
531
- // Clipboard
532
- async writeToClipboard(options: {
533
- text?: string;
534
- html?: string;
535
- image?: string;
536
- rtf?: string;
537
- }): Promise<void> {
538
- await this.invokeBridge(
539
- "writeToClipboard",
540
- "desktopWriteToClipboard",
541
- "desktop:writeToClipboard",
542
- options,
543
- );
544
- }
545
-
546
- async readFromClipboard(): Promise<{
547
- text?: string;
548
- html?: string;
549
- rtf?: string;
550
- hasImage: boolean;
551
- }> {
552
- return await this.invokeBridge<{
553
- text?: string;
554
- html?: string;
555
- rtf?: string;
556
- hasImage: boolean;
557
- }>(
558
- "readFromClipboard",
559
- "desktopReadFromClipboard",
560
- "desktop:readFromClipboard",
561
- );
562
- }
563
-
564
- async clearClipboard(): Promise<void> {
565
- await this.invokeBridge(
566
- "clearClipboard",
567
- "desktopClearClipboard",
568
- "desktop:clearClipboard",
569
- );
570
- }
571
-
572
- // Shell
573
- async openExternal(options: { url: string }): Promise<void> {
574
- await this.invokeBridge(
575
- "openExternal",
576
- "desktopOpenExternal",
577
- "desktop:openExternal",
578
- options,
579
- );
580
- }
581
-
582
- async showItemInFolder(options: { path: string }): Promise<void> {
583
- await this.invokeBridge(
584
- "showItemInFolder",
585
- "desktopShowItemInFolder",
586
- "desktop:showItemInFolder",
587
- options,
588
- );
589
- }
590
-
591
- async beep(): Promise<void> {
592
- await this.invokeBridge("beep", "desktopBeep", "desktop:beep");
593
- }
594
-
595
- // Events
596
- async addListener(
597
- eventName: "trayClick",
598
- listenerFunc: (event: TrayClickEvent) => void,
599
- ): Promise<PluginListenerHandle>;
600
- async addListener(
601
- eventName: "trayDoubleClick",
602
- listenerFunc: (event: TrayClickEvent) => void,
603
- ): Promise<PluginListenerHandle>;
604
- async addListener(
605
- eventName: "trayRightClick",
606
- listenerFunc: (event: TrayClickEvent) => void,
607
- ): Promise<PluginListenerHandle>;
608
- async addListener(
609
- eventName: "trayMenuClick",
610
- listenerFunc: (event: TrayMenuClickEvent) => void,
611
- ): Promise<PluginListenerHandle>;
612
- async addListener(
613
- eventName: "shortcutPressed",
614
- listenerFunc: (event: GlobalShortcutEvent) => void,
615
- ): Promise<PluginListenerHandle>;
616
- async addListener(
617
- eventName: "notificationClick",
618
- listenerFunc: (event: NotificationEvent) => void,
619
- ): Promise<PluginListenerHandle>;
620
- async addListener(
621
- eventName: "notificationAction",
622
- listenerFunc: (event: NotificationEvent) => void,
623
- ): Promise<PluginListenerHandle>;
624
- async addListener(
625
- eventName: "notificationReply",
626
- listenerFunc: (event: NotificationEvent) => void,
627
- ): Promise<PluginListenerHandle>;
628
- async addListener(
629
- eventName: "windowFocus",
630
- listenerFunc: () => void,
631
- ): Promise<PluginListenerHandle>;
632
- async addListener(
633
- eventName: "windowBlur",
634
- listenerFunc: () => void,
635
- ): Promise<PluginListenerHandle>;
636
- async addListener(
637
- eventName: "windowMaximize",
638
- listenerFunc: () => void,
639
- ): Promise<PluginListenerHandle>;
640
- async addListener(
641
- eventName: "windowUnmaximize",
642
- listenerFunc: () => void,
643
- ): Promise<PluginListenerHandle>;
644
- async addListener(
645
- eventName: "windowMinimize",
646
- listenerFunc: () => void,
647
- ): Promise<PluginListenerHandle>;
648
- async addListener(
649
- eventName: "windowRestore",
650
- listenerFunc: () => void,
651
- ): Promise<PluginListenerHandle>;
652
- async addListener(
653
- eventName: "windowClose",
654
- listenerFunc: () => void,
655
- ): Promise<PluginListenerHandle>;
656
- async addListener(
657
- eventName: "powerSuspend",
658
- listenerFunc: () => void,
659
- ): Promise<PluginListenerHandle>;
660
- async addListener(
661
- eventName: "powerResume",
662
- listenerFunc: () => void,
663
- ): Promise<PluginListenerHandle>;
664
- async addListener(
665
- eventName: "powerOnAC",
666
- listenerFunc: () => void,
667
- ): Promise<PluginListenerHandle>;
668
- async addListener(
669
- eventName: "powerOnBattery",
670
- listenerFunc: () => void,
671
- ): Promise<PluginListenerHandle>;
672
- async addListener(
673
- eventName: DesktopEventName,
674
- listenerFunc: EventCallback<DesktopEventData>,
675
- ): Promise<PluginListenerHandle> {
676
- const entry: ListenerEntry = { eventName, callback: listenerFunc };
677
- this.listeners.push(entry);
678
-
679
- return {
680
- remove: async () => {
681
- const idx = this.listeners.indexOf(entry);
682
- if (idx >= 0) {
683
- this.listeners.splice(idx, 1);
684
- }
685
- },
686
- };
687
- }
688
-
689
- async removeAllListeners(): Promise<void> {
690
- this.listeners = [];
691
- }
692
-
693
- private notifyListeners<T extends DesktopEventName>(
694
- eventName: T,
695
- data?: DesktopEventPayloads[T],
696
- ): void {
697
- for (const listener of this.listeners) {
698
- if (listener.eventName === eventName) {
699
- (listener.callback as EventCallback<DesktopEventPayloads[T]>)(
700
- data as DesktopEventPayloads[T],
701
- );
702
- }
703
- }
704
- }
705
- }
706
-
707
- // Export the plugin instance
708
- export const Desktop = new DesktopElectrobun();
@@ -1,16 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2020",
4
- "module": "ESNext",
5
- "moduleResolution": "bundler",
6
- "lib": ["ES2020", "DOM"],
7
- "declaration": true,
8
- "outDir": "dist",
9
- "strict": true,
10
- "skipLibCheck": true,
11
- "esModuleInterop": true,
12
- "forceConsistentCasingInFileNames": true
13
- },
14
- "include": ["src/**/*.ts"],
15
- "exclude": ["node_modules", "dist"]
16
- }