@owdproject/core 3.4.0 → 4.0.0-alpha.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/README.md +112 -13
- package/dist/dom/index.d.mts +65 -0
- package/dist/dom/index.d.ts +65 -0
- package/dist/dom/index.mjs +224 -0
- package/dist/events/index.d.mts +70 -0
- package/dist/events/index.d.ts +70 -0
- package/dist/events/index.mjs +3 -0
- package/dist/index.d.mts +73 -0
- package/dist/index.d.ts +73 -0
- package/dist/index.mjs +115 -0
- package/dist/layout/index.d.mts +41 -0
- package/dist/layout/index.d.ts +41 -0
- package/dist/layout/index.mjs +64 -0
- package/dist/machines/index.d.mts +31 -0
- package/dist/machines/index.d.ts +31 -0
- package/dist/machines/index.mjs +2 -0
- package/dist/managers/index.d.mts +118 -0
- package/dist/managers/index.d.ts +118 -0
- package/dist/managers/index.mjs +6 -0
- package/dist/session/index.d.mts +57 -0
- package/dist/session/index.d.ts +57 -0
- package/dist/session/index.mjs +65 -0
- package/dist/shared/core.B1XxB289.mjs +239 -0
- package/dist/shared/core.B3mp7ztE.mjs +237 -0
- package/dist/shared/core.BOvFdEVQ.d.ts +114 -0
- package/dist/shared/core.CsDFgGnX.mjs +40 -0
- package/dist/shared/core.Di1eFcr_.d.mts +114 -0
- package/dist/shared/core.Pd_Ogt4g.mjs +101 -0
- package/dist/shared/core.b3Xldzyu.mjs +29 -0
- package/dist/shared/core.d_A3q1kZ.mjs +869 -0
- package/dist/types/index.d.mts +266 -0
- package/dist/types/index.d.ts +266 -0
- package/dist/types/index.mjs +1 -0
- package/package.json +56 -112
- package/CHANGELOG.md +0 -98
- package/DESKTOP_KERNEL.md +0 -232
- package/MIGRATION_3.3.2.md +0 -23
- package/MIGRATION_3.4.md +0 -126
- package/PLAYGROUND.md +0 -91
- package/dist/module.d.mts +0 -13
- package/dist/module.json +0 -9
- package/dist/module.mjs +0 -254
- package/dist/types.d.mts +0 -7
- package/index.ts +0 -8
- package/kit/authoring.ts +0 -340
- package/kit/defineDesktopApp.ts +0 -56
- package/module.ts +0 -203
- package/runtime/components/Application/DesktopCoreApplicationRender.vue +0 -20
- package/runtime/components/Application/DesktopCoreApplicationWindowsRender.vue +0 -38
- package/runtime/components/background/DesktopCoreBackground.vue +0 -16
- package/runtime/components/core/DesktopCore.vue +0 -43
- package/runtime/components/time/DesktopCoreTime.vue +0 -56
- package/runtime/components/window/DesktopCoreWindow.vue +0 -215
- package/runtime/components/window/DesktopCoreWindowContent.vue +0 -28
- package/runtime/components/window/DesktopCoreWindowNav.vue +0 -66
- package/runtime/components/window/DesktopCoreWindowSnapHintsBase.vue +0 -74
- package/runtime/components/workspace/DesktopCoreWorkspaceEdgeHintsBase.vue +0 -84
- package/runtime/composables/useApplicationEntries.ts +0 -51
- package/runtime/composables/useApplicationManager.ts +0 -285
- package/runtime/composables/useBlockNonInputContextMenu.ts +0 -30
- package/runtime/composables/useDesktopConfig.ts +0 -8
- package/runtime/composables/useDesktopDialogs.ts +0 -16
- package/runtime/composables/useDesktopExtension.ts +0 -8
- package/runtime/composables/useDesktopManager.ts +0 -51
- package/runtime/composables/useDesktopManifest.ts +0 -17
- package/runtime/composables/useDesktopSession.ts +0 -27
- package/runtime/composables/useDesktopShellIdentity.ts +0 -99
- package/runtime/composables/useDesktopShellOptions.ts +0 -36
- package/runtime/composables/useDesktopShellReady.ts +0 -7
- package/runtime/composables/useDesktopWorkArea.ts +0 -93
- package/runtime/composables/useTerminalManager.ts +0 -159
- package/runtime/composables/useToggleWindowMaximize.ts +0 -35
- package/runtime/composables/useWindowDragHandlers.ts +0 -47
- package/runtime/composables/useWindowSnapDrop.ts +0 -112
- package/runtime/composables/useWorkspaceEdgeDrop.ts +0 -176
- package/runtime/composables/useWorkspaceManager.ts +0 -67
- package/runtime/composables/useWorkspaceOverviewCapture.ts +0 -92
- package/runtime/composables/useWorkspaceOverviewLiveScale.ts +0 -151
- package/runtime/constants/desktopShellKeys.ts +0 -12
- package/runtime/constants/shellLayout.ts +0 -5
- package/runtime/dialogs/desktopDialogProvider.ts +0 -73
- package/runtime/internal/controllers/ApplicationController.ts +0 -351
- package/runtime/internal/controllers/WindowController.ts +0 -547
- package/runtime/plugins/01.desktop-shell-init.client.ts +0 -28
- package/runtime/plugins/02.desktop-register-desktop-apps.client.ts +0 -13
- package/runtime/plugins/resize.client.ts +0 -6
- package/runtime/stores/storeApplicationMeta.ts +0 -60
- package/runtime/stores/storeApplicationWindows.ts +0 -21
- package/runtime/stores/storeDesktop.ts +0 -71
- package/runtime/stores/storeDesktopDefaultApps.ts +0 -54
- package/runtime/stores/storeDesktopVolume.ts +0 -19
- package/runtime/stores/storeDesktopWindow.ts +0 -38
- package/runtime/stores/storeDesktopWorkspace.ts +0 -105
- package/runtime/stores/storeIds.ts +0 -35
- package/runtime/types/desktopMenu.ts +0 -10
- package/runtime/utils/initDesktopShell.ts +0 -80
- package/runtime/utils/migratePersistedStoreIds.ts +0 -57
- package/runtime/utils/utilApp.ts +0 -25
- package/runtime/utils/utilCaptureElementToCanvas.ts +0 -21
- package/runtime/utils/utilCommon.ts +0 -26
- package/runtime/utils/utilDebug.ts +0 -30
- package/runtime/utils/utilDetectSnapZone.ts +0 -57
- package/runtime/utils/utilTerminal.ts +0 -6
- package/runtime/utils/utilWindowControllerAdapter.ts +0 -15
- package/runtime/utils/utilWindowLayout.ts +0 -82
- package/runtime/utils/utilWindowMaximizeLayout.ts +0 -44
- package/runtime/utils/utilWorkspaceWindows.ts +0 -33
- package/types/index.d.ts +0 -531
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { W as WindowManager, a as WindowInstance } from '../shared/core.BOvFdEVQ.js';
|
|
2
|
+
import { CoreIPCBus } from '../events/index.js';
|
|
3
|
+
import { Hookable } from 'hookable';
|
|
4
|
+
import { DesktopWorkareaRect, DesktopRuntimeHooks, ApplicationConfig, ApplicationPermission, WindowState } from '../types/index.js';
|
|
5
|
+
|
|
6
|
+
interface WorkspaceState {
|
|
7
|
+
readonly workspaces: readonly string[];
|
|
8
|
+
readonly active: string;
|
|
9
|
+
readonly workarea: DesktopWorkareaRect;
|
|
10
|
+
}
|
|
11
|
+
declare class WorkspaceManager {
|
|
12
|
+
private state;
|
|
13
|
+
private subscribers;
|
|
14
|
+
private hooks;
|
|
15
|
+
private ipc;
|
|
16
|
+
constructor(options?: {
|
|
17
|
+
workspaces?: string[];
|
|
18
|
+
active?: string;
|
|
19
|
+
workarea?: DesktopWorkareaRect;
|
|
20
|
+
hooks?: Hookable<DesktopRuntimeHooks>;
|
|
21
|
+
ipc?: CoreIPCBus;
|
|
22
|
+
});
|
|
23
|
+
private updateState;
|
|
24
|
+
getSnapshot(): WorkspaceState;
|
|
25
|
+
subscribe(callback: (state: WorkspaceState) => void): () => void;
|
|
26
|
+
private notify;
|
|
27
|
+
get activeWorkspace(): string;
|
|
28
|
+
get workspaces(): string[];
|
|
29
|
+
get workarea(): DesktopWorkareaRect;
|
|
30
|
+
setWorkspace(workspaceId: string): Promise<boolean>;
|
|
31
|
+
setWorkarea(workarea: DesktopWorkareaRect): void;
|
|
32
|
+
addWorkspace(id: string): void;
|
|
33
|
+
removeWorkspace(id: string): boolean;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
interface ApplicationProcessSnapshot {
|
|
37
|
+
readonly id: string;
|
|
38
|
+
readonly title: string;
|
|
39
|
+
readonly icon?: string;
|
|
40
|
+
readonly category?: string;
|
|
41
|
+
readonly stateValue: string;
|
|
42
|
+
readonly pid: number | null;
|
|
43
|
+
readonly startedAt: number | null;
|
|
44
|
+
readonly isRunning: boolean;
|
|
45
|
+
readonly isSuspended: boolean;
|
|
46
|
+
readonly windowIds: readonly string[];
|
|
47
|
+
}
|
|
48
|
+
declare class ApplicationInstance {
|
|
49
|
+
readonly id: string;
|
|
50
|
+
readonly config: ApplicationConfig;
|
|
51
|
+
private actor;
|
|
52
|
+
private _pid;
|
|
53
|
+
private _startedAt;
|
|
54
|
+
private _windowIds;
|
|
55
|
+
private snapshot;
|
|
56
|
+
private subscribers;
|
|
57
|
+
private windowManager;
|
|
58
|
+
private workspaceManager?;
|
|
59
|
+
private hooks;
|
|
60
|
+
private ipc;
|
|
61
|
+
private allocatePid;
|
|
62
|
+
constructor(options: {
|
|
63
|
+
config: ApplicationConfig;
|
|
64
|
+
windowManager: WindowManager;
|
|
65
|
+
workspaceManager?: WorkspaceManager;
|
|
66
|
+
hooks?: Hookable<DesktopRuntimeHooks>;
|
|
67
|
+
ipc?: CoreIPCBus;
|
|
68
|
+
allocatePid: () => number;
|
|
69
|
+
});
|
|
70
|
+
private computeSnapshot;
|
|
71
|
+
private refreshSnapshot;
|
|
72
|
+
private notify;
|
|
73
|
+
getSnapshot(): ApplicationProcessSnapshot;
|
|
74
|
+
subscribe(callback: (snapshot: ApplicationProcessSnapshot) => void): () => void;
|
|
75
|
+
get pid(): number | null;
|
|
76
|
+
get startedAt(): number | null;
|
|
77
|
+
get stateValue(): string;
|
|
78
|
+
get isRunning(): boolean;
|
|
79
|
+
get isSuspended(): boolean;
|
|
80
|
+
hasPermission(permission: ApplicationPermission): boolean;
|
|
81
|
+
private ensureProcessStarted;
|
|
82
|
+
private reuseSingletonWindow;
|
|
83
|
+
launch(entryKey?: string, argument?: string): Promise<boolean>;
|
|
84
|
+
openWindow(model: string, meta?: Record<string, any>, initialState?: Partial<WindowState>): Promise<WindowInstance | undefined>;
|
|
85
|
+
closeWindow(windowId: string): Promise<boolean>;
|
|
86
|
+
closeAllWindows(): void;
|
|
87
|
+
suspend(): Promise<boolean>;
|
|
88
|
+
resume(): Promise<boolean>;
|
|
89
|
+
terminate(signal?: 'SIGTERM' | 'SIGKILL'): Promise<boolean>;
|
|
90
|
+
}
|
|
91
|
+
declare class ApplicationManager {
|
|
92
|
+
private apps;
|
|
93
|
+
private snapshotCache;
|
|
94
|
+
private pidCounter;
|
|
95
|
+
private subscribers;
|
|
96
|
+
private windowManager;
|
|
97
|
+
private workspaceManager?;
|
|
98
|
+
private hooks;
|
|
99
|
+
private ipc;
|
|
100
|
+
constructor(options: {
|
|
101
|
+
windowManager: WindowManager;
|
|
102
|
+
workspaceManager?: WorkspaceManager;
|
|
103
|
+
hooks?: Hookable<DesktopRuntimeHooks>;
|
|
104
|
+
ipc?: CoreIPCBus;
|
|
105
|
+
});
|
|
106
|
+
getSnapshot(): ApplicationInstance[];
|
|
107
|
+
subscribe(callback: (apps: ApplicationInstance[]) => void): () => void;
|
|
108
|
+
private notify;
|
|
109
|
+
register(config: ApplicationConfig): ApplicationInstance;
|
|
110
|
+
get(id: string): ApplicationInstance | undefined;
|
|
111
|
+
getByPid(pid: number): ApplicationInstance | undefined;
|
|
112
|
+
get runningApps(): ApplicationInstance[];
|
|
113
|
+
launch(id: string, entryKey?: string, argument?: string): Promise<boolean>;
|
|
114
|
+
terminate(idOrPid: string | number, signal?: 'SIGTERM' | 'SIGKILL'): Promise<boolean>;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export { ApplicationInstance, ApplicationManager, WindowInstance, WindowManager, WorkspaceManager };
|
|
118
|
+
export type { ApplicationProcessSnapshot, WorkspaceState };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { A as ApplicationInstance, a as ApplicationManager, W as WindowInstance, b as WindowManager, c as WorkspaceManager } from '../shared/core.d_A3q1kZ.mjs';
|
|
2
|
+
import 'xstate';
|
|
3
|
+
import '../shared/core.B3mp7ztE.mjs';
|
|
4
|
+
import '../shared/core.CsDFgGnX.mjs';
|
|
5
|
+
import '../shared/core.Pd_Ogt4g.mjs';
|
|
6
|
+
import 'hookable';
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { WindowManager } from '../index.mjs';
|
|
2
|
+
import 'hookable';
|
|
3
|
+
import '../types/index.mjs';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @owdproject/core - Desktop Session Serializer & Hydration Engine
|
|
7
|
+
* Allows full state capture, persistence (LocalStorage / Database), and instant restore
|
|
8
|
+
* across sessions, devices, and frameworks.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
interface DesktopSerializedWindow {
|
|
12
|
+
id: string;
|
|
13
|
+
model: string;
|
|
14
|
+
workspace: string;
|
|
15
|
+
title?: string;
|
|
16
|
+
position?: {
|
|
17
|
+
x?: number;
|
|
18
|
+
y?: number;
|
|
19
|
+
z?: number;
|
|
20
|
+
};
|
|
21
|
+
size?: {
|
|
22
|
+
width?: any;
|
|
23
|
+
height?: any;
|
|
24
|
+
};
|
|
25
|
+
maximized?: boolean;
|
|
26
|
+
layout?: any;
|
|
27
|
+
spatial?: any;
|
|
28
|
+
focused?: boolean;
|
|
29
|
+
meta?: Record<string, any>;
|
|
30
|
+
}
|
|
31
|
+
interface DesktopSerializedSession {
|
|
32
|
+
version: number;
|
|
33
|
+
timestamp: number;
|
|
34
|
+
activeWorkspace?: string;
|
|
35
|
+
windows: DesktopSerializedWindow[];
|
|
36
|
+
}
|
|
37
|
+
declare class DesktopSessionManager {
|
|
38
|
+
static readonly CURRENT_VERSION = 1;
|
|
39
|
+
/**
|
|
40
|
+
* Serializes current WindowManager state into a JSON-compatible object.
|
|
41
|
+
*/
|
|
42
|
+
static serialize(windowManager: WindowManager, options?: {
|
|
43
|
+
activeWorkspace?: string;
|
|
44
|
+
}): DesktopSerializedSession;
|
|
45
|
+
/**
|
|
46
|
+
* Restores windows from a serialized session into a WindowManager instance.
|
|
47
|
+
*/
|
|
48
|
+
static restore(windowManager: WindowManager, session: DesktopSerializedSession, options?: {
|
|
49
|
+
componentResolver?: (model: string) => any;
|
|
50
|
+
}): {
|
|
51
|
+
restoredCount: number;
|
|
52
|
+
errors: string[];
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export { DesktopSessionManager };
|
|
57
|
+
export type { DesktopSerializedSession, DesktopSerializedWindow };
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { WindowManager } from '../index.js';
|
|
2
|
+
import 'hookable';
|
|
3
|
+
import '../types/index.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @owdproject/core - Desktop Session Serializer & Hydration Engine
|
|
7
|
+
* Allows full state capture, persistence (LocalStorage / Database), and instant restore
|
|
8
|
+
* across sessions, devices, and frameworks.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
interface DesktopSerializedWindow {
|
|
12
|
+
id: string;
|
|
13
|
+
model: string;
|
|
14
|
+
workspace: string;
|
|
15
|
+
title?: string;
|
|
16
|
+
position?: {
|
|
17
|
+
x?: number;
|
|
18
|
+
y?: number;
|
|
19
|
+
z?: number;
|
|
20
|
+
};
|
|
21
|
+
size?: {
|
|
22
|
+
width?: any;
|
|
23
|
+
height?: any;
|
|
24
|
+
};
|
|
25
|
+
maximized?: boolean;
|
|
26
|
+
layout?: any;
|
|
27
|
+
spatial?: any;
|
|
28
|
+
focused?: boolean;
|
|
29
|
+
meta?: Record<string, any>;
|
|
30
|
+
}
|
|
31
|
+
interface DesktopSerializedSession {
|
|
32
|
+
version: number;
|
|
33
|
+
timestamp: number;
|
|
34
|
+
activeWorkspace?: string;
|
|
35
|
+
windows: DesktopSerializedWindow[];
|
|
36
|
+
}
|
|
37
|
+
declare class DesktopSessionManager {
|
|
38
|
+
static readonly CURRENT_VERSION = 1;
|
|
39
|
+
/**
|
|
40
|
+
* Serializes current WindowManager state into a JSON-compatible object.
|
|
41
|
+
*/
|
|
42
|
+
static serialize(windowManager: WindowManager, options?: {
|
|
43
|
+
activeWorkspace?: string;
|
|
44
|
+
}): DesktopSerializedSession;
|
|
45
|
+
/**
|
|
46
|
+
* Restores windows from a serialized session into a WindowManager instance.
|
|
47
|
+
*/
|
|
48
|
+
static restore(windowManager: WindowManager, session: DesktopSerializedSession, options?: {
|
|
49
|
+
componentResolver?: (model: string) => any;
|
|
50
|
+
}): {
|
|
51
|
+
restoredCount: number;
|
|
52
|
+
errors: string[];
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export { DesktopSessionManager };
|
|
57
|
+
export type { DesktopSerializedSession, DesktopSerializedWindow };
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
class DesktopSessionManager {
|
|
2
|
+
static CURRENT_VERSION = 1;
|
|
3
|
+
/**
|
|
4
|
+
* Serializes current WindowManager state into a JSON-compatible object.
|
|
5
|
+
*/
|
|
6
|
+
static serialize(windowManager, options) {
|
|
7
|
+
const windows = windowManager.getSnapshot();
|
|
8
|
+
const serializedWindows = windows.filter((win) => win.state.active).map((win) => {
|
|
9
|
+
return {
|
|
10
|
+
id: win.id,
|
|
11
|
+
model: win.model ?? "window",
|
|
12
|
+
workspace: win.state.workspace,
|
|
13
|
+
title: win.config.title,
|
|
14
|
+
position: win.state.position,
|
|
15
|
+
size: win.state.size,
|
|
16
|
+
maximized: win.state.maximized,
|
|
17
|
+
layout: win.state.layout,
|
|
18
|
+
spatial: win.state.spatial,
|
|
19
|
+
focused: win.state.focused
|
|
20
|
+
};
|
|
21
|
+
});
|
|
22
|
+
return {
|
|
23
|
+
version: DesktopSessionManager.CURRENT_VERSION,
|
|
24
|
+
timestamp: Date.now(),
|
|
25
|
+
activeWorkspace: options?.activeWorkspace,
|
|
26
|
+
windows: serializedWindows
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Restores windows from a serialized session into a WindowManager instance.
|
|
31
|
+
*/
|
|
32
|
+
static restore(windowManager, session, options) {
|
|
33
|
+
const errors = [];
|
|
34
|
+
let restoredCount = 0;
|
|
35
|
+
if (!session || typeof session !== "object" || !Array.isArray(session.windows)) {
|
|
36
|
+
return { restoredCount: 0, errors: ["Invalid session format"] };
|
|
37
|
+
}
|
|
38
|
+
for (const item of session.windows) {
|
|
39
|
+
try {
|
|
40
|
+
const component = options?.componentResolver?.(item.model);
|
|
41
|
+
windowManager.createWindow({
|
|
42
|
+
id: item.id,
|
|
43
|
+
model: item.model,
|
|
44
|
+
config: {
|
|
45
|
+
title: item.title,
|
|
46
|
+
component
|
|
47
|
+
},
|
|
48
|
+
initialState: {
|
|
49
|
+
workspace: item.workspace,
|
|
50
|
+
position: item.position,
|
|
51
|
+
size: item.size ?? { width: 640, height: 480 },
|
|
52
|
+
maximized: item.maximized,
|
|
53
|
+
spatial: item.spatial
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
restoredCount++;
|
|
57
|
+
} catch (err) {
|
|
58
|
+
errors.push(`Failed to restore window ${item.id}: ${err?.message || String(err)}`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return { restoredCount, errors };
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export { DesktopSessionManager };
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import { g as globalDesktopHooks, a as globalIPCBus } from './core.Pd_Ogt4g.mjs';
|
|
2
|
+
|
|
3
|
+
function shellEscape(str) {
|
|
4
|
+
if (str === "") {
|
|
5
|
+
return "''";
|
|
6
|
+
}
|
|
7
|
+
return `${str.replace(/'/g, `'\\''`)}`;
|
|
8
|
+
}
|
|
9
|
+
function padEnd(str, len) {
|
|
10
|
+
return str.length >= len ? str : str + " ".repeat(len - str.length);
|
|
11
|
+
}
|
|
12
|
+
function formatDuration(ms) {
|
|
13
|
+
const totalSec = Math.max(0, Math.floor(ms / 1e3));
|
|
14
|
+
const m = Math.floor(totalSec / 60);
|
|
15
|
+
const s = totalSec % 60;
|
|
16
|
+
return `${String(m).padStart(2, "0")}m ${String(s).padStart(2, "0")}s`;
|
|
17
|
+
}
|
|
18
|
+
function parseCommandLine(input) {
|
|
19
|
+
const trimmed = input.trim();
|
|
20
|
+
if (!trimmed) {
|
|
21
|
+
return { name: "", args: [] };
|
|
22
|
+
}
|
|
23
|
+
const [name = "", ...args] = trimmed.split(/\s+/);
|
|
24
|
+
return { name, args };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
class DesktopKeybindings {
|
|
28
|
+
windowManager;
|
|
29
|
+
workareaProvider;
|
|
30
|
+
customHandlers = /* @__PURE__ */ new Map();
|
|
31
|
+
isListening = false;
|
|
32
|
+
listenerRef;
|
|
33
|
+
constructor(windowManager, options) {
|
|
34
|
+
this.windowManager = windowManager;
|
|
35
|
+
this.workareaProvider = options?.workareaProvider;
|
|
36
|
+
}
|
|
37
|
+
register(shortcut, handler) {
|
|
38
|
+
this.customHandlers.set(shortcut.toLowerCase(), handler);
|
|
39
|
+
return this;
|
|
40
|
+
}
|
|
41
|
+
listen() {
|
|
42
|
+
if (typeof window === "undefined" || this.isListening) {
|
|
43
|
+
return () => this.stop();
|
|
44
|
+
}
|
|
45
|
+
this.isListening = true;
|
|
46
|
+
this.listenerRef = (e) => this.handleKeyDown(e);
|
|
47
|
+
window.addEventListener("keydown", this.listenerRef);
|
|
48
|
+
return () => this.stop();
|
|
49
|
+
}
|
|
50
|
+
stop() {
|
|
51
|
+
if (typeof window !== "undefined" && this.listenerRef) {
|
|
52
|
+
window.removeEventListener("keydown", this.listenerRef);
|
|
53
|
+
}
|
|
54
|
+
this.isListening = false;
|
|
55
|
+
}
|
|
56
|
+
handleKeyDown(e) {
|
|
57
|
+
const activeEl = document.activeElement;
|
|
58
|
+
if (activeEl && (activeEl.tagName === "INPUT" || activeEl.tagName === "TEXTAREA" || activeEl.isContentEditable)) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
const isMetaOrCtrl = e.metaKey || e.ctrlKey;
|
|
62
|
+
const isAlt = e.altKey;
|
|
63
|
+
const isShift = e.shiftKey;
|
|
64
|
+
const key = e.key.toLowerCase();
|
|
65
|
+
if (isAlt && key === "tab") {
|
|
66
|
+
e.preventDefault();
|
|
67
|
+
this.cycleWindowFocus(isShift ? "backward" : "forward");
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (isMetaOrCtrl) {
|
|
71
|
+
const focused = this.windowManager.focusedWindow;
|
|
72
|
+
const workarea = this.workareaProvider?.() ?? {
|
|
73
|
+
x: 0,
|
|
74
|
+
y: 0,
|
|
75
|
+
width: typeof window !== "undefined" ? window.innerWidth : 1920,
|
|
76
|
+
height: typeof window !== "undefined" ? window.innerHeight : 1080
|
|
77
|
+
};
|
|
78
|
+
if (key === "arrowleft" && focused) {
|
|
79
|
+
e.preventDefault();
|
|
80
|
+
this.windowManager.snapWindow(focused.id, "left-half", workarea);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
if (key === "arrowright" && focused) {
|
|
84
|
+
e.preventDefault();
|
|
85
|
+
this.windowManager.snapWindow(focused.id, "right-half", workarea);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
if (key === "arrowup" && focused) {
|
|
89
|
+
e.preventDefault();
|
|
90
|
+
if (!focused.state.maximized) {
|
|
91
|
+
focused.maximize();
|
|
92
|
+
}
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
if (key === "arrowdown" && focused) {
|
|
96
|
+
e.preventDefault();
|
|
97
|
+
if (focused.state.maximized) {
|
|
98
|
+
focused.unmaximize();
|
|
99
|
+
} else {
|
|
100
|
+
focused.minimize();
|
|
101
|
+
}
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
if (key === "w" && focused && !e.shiftKey) {
|
|
105
|
+
e.preventDefault();
|
|
106
|
+
this.windowManager.closeWindow(focused.id);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
cycleWindowFocus(direction) {
|
|
112
|
+
const activeWindows = Array.from(this.windowManager.getSnapshot()).filter((w) => w.active);
|
|
113
|
+
if (activeWindows.length <= 1) return;
|
|
114
|
+
const focusedId = this.windowManager.focusedWindow?.id;
|
|
115
|
+
const currentIndex = activeWindows.findIndex((w) => w.id === focusedId);
|
|
116
|
+
let nextIndex = 0;
|
|
117
|
+
if (direction === "forward") {
|
|
118
|
+
nextIndex = (currentIndex + 1) % activeWindows.length;
|
|
119
|
+
} else {
|
|
120
|
+
nextIndex = (currentIndex - 1 + activeWindows.length) % activeWindows.length;
|
|
121
|
+
}
|
|
122
|
+
const nextWin = activeWindows[nextIndex];
|
|
123
|
+
if (nextWin) {
|
|
124
|
+
this.windowManager.focusWindow(nextWin.id);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
class DesktopCommands {
|
|
130
|
+
commands = /* @__PURE__ */ new Map();
|
|
131
|
+
snapshotCache = Object.freeze([]);
|
|
132
|
+
subscribers = /* @__PURE__ */ new Set();
|
|
133
|
+
hooks;
|
|
134
|
+
ipc;
|
|
135
|
+
constructor(options) {
|
|
136
|
+
this.hooks = options?.hooks ?? globalDesktopHooks;
|
|
137
|
+
this.ipc = options?.ipc ?? globalIPCBus;
|
|
138
|
+
}
|
|
139
|
+
getSnapshot() {
|
|
140
|
+
return this.snapshotCache;
|
|
141
|
+
}
|
|
142
|
+
subscribe(callback) {
|
|
143
|
+
this.subscribers.add(callback);
|
|
144
|
+
callback(this.getSnapshot());
|
|
145
|
+
return () => {
|
|
146
|
+
this.subscribers.delete(callback);
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
notify() {
|
|
150
|
+
this.snapshotCache = Object.freeze(
|
|
151
|
+
Array.from(this.commands.values()).map(({ handler: _h, ...meta }) => Object.freeze({ ...meta }))
|
|
152
|
+
);
|
|
153
|
+
const snapshot = this.getSnapshot();
|
|
154
|
+
for (const sub of this.subscribers) {
|
|
155
|
+
try {
|
|
156
|
+
sub(snapshot);
|
|
157
|
+
} catch {
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
register(command, handler) {
|
|
162
|
+
this.commands.set(command.name, {
|
|
163
|
+
...command,
|
|
164
|
+
handler
|
|
165
|
+
});
|
|
166
|
+
this.notify();
|
|
167
|
+
return () => {
|
|
168
|
+
this.unregister(command.name);
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
unregister(name) {
|
|
172
|
+
const deleted = this.commands.delete(name);
|
|
173
|
+
if (deleted) {
|
|
174
|
+
this.notify();
|
|
175
|
+
}
|
|
176
|
+
return deleted;
|
|
177
|
+
}
|
|
178
|
+
has(name) {
|
|
179
|
+
return this.commands.has(name);
|
|
180
|
+
}
|
|
181
|
+
getCommands() {
|
|
182
|
+
return this.getSnapshot();
|
|
183
|
+
}
|
|
184
|
+
async exec(input) {
|
|
185
|
+
const { name, args } = parseCommandLine(input);
|
|
186
|
+
if (!name) return void 0;
|
|
187
|
+
const execCtx = {
|
|
188
|
+
input,
|
|
189
|
+
commandName: name,
|
|
190
|
+
args,
|
|
191
|
+
cancel: false,
|
|
192
|
+
overrideOutput: void 0
|
|
193
|
+
};
|
|
194
|
+
await this.hooks.callHook("command:before-exec", execCtx);
|
|
195
|
+
if (execCtx.cancel) {
|
|
196
|
+
return execCtx.overrideOutput ?? {
|
|
197
|
+
message: `Command "${name}" execution cancelled by policy.`,
|
|
198
|
+
isError: true
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
const registered = this.commands.get(name);
|
|
202
|
+
if (!registered) {
|
|
203
|
+
const notFoundOutput = {
|
|
204
|
+
message: `${name}: command not found`,
|
|
205
|
+
isError: true
|
|
206
|
+
};
|
|
207
|
+
await this.hooks.callHook("command:after-exec", {
|
|
208
|
+
input,
|
|
209
|
+
commandName: name,
|
|
210
|
+
output: notFoundOutput
|
|
211
|
+
});
|
|
212
|
+
return notFoundOutput;
|
|
213
|
+
}
|
|
214
|
+
try {
|
|
215
|
+
const result = await registered.handler(args, input);
|
|
216
|
+
const output = typeof result === "string" ? { message: result, isError: false } : result;
|
|
217
|
+
this.ipc.emit("command:executed", { command: name, args }, { source: "commands" });
|
|
218
|
+
await this.hooks.callHook("command:after-exec", {
|
|
219
|
+
input,
|
|
220
|
+
commandName: name,
|
|
221
|
+
output
|
|
222
|
+
});
|
|
223
|
+
return output;
|
|
224
|
+
} catch (err) {
|
|
225
|
+
const errorOutput = {
|
|
226
|
+
message: err?.message || String(err),
|
|
227
|
+
isError: true
|
|
228
|
+
};
|
|
229
|
+
await this.hooks.callHook("command:after-exec", {
|
|
230
|
+
input,
|
|
231
|
+
commandName: name,
|
|
232
|
+
output: errorOutput
|
|
233
|
+
});
|
|
234
|
+
return errorOutput;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
export { DesktopCommands as D, DesktopKeybindings as a, parseCommandLine as b, formatDuration as f, padEnd as p, shellEscape as s };
|