@wong2kim/wmux 1.0.0 → 1.0.1

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.
Files changed (110) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +209 -157
  3. package/dist/cli/cli/client.js +1 -1
  4. package/dist/cli/cli/commands/browser.js +19 -19
  5. package/dist/cli/cli/index.js +58 -58
  6. package/dist/cli/shared/constants.js +17 -4
  7. package/dist/mcp/shared/constants.js +17 -4
  8. package/package.json +96 -84
  9. package/assets/icon.ico +0 -0
  10. package/assets/icon.svg +0 -6
  11. package/forge.config.ts +0 -61
  12. package/index.html +0 -12
  13. package/postcss.config.js +0 -6
  14. package/src/cli/client.ts +0 -76
  15. package/src/cli/commands/browser.ts +0 -128
  16. package/src/cli/commands/input.ts +0 -72
  17. package/src/cli/commands/notify.ts +0 -29
  18. package/src/cli/commands/pane.ts +0 -90
  19. package/src/cli/commands/surface.ts +0 -102
  20. package/src/cli/commands/system.ts +0 -95
  21. package/src/cli/commands/workspace.ts +0 -116
  22. package/src/cli/index.ts +0 -145
  23. package/src/cli/utils.ts +0 -44
  24. package/src/main/index.ts +0 -86
  25. package/src/main/ipc/handlers/clipboard.handler.ts +0 -20
  26. package/src/main/ipc/handlers/metadata.handler.ts +0 -56
  27. package/src/main/ipc/handlers/pty.handler.ts +0 -69
  28. package/src/main/ipc/handlers/session.handler.ts +0 -17
  29. package/src/main/ipc/handlers/shell.handler.ts +0 -11
  30. package/src/main/ipc/registerHandlers.ts +0 -31
  31. package/src/main/mcp/McpRegistrar.ts +0 -156
  32. package/src/main/metadata/MetadataCollector.ts +0 -58
  33. package/src/main/notification/ToastManager.ts +0 -32
  34. package/src/main/pipe/PipeServer.ts +0 -190
  35. package/src/main/pipe/RpcRouter.ts +0 -46
  36. package/src/main/pipe/handlers/_bridge.ts +0 -40
  37. package/src/main/pipe/handlers/browser.rpc.ts +0 -132
  38. package/src/main/pipe/handlers/input.rpc.ts +0 -120
  39. package/src/main/pipe/handlers/meta.rpc.ts +0 -59
  40. package/src/main/pipe/handlers/notify.rpc.ts +0 -53
  41. package/src/main/pipe/handlers/pane.rpc.ts +0 -39
  42. package/src/main/pipe/handlers/surface.rpc.ts +0 -43
  43. package/src/main/pipe/handlers/system.rpc.ts +0 -36
  44. package/src/main/pipe/handlers/workspace.rpc.ts +0 -52
  45. package/src/main/pty/AgentDetector.ts +0 -247
  46. package/src/main/pty/OscParser.ts +0 -81
  47. package/src/main/pty/PTYBridge.ts +0 -88
  48. package/src/main/pty/PTYManager.ts +0 -104
  49. package/src/main/pty/ShellDetector.ts +0 -63
  50. package/src/main/session/SessionManager.ts +0 -53
  51. package/src/main/updater/AutoUpdater.ts +0 -132
  52. package/src/main/window/createWindow.ts +0 -71
  53. package/src/mcp/README.md +0 -56
  54. package/src/mcp/index.ts +0 -153
  55. package/src/mcp/wmux-client.ts +0 -127
  56. package/src/preload/index.ts +0 -111
  57. package/src/preload/preload.ts +0 -108
  58. package/src/renderer/App.tsx +0 -5
  59. package/src/renderer/components/Browser/BrowserPanel.tsx +0 -219
  60. package/src/renderer/components/Browser/BrowserToolbar.tsx +0 -253
  61. package/src/renderer/components/Company/ApprovalDialog.tsx +0 -3
  62. package/src/renderer/components/Company/CompanyView.tsx +0 -7
  63. package/src/renderer/components/Company/MessageFeedPanel.tsx +0 -3
  64. package/src/renderer/components/Layout/AppLayout.tsx +0 -234
  65. package/src/renderer/components/Notification/NotificationPanel.tsx +0 -129
  66. package/src/renderer/components/Palette/CommandPalette.tsx +0 -409
  67. package/src/renderer/components/Palette/PaletteItem.tsx +0 -55
  68. package/src/renderer/components/Pane/Pane.tsx +0 -122
  69. package/src/renderer/components/Pane/PaneContainer.tsx +0 -41
  70. package/src/renderer/components/Pane/SurfaceTabs.tsx +0 -46
  71. package/src/renderer/components/Settings/SettingsPanel.tsx +0 -886
  72. package/src/renderer/components/Sidebar/MiniSidebar.tsx +0 -67
  73. package/src/renderer/components/Sidebar/Sidebar.tsx +0 -84
  74. package/src/renderer/components/Sidebar/WorkspaceItem.tsx +0 -241
  75. package/src/renderer/components/StatusBar/StatusBar.tsx +0 -93
  76. package/src/renderer/components/Terminal/SearchBar.tsx +0 -126
  77. package/src/renderer/components/Terminal/Terminal.tsx +0 -102
  78. package/src/renderer/components/Terminal/ViCopyMode.tsx +0 -104
  79. package/src/renderer/hooks/useKeyboard.ts +0 -310
  80. package/src/renderer/hooks/useNotificationListener.ts +0 -80
  81. package/src/renderer/hooks/useNotificationSound.ts +0 -75
  82. package/src/renderer/hooks/useRpcBridge.ts +0 -451
  83. package/src/renderer/hooks/useT.ts +0 -11
  84. package/src/renderer/hooks/useTerminal.ts +0 -349
  85. package/src/renderer/hooks/useViCopyMode.ts +0 -320
  86. package/src/renderer/i18n/index.ts +0 -69
  87. package/src/renderer/i18n/locales/en.ts +0 -157
  88. package/src/renderer/i18n/locales/ja.ts +0 -155
  89. package/src/renderer/i18n/locales/ko.ts +0 -155
  90. package/src/renderer/i18n/locales/zh.ts +0 -155
  91. package/src/renderer/index.tsx +0 -6
  92. package/src/renderer/stores/index.ts +0 -19
  93. package/src/renderer/stores/slices/notificationSlice.ts +0 -56
  94. package/src/renderer/stores/slices/paneSlice.ts +0 -141
  95. package/src/renderer/stores/slices/surfaceSlice.ts +0 -122
  96. package/src/renderer/stores/slices/uiSlice.ts +0 -247
  97. package/src/renderer/stores/slices/workspaceSlice.ts +0 -120
  98. package/src/renderer/styles/globals.css +0 -150
  99. package/src/renderer/themes.ts +0 -99
  100. package/src/shared/constants.ts +0 -53
  101. package/src/shared/electron.d.ts +0 -11
  102. package/src/shared/rpc.ts +0 -71
  103. package/src/shared/types.ts +0 -176
  104. package/tailwind.config.js +0 -11
  105. package/tsconfig.cli.json +0 -24
  106. package/tsconfig.json +0 -21
  107. package/tsconfig.mcp.json +0 -25
  108. package/vite.main.config.ts +0 -14
  109. package/vite.preload.config.ts +0 -9
  110. package/vite.renderer.config.ts +0 -6
@@ -1,40 +0,0 @@
1
- import { ipcMain, type BrowserWindow } from 'electron';
2
- import { randomUUID } from 'node:crypto';
3
- import { IPC } from '../../../shared/constants';
4
-
5
- type GetWindow = () => BrowserWindow | null;
6
-
7
- const TIMEOUT_MS = 5000;
8
-
9
- /**
10
- * Sends a RPC command to the renderer via IPC and waits for the response.
11
- * Uses a unique requestId per call so concurrent requests don't collide.
12
- */
13
- export function sendToRenderer(
14
- getWindow: GetWindow,
15
- method: string,
16
- params: Record<string, unknown> = {},
17
- ): Promise<unknown> {
18
- return new Promise((resolve, reject) => {
19
- const win = getWindow();
20
- if (!win || win.isDestroyed()) {
21
- reject(new Error('BrowserWindow is not available'));
22
- return;
23
- }
24
-
25
- const requestId = `rpc-${randomUUID()}`;
26
- const responseChannel = `${IPC.RPC_RESPONSE}:${requestId}`;
27
-
28
- const timer = setTimeout(() => {
29
- ipcMain.removeAllListeners(responseChannel);
30
- reject(new Error(`RPC timeout: ${method} (${TIMEOUT_MS}ms)`));
31
- }, TIMEOUT_MS);
32
-
33
- ipcMain.once(responseChannel, (_event, result: unknown) => {
34
- clearTimeout(timer);
35
- resolve(result);
36
- });
37
-
38
- win.webContents.send(IPC.RPC_COMMAND, requestId, method, params);
39
- });
40
- }
@@ -1,132 +0,0 @@
1
- import type { BrowserWindow } from 'electron';
2
- import type { RpcRouter } from '../RpcRouter';
3
- import { sendToRenderer } from './_bridge';
4
-
5
- type GetWindow = () => BrowserWindow | null;
6
-
7
- /**
8
- * Registers browser.* RPC handlers.
9
- *
10
- * All commands are delegated to the renderer process via IPC where the active
11
- * browser Surface's <webview> element executes the requested operation.
12
- */
13
- export function registerBrowserRpc(router: RpcRouter, getWindow: GetWindow): void {
14
- /**
15
- * browser.open
16
- * Opens a new browser surface in the active pane.
17
- * params: { url?: string }
18
- */
19
- router.register('browser.open', (params) => {
20
- const url = typeof params['url'] === 'string' ? params['url'] : undefined;
21
- return sendToRenderer(getWindow, 'browser.open', {
22
- ...(url && { url }),
23
- });
24
- });
25
-
26
- /**
27
- * browser.snapshot
28
- * Returns the full outer HTML of the current page as a string.
29
- * params: {}
30
- */
31
- router.register('browser.snapshot', (params) => {
32
- const surfaceId = typeof params['surfaceId'] === 'string' ? params['surfaceId'] : undefined;
33
- return sendToRenderer(getWindow, 'browser.snapshot', {
34
- ...(surfaceId && { surfaceId }),
35
- });
36
- });
37
-
38
- /**
39
- * browser.click
40
- * Clicks the first element matching the given CSS selector.
41
- * params: { selector: string }
42
- */
43
- router.register('browser.click', (params) => {
44
- if (typeof params['selector'] !== 'string' || params['selector'].length === 0) {
45
- throw new Error('browser.click: missing required param "selector"');
46
- }
47
- const surfaceId = typeof params['surfaceId'] === 'string' ? params['surfaceId'] : undefined;
48
- return sendToRenderer(getWindow, 'browser.click', {
49
- selector: params['selector'],
50
- ...(surfaceId && { surfaceId }),
51
- });
52
- });
53
-
54
- /**
55
- * browser.fill
56
- * Sets the value of an input element matching the given CSS selector.
57
- * params: { selector: string; text: string }
58
- */
59
- router.register('browser.fill', (params) => {
60
- if (typeof params['selector'] !== 'string' || params['selector'].length === 0) {
61
- throw new Error('browser.fill: missing required param "selector"');
62
- }
63
- if (typeof params['text'] !== 'string') {
64
- throw new Error('browser.fill: missing required param "text"');
65
- }
66
- const surfaceId = typeof params['surfaceId'] === 'string' ? params['surfaceId'] : undefined;
67
- return sendToRenderer(getWindow, 'browser.fill', {
68
- selector: params['selector'],
69
- text: params['text'],
70
- ...(surfaceId && { surfaceId }),
71
- });
72
- });
73
-
74
- /**
75
- * browser.eval
76
- * Evaluates arbitrary JavaScript in the context of the current page.
77
- * params: { code: string }
78
- */
79
- router.register('browser.eval', (params) => {
80
- if (typeof params['code'] !== 'string' || params['code'].length === 0) {
81
- throw new Error('browser.eval: missing required param "code"');
82
- }
83
- // Security: block patterns that could escape webview sandbox
84
- const code = params['code'];
85
- const dangerousPatterns = [
86
- /\brequire\s*\(/i,
87
- /\bprocess\s*\./i,
88
- /\b__dirname\b/i,
89
- /\b__filename\b/i,
90
- /\bchild_process\b/i,
91
- /\bglobal\s*\.\s*process\b/i,
92
- /\belectron\b/i,
93
- ];
94
- for (const pat of dangerousPatterns) {
95
- if (pat.test(code)) {
96
- throw new Error('browser.eval: code contains blocked pattern');
97
- }
98
- }
99
- const surfaceId = typeof params['surfaceId'] === 'string' ? params['surfaceId'] : undefined;
100
- return sendToRenderer(getWindow, 'browser.eval', {
101
- code,
102
- ...(surfaceId && { surfaceId }),
103
- });
104
- });
105
-
106
- /**
107
- * browser.navigate
108
- * Navigates the active browser Surface to the given URL.
109
- * params: { url: string }
110
- */
111
- router.register('browser.navigate', (params) => {
112
- if (typeof params['url'] !== 'string' || params['url'].length === 0) {
113
- throw new Error('browser.navigate: missing required param "url"');
114
- }
115
- // Security: block dangerous URL schemes
116
- const url = params['url'];
117
- const normalizedUrl = url.trim().toLowerCase();
118
- if (
119
- normalizedUrl.startsWith('javascript:') ||
120
- normalizedUrl.startsWith('data:') ||
121
- normalizedUrl.startsWith('vbscript:') ||
122
- normalizedUrl.startsWith('file:')
123
- ) {
124
- throw new Error(`browser.navigate: blocked URL scheme`);
125
- }
126
- const surfaceId = typeof params['surfaceId'] === 'string' ? params['surfaceId'] : undefined;
127
- return sendToRenderer(getWindow, 'browser.navigate', {
128
- url,
129
- ...(surfaceId && { surfaceId }),
130
- });
131
- });
132
- }
@@ -1,120 +0,0 @@
1
- import type { BrowserWindow } from 'electron';
2
- import type { RpcRouter } from '../RpcRouter';
3
- import type { PTYManager } from '../../pty/PTYManager';
4
- import { sendToRenderer } from './_bridge';
5
-
6
- type GetWindow = () => BrowserWindow | null;
7
-
8
- /**
9
- * Key sequence mapping table for input.sendKey
10
- */
11
- const KEY_MAP: Readonly<Record<string, string>> = {
12
- enter: '\r',
13
- tab: '\t',
14
- 'ctrl+c': '\x03',
15
- 'ctrl+d': '\x04',
16
- 'ctrl+z': '\x1a',
17
- 'ctrl+l': '\x0c',
18
- escape: '\x1b',
19
- up: '\x1b[A',
20
- down: '\x1b[B',
21
- right: '\x1b[C',
22
- left: '\x1b[D',
23
- } as const;
24
-
25
- /**
26
- * Resolves the active ptyId from the renderer when none is provided.
27
- * Asks the renderer for the currently focused surface's ptyId.
28
- */
29
- async function resolveActivePtyId(getWindow: GetWindow): Promise<string> {
30
- const result = await sendToRenderer(getWindow, 'input.readScreen');
31
- // renderer returns { ptyId: string, ... } for the active surface
32
- if (
33
- result !== null &&
34
- typeof result === 'object' &&
35
- 'ptyId' in result &&
36
- typeof (result as Record<string, unknown>)['ptyId'] === 'string'
37
- ) {
38
- return (result as Record<string, string>)['ptyId'];
39
- }
40
- throw new Error('input: could not resolve active ptyId from renderer');
41
- }
42
-
43
- export function registerInputRpc(
44
- router: RpcRouter,
45
- ptyManager: PTYManager,
46
- getWindow: GetWindow,
47
- ): void {
48
- /**
49
- * input.send — writes text to a PTY session.
50
- * params: { text: string, ptyId?: string }
51
- * If ptyId is omitted the renderer is queried for the active surface's ptyId.
52
- */
53
- router.register('input.send', async (params) => {
54
- if (typeof params['text'] !== 'string') {
55
- throw new Error('input.send: missing required param "text"');
56
- }
57
-
58
- const text = params['text'];
59
- let ptyId: string;
60
-
61
- if (typeof params['ptyId'] === 'string' && params['ptyId'].length > 0) {
62
- ptyId = params['ptyId'];
63
- } else {
64
- ptyId = await resolveActivePtyId(getWindow);
65
- }
66
-
67
- const instance = ptyManager.get(ptyId);
68
- if (!instance) {
69
- throw new Error(`input.send: PTY not found — id="${ptyId}"`);
70
- }
71
-
72
- ptyManager.write(ptyId, text);
73
- return { ok: true, ptyId };
74
- });
75
-
76
- /**
77
- * input.sendKey — maps a named key to an ANSI sequence and writes it.
78
- * params: { key: string, ptyId?: string }
79
- * Supported keys: enter, tab, ctrl+c, ctrl+d, ctrl+z, ctrl+l,
80
- * escape, up, down, right, left
81
- */
82
- router.register('input.sendKey', async (params) => {
83
- if (typeof params['key'] !== 'string') {
84
- throw new Error('input.sendKey: missing required param "key"');
85
- }
86
-
87
- const key = params['key'].toLowerCase();
88
- const sequence = KEY_MAP[key];
89
- if (sequence === undefined) {
90
- throw new Error(
91
- `input.sendKey: unknown key "${params['key']}". ` +
92
- `Supported: ${Object.keys(KEY_MAP).join(', ')}`,
93
- );
94
- }
95
-
96
- let ptyId: string;
97
- if (typeof params['ptyId'] === 'string' && params['ptyId'].length > 0) {
98
- ptyId = params['ptyId'];
99
- } else {
100
- ptyId = await resolveActivePtyId(getWindow);
101
- }
102
-
103
- const instance = ptyManager.get(ptyId);
104
- if (!instance) {
105
- throw new Error(`input.sendKey: PTY not found — id="${ptyId}"`);
106
- }
107
-
108
- ptyManager.write(ptyId, sequence);
109
- return { ok: true, ptyId, key, sequence };
110
- });
111
-
112
- /**
113
- * input.readScreen — delegates to the renderer to capture the current
114
- * terminal viewport text of the active surface.
115
- * Returns { ptyId: string, text: string }
116
- */
117
- router.register('input.readScreen', (_params) =>
118
- sendToRenderer(getWindow, 'input.readScreen'),
119
- );
120
- }
@@ -1,59 +0,0 @@
1
- import type { BrowserWindow } from 'electron';
2
- import type { RpcRouter } from '../RpcRouter';
3
- import { IPC } from '../../../shared/constants';
4
-
5
- type GetWindow = () => BrowserWindow | null;
6
-
7
- /**
8
- * Sub-channel names embedded in the METADATA_UPDATE IPC message.
9
- * The renderer's useNotificationListener (or a dedicated metadata listener)
10
- * discriminates on the `kind` field.
11
- */
12
- type MetaUpdateKind = 'status' | 'progress';
13
-
14
- interface MetaStatusPayload {
15
- kind: 'status';
16
- text: string;
17
- }
18
-
19
- interface MetaProgressPayload {
20
- kind: 'progress';
21
- value: number;
22
- }
23
-
24
- type MetaPayload = MetaStatusPayload | MetaProgressPayload;
25
-
26
- function sendMeta(getWindow: GetWindow, payload: MetaPayload): Promise<{ ok: boolean }> {
27
- const win = getWindow();
28
- if (!win || win.isDestroyed()) {
29
- return Promise.reject(new Error('meta: BrowserWindow is not available'));
30
- }
31
- win.webContents.send(IPC.METADATA_UPDATE, payload);
32
- return Promise.resolve({ ok: true });
33
- }
34
-
35
- export function registerMetaRpc(router: RpcRouter, getWindow: GetWindow): void {
36
- /**
37
- * meta.setStatus — sets an arbitrary status text string in the renderer.
38
- * params: { text: string }
39
- */
40
- router.register('meta.setStatus', (params) => {
41
- if (typeof params['text'] !== 'string') {
42
- throw new Error('meta.setStatus: missing required param "text"');
43
- }
44
- return sendMeta(getWindow, { kind: 'status', text: params['text'] });
45
- });
46
-
47
- /**
48
- * meta.setProgress — sets a progress value (0–100) in the renderer.
49
- * params: { value: number }
50
- * Values outside 0–100 are clamped.
51
- */
52
- router.register('meta.setProgress', (params) => {
53
- if (typeof params['value'] !== 'number') {
54
- throw new Error('meta.setProgress: missing required param "value" (number)');
55
- }
56
- const value = Math.min(100, Math.max(0, params['value']));
57
- return sendMeta(getWindow, { kind: 'progress', value });
58
- });
59
- }
@@ -1,53 +0,0 @@
1
- import type { BrowserWindow } from 'electron';
2
- import type { RpcRouter } from '../RpcRouter';
3
- import type { NotificationType } from '../../../shared/types';
4
- import { IPC } from '../../../shared/constants';
5
- import { ToastManager } from '../../notification/ToastManager';
6
-
7
- type GetWindow = () => BrowserWindow | null;
8
-
9
- const VALID_TYPES = new Set<NotificationType>(['info', 'warning', 'error', 'agent']);
10
-
11
- function isNotificationType(value: unknown): value is NotificationType {
12
- return typeof value === 'string' && VALID_TYPES.has(value as NotificationType);
13
- }
14
-
15
- export const toastManager = new ToastManager();
16
-
17
- export function registerNotifyRpc(router: RpcRouter, getWindow: GetWindow): void {
18
- /**
19
- * notify — delivers a notification to the renderer UI and, when the app is
20
- * not focused, also shows a Windows Toast notification.
21
- *
22
- * params: {
23
- * title: string
24
- * body: string
25
- * type?: 'info' | 'warning' | 'error' | 'agent' (default: 'info')
26
- * }
27
- */
28
- router.register('notify', (params) => {
29
- if (typeof params['title'] !== 'string' || params['title'].length === 0) {
30
- throw new Error('notify: missing required param "title"');
31
- }
32
- if (typeof params['body'] !== 'string') {
33
- throw new Error('notify: missing required param "body"');
34
- }
35
-
36
- const title = params['title'];
37
- const body = params['body'];
38
- const type: NotificationType = isNotificationType(params['type'])
39
- ? params['type']
40
- : 'info';
41
-
42
- const win = getWindow();
43
- if (win && !win.isDestroyed()) {
44
- // Push notification to the renderer notification store
45
- win.webContents.send(IPC.NOTIFICATION, { title, body, type });
46
- }
47
-
48
- // Show OS-level toast (only when window is not focused)
49
- toastManager.show(title, body);
50
-
51
- return Promise.resolve({ delivered: true, type });
52
- });
53
- }
@@ -1,39 +0,0 @@
1
- import type { BrowserWindow } from 'electron';
2
- import type { RpcRouter } from '../RpcRouter';
3
- import { sendToRenderer } from './_bridge';
4
-
5
- type GetWindow = () => BrowserWindow | null;
6
-
7
- export function registerPaneRpc(router: RpcRouter, getWindow: GetWindow): void {
8
- /**
9
- * pane.list — returns all panes (leaf nodes) of the current workspace
10
- */
11
- router.register('pane.list', (_params) =>
12
- sendToRenderer(getWindow, 'pane.list'),
13
- );
14
-
15
- /**
16
- * pane.focus — focuses a specific pane
17
- * params: { id: string }
18
- */
19
- router.register('pane.focus', (params) => {
20
- if (typeof params['id'] !== 'string') {
21
- return Promise.reject(new Error('pane.focus: missing required param "id"'));
22
- }
23
- return sendToRenderer(getWindow, 'pane.focus', { id: params['id'] });
24
- });
25
-
26
- /**
27
- * pane.split — splits the active pane
28
- * params: { direction: 'horizontal' | 'vertical' }
29
- */
30
- router.register('pane.split', (params) => {
31
- const direction = params['direction'];
32
- if (direction !== 'horizontal' && direction !== 'vertical') {
33
- return Promise.reject(
34
- new Error('pane.split: "direction" must be "horizontal" or "vertical"'),
35
- );
36
- }
37
- return sendToRenderer(getWindow, 'pane.split', { direction });
38
- });
39
- }
@@ -1,43 +0,0 @@
1
- import type { BrowserWindow } from 'electron';
2
- import type { RpcRouter } from '../RpcRouter';
3
- import { sendToRenderer } from './_bridge';
4
-
5
- type GetWindow = () => BrowserWindow | null;
6
-
7
- export function registerSurfaceRpc(router: RpcRouter, getWindow: GetWindow): void {
8
- /**
9
- * surface.list — returns surfaces of the current workspace's active pane
10
- */
11
- router.register('surface.list', (_params) =>
12
- sendToRenderer(getWindow, 'surface.list'),
13
- );
14
-
15
- /**
16
- * surface.new — creates a new surface in the active pane
17
- */
18
- router.register('surface.new', (_params) =>
19
- sendToRenderer(getWindow, 'surface.new'),
20
- );
21
-
22
- /**
23
- * surface.focus — focuses a specific surface
24
- * params: { id: string }
25
- */
26
- router.register('surface.focus', (params) => {
27
- if (typeof params['id'] !== 'string') {
28
- return Promise.reject(new Error('surface.focus: missing required param "id"'));
29
- }
30
- return sendToRenderer(getWindow, 'surface.focus', { id: params['id'] });
31
- });
32
-
33
- /**
34
- * surface.close — closes a specific surface
35
- * params: { id: string }
36
- */
37
- router.register('surface.close', (params) => {
38
- if (typeof params['id'] !== 'string') {
39
- return Promise.reject(new Error('surface.close: missing required param "id"'));
40
- }
41
- return sendToRenderer(getWindow, 'surface.close', { id: params['id'] });
42
- });
43
- }
@@ -1,36 +0,0 @@
1
- import { app } from 'electron';
2
- import type { RpcRouter } from '../RpcRouter';
3
- import { ALL_RPC_METHODS } from '../../../shared/rpc';
4
-
5
- /**
6
- * Shape returned by system.identify.
7
- */
8
- interface SystemIdentity {
9
- app: string;
10
- version: string;
11
- platform: NodeJS.Platform;
12
- electronVersion: string;
13
- }
14
-
15
- export function registerSystemRpc(router: RpcRouter): void {
16
- /**
17
- * system.identify — returns static information about the running WinMux instance.
18
- * No renderer round-trip needed; answered entirely from Main.
19
- */
20
- router.register('system.identify', (_params): Promise<SystemIdentity> => {
21
- return Promise.resolve({
22
- app: 'wmux',
23
- version: app.getVersion(),
24
- platform: process.platform,
25
- electronVersion: process.versions.electron ?? 'unknown',
26
- });
27
- });
28
-
29
- /**
30
- * system.capabilities — returns the full list of registered RPC method names.
31
- * Sourced from the single-source-of-truth array in shared/rpc.ts.
32
- */
33
- router.register('system.capabilities', (_params) => {
34
- return Promise.resolve({ methods: ALL_RPC_METHODS });
35
- });
36
- }
@@ -1,52 +0,0 @@
1
- import type { BrowserWindow } from 'electron';
2
- import type { RpcRouter } from '../RpcRouter';
3
- import { sendToRenderer } from './_bridge';
4
-
5
- type GetWindow = () => BrowserWindow | null;
6
-
7
- export function registerWorkspaceRpc(router: RpcRouter, getWindow: GetWindow): void {
8
- /**
9
- * workspace.list — returns all workspaces as {id, name}[]
10
- */
11
- router.register('workspace.list', (_params) =>
12
- sendToRenderer(getWindow, 'workspace.list'),
13
- );
14
-
15
- /**
16
- * workspace.new — creates a new workspace
17
- * params: { name?: string }
18
- */
19
- router.register('workspace.new', (params) => {
20
- const name = typeof params['name'] === 'string' ? params['name'] : undefined;
21
- return sendToRenderer(getWindow, 'workspace.new', name !== undefined ? { name } : {});
22
- });
23
-
24
- /**
25
- * workspace.focus — sets the active workspace
26
- * params: { id: string }
27
- */
28
- router.register('workspace.focus', (params) => {
29
- if (typeof params['id'] !== 'string') {
30
- return Promise.reject(new Error('workspace.focus: missing required param "id"'));
31
- }
32
- return sendToRenderer(getWindow, 'workspace.focus', { id: params['id'] });
33
- });
34
-
35
- /**
36
- * workspace.close — removes a workspace
37
- * params: { id: string }
38
- */
39
- router.register('workspace.close', (params) => {
40
- if (typeof params['id'] !== 'string') {
41
- return Promise.reject(new Error('workspace.close: missing required param "id"'));
42
- }
43
- return sendToRenderer(getWindow, 'workspace.close', { id: params['id'] });
44
- });
45
-
46
- /**
47
- * workspace.current — returns the currently active workspace {id, name}
48
- */
49
- router.register('workspace.current', (_params) =>
50
- sendToRenderer(getWindow, 'workspace.current'),
51
- );
52
- }