@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.
- package/LICENSE +21 -0
- package/README.md +209 -157
- package/dist/cli/cli/client.js +1 -1
- package/dist/cli/cli/commands/browser.js +19 -19
- package/dist/cli/cli/index.js +58 -58
- package/dist/cli/shared/constants.js +17 -4
- package/dist/mcp/shared/constants.js +17 -4
- package/package.json +96 -84
- package/assets/icon.ico +0 -0
- package/assets/icon.svg +0 -6
- package/forge.config.ts +0 -61
- package/index.html +0 -12
- package/postcss.config.js +0 -6
- package/src/cli/client.ts +0 -76
- package/src/cli/commands/browser.ts +0 -128
- package/src/cli/commands/input.ts +0 -72
- package/src/cli/commands/notify.ts +0 -29
- package/src/cli/commands/pane.ts +0 -90
- package/src/cli/commands/surface.ts +0 -102
- package/src/cli/commands/system.ts +0 -95
- package/src/cli/commands/workspace.ts +0 -116
- package/src/cli/index.ts +0 -145
- package/src/cli/utils.ts +0 -44
- package/src/main/index.ts +0 -86
- package/src/main/ipc/handlers/clipboard.handler.ts +0 -20
- package/src/main/ipc/handlers/metadata.handler.ts +0 -56
- package/src/main/ipc/handlers/pty.handler.ts +0 -69
- package/src/main/ipc/handlers/session.handler.ts +0 -17
- package/src/main/ipc/handlers/shell.handler.ts +0 -11
- package/src/main/ipc/registerHandlers.ts +0 -31
- package/src/main/mcp/McpRegistrar.ts +0 -156
- package/src/main/metadata/MetadataCollector.ts +0 -58
- package/src/main/notification/ToastManager.ts +0 -32
- package/src/main/pipe/PipeServer.ts +0 -190
- package/src/main/pipe/RpcRouter.ts +0 -46
- package/src/main/pipe/handlers/_bridge.ts +0 -40
- package/src/main/pipe/handlers/browser.rpc.ts +0 -132
- package/src/main/pipe/handlers/input.rpc.ts +0 -120
- package/src/main/pipe/handlers/meta.rpc.ts +0 -59
- package/src/main/pipe/handlers/notify.rpc.ts +0 -53
- package/src/main/pipe/handlers/pane.rpc.ts +0 -39
- package/src/main/pipe/handlers/surface.rpc.ts +0 -43
- package/src/main/pipe/handlers/system.rpc.ts +0 -36
- package/src/main/pipe/handlers/workspace.rpc.ts +0 -52
- package/src/main/pty/AgentDetector.ts +0 -247
- package/src/main/pty/OscParser.ts +0 -81
- package/src/main/pty/PTYBridge.ts +0 -88
- package/src/main/pty/PTYManager.ts +0 -104
- package/src/main/pty/ShellDetector.ts +0 -63
- package/src/main/session/SessionManager.ts +0 -53
- package/src/main/updater/AutoUpdater.ts +0 -132
- package/src/main/window/createWindow.ts +0 -71
- package/src/mcp/README.md +0 -56
- package/src/mcp/index.ts +0 -153
- package/src/mcp/wmux-client.ts +0 -127
- package/src/preload/index.ts +0 -111
- package/src/preload/preload.ts +0 -108
- package/src/renderer/App.tsx +0 -5
- package/src/renderer/components/Browser/BrowserPanel.tsx +0 -219
- package/src/renderer/components/Browser/BrowserToolbar.tsx +0 -253
- package/src/renderer/components/Company/ApprovalDialog.tsx +0 -3
- package/src/renderer/components/Company/CompanyView.tsx +0 -7
- package/src/renderer/components/Company/MessageFeedPanel.tsx +0 -3
- package/src/renderer/components/Layout/AppLayout.tsx +0 -234
- package/src/renderer/components/Notification/NotificationPanel.tsx +0 -129
- package/src/renderer/components/Palette/CommandPalette.tsx +0 -409
- package/src/renderer/components/Palette/PaletteItem.tsx +0 -55
- package/src/renderer/components/Pane/Pane.tsx +0 -122
- package/src/renderer/components/Pane/PaneContainer.tsx +0 -41
- package/src/renderer/components/Pane/SurfaceTabs.tsx +0 -46
- package/src/renderer/components/Settings/SettingsPanel.tsx +0 -886
- package/src/renderer/components/Sidebar/MiniSidebar.tsx +0 -67
- package/src/renderer/components/Sidebar/Sidebar.tsx +0 -84
- package/src/renderer/components/Sidebar/WorkspaceItem.tsx +0 -241
- package/src/renderer/components/StatusBar/StatusBar.tsx +0 -93
- package/src/renderer/components/Terminal/SearchBar.tsx +0 -126
- package/src/renderer/components/Terminal/Terminal.tsx +0 -102
- package/src/renderer/components/Terminal/ViCopyMode.tsx +0 -104
- package/src/renderer/hooks/useKeyboard.ts +0 -310
- package/src/renderer/hooks/useNotificationListener.ts +0 -80
- package/src/renderer/hooks/useNotificationSound.ts +0 -75
- package/src/renderer/hooks/useRpcBridge.ts +0 -451
- package/src/renderer/hooks/useT.ts +0 -11
- package/src/renderer/hooks/useTerminal.ts +0 -349
- package/src/renderer/hooks/useViCopyMode.ts +0 -320
- package/src/renderer/i18n/index.ts +0 -69
- package/src/renderer/i18n/locales/en.ts +0 -157
- package/src/renderer/i18n/locales/ja.ts +0 -155
- package/src/renderer/i18n/locales/ko.ts +0 -155
- package/src/renderer/i18n/locales/zh.ts +0 -155
- package/src/renderer/index.tsx +0 -6
- package/src/renderer/stores/index.ts +0 -19
- package/src/renderer/stores/slices/notificationSlice.ts +0 -56
- package/src/renderer/stores/slices/paneSlice.ts +0 -141
- package/src/renderer/stores/slices/surfaceSlice.ts +0 -122
- package/src/renderer/stores/slices/uiSlice.ts +0 -247
- package/src/renderer/stores/slices/workspaceSlice.ts +0 -120
- package/src/renderer/styles/globals.css +0 -150
- package/src/renderer/themes.ts +0 -99
- package/src/shared/constants.ts +0 -53
- package/src/shared/electron.d.ts +0 -11
- package/src/shared/rpc.ts +0 -71
- package/src/shared/types.ts +0 -176
- package/tailwind.config.js +0 -11
- package/tsconfig.cli.json +0 -24
- package/tsconfig.json +0 -21
- package/tsconfig.mcp.json +0 -25
- package/vite.main.config.ts +0 -14
- package/vite.preload.config.ts +0 -9
- package/vite.renderer.config.ts +0 -6
package/src/cli/commands/pane.ts
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import { sendRequest } from '../client';
|
|
2
|
-
import { printResult, printError, parseFlag } from '../utils';
|
|
3
|
-
import type { RpcResponse } from '../../shared/rpc';
|
|
4
|
-
|
|
5
|
-
interface PaneInfo {
|
|
6
|
-
id: string;
|
|
7
|
-
type: 'leaf' | 'branch';
|
|
8
|
-
direction?: string;
|
|
9
|
-
activeSurfaceId?: string;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
function formatPaneList(result: unknown): void {
|
|
13
|
-
const list = result as PaneInfo[];
|
|
14
|
-
if (!Array.isArray(list) || list.length === 0) {
|
|
15
|
-
console.log('No panes found.');
|
|
16
|
-
return;
|
|
17
|
-
}
|
|
18
|
-
const maxId = Math.max(...list.map((p) => p.id.length));
|
|
19
|
-
console.log('ID'.padEnd(maxId + 2) + 'TYPE'.padEnd(8) + 'DETAILS');
|
|
20
|
-
console.log('-'.repeat(maxId + 30));
|
|
21
|
-
for (const p of list) {
|
|
22
|
-
let details = '';
|
|
23
|
-
if (p.type === 'leaf' && p.activeSurfaceId) {
|
|
24
|
-
details = `active surface: ${p.activeSurfaceId}`;
|
|
25
|
-
} else if (p.type === 'branch' && p.direction) {
|
|
26
|
-
details = `direction: ${p.direction}`;
|
|
27
|
-
}
|
|
28
|
-
console.log(p.id.padEnd(maxId + 2) + p.type.padEnd(8) + details);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export async function handlePane(
|
|
33
|
-
cmd: string,
|
|
34
|
-
args: string[],
|
|
35
|
-
jsonMode: boolean
|
|
36
|
-
): Promise<void> {
|
|
37
|
-
let response: RpcResponse;
|
|
38
|
-
|
|
39
|
-
switch (cmd) {
|
|
40
|
-
case 'list-panes': {
|
|
41
|
-
response = await sendRequest('pane.list', {});
|
|
42
|
-
if (jsonMode) {
|
|
43
|
-
printResult(response);
|
|
44
|
-
} else {
|
|
45
|
-
if (!response.ok) { printError(response); return; }
|
|
46
|
-
formatPaneList(response.result);
|
|
47
|
-
}
|
|
48
|
-
break;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
case 'focus-pane': {
|
|
52
|
-
const id = args[0];
|
|
53
|
-
if (!id) {
|
|
54
|
-
console.error('Error: focus-pane requires <id>');
|
|
55
|
-
process.exit(1);
|
|
56
|
-
}
|
|
57
|
-
response = await sendRequest('pane.focus', { id });
|
|
58
|
-
if (jsonMode) {
|
|
59
|
-
printResult(response);
|
|
60
|
-
} else {
|
|
61
|
-
if (!response.ok) { printError(response); return; }
|
|
62
|
-
console.log(`Focused pane: ${id}`);
|
|
63
|
-
}
|
|
64
|
-
break;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
case 'split': {
|
|
68
|
-
const direction = parseFlag(args, '--direction') ?? 'right';
|
|
69
|
-
if (direction !== 'right' && direction !== 'down') {
|
|
70
|
-
console.error('Error: --direction must be "right" or "down"');
|
|
71
|
-
process.exit(1);
|
|
72
|
-
}
|
|
73
|
-
// right → horizontal, down → vertical (server expects horizontal/vertical)
|
|
74
|
-
const dirMap: Record<string, string> = { right: 'horizontal', down: 'vertical' };
|
|
75
|
-
const mapped = dirMap[direction] || direction;
|
|
76
|
-
response = await sendRequest('pane.split', { direction: mapped });
|
|
77
|
-
if (jsonMode) {
|
|
78
|
-
printResult(response);
|
|
79
|
-
} else {
|
|
80
|
-
if (!response.ok) { printError(response); return; }
|
|
81
|
-
console.log(`Split pane ${direction}.`);
|
|
82
|
-
}
|
|
83
|
-
break;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
default:
|
|
87
|
-
console.error(`Unknown pane command: ${cmd}`);
|
|
88
|
-
process.exit(1);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
import { sendRequest } from '../client';
|
|
2
|
-
import { printResult, printError } from '../utils';
|
|
3
|
-
import type { RpcResponse } from '../../shared/rpc';
|
|
4
|
-
|
|
5
|
-
interface SurfaceInfo {
|
|
6
|
-
id: string;
|
|
7
|
-
title: string;
|
|
8
|
-
shell: string;
|
|
9
|
-
cwd: string;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
function formatSurfaceList(result: unknown): void {
|
|
13
|
-
const list = result as SurfaceInfo[];
|
|
14
|
-
if (!Array.isArray(list) || list.length === 0) {
|
|
15
|
-
console.log('No surfaces found.');
|
|
16
|
-
return;
|
|
17
|
-
}
|
|
18
|
-
const maxId = Math.max(...list.map((s) => s.id.length));
|
|
19
|
-
const maxTitle = Math.max(...list.map((s) => (s.title ?? '').length), 5);
|
|
20
|
-
console.log(
|
|
21
|
-
'ID'.padEnd(maxId + 2) +
|
|
22
|
-
'TITLE'.padEnd(maxTitle + 2) +
|
|
23
|
-
'SHELL'
|
|
24
|
-
);
|
|
25
|
-
console.log('-'.repeat(maxId + maxTitle + 20));
|
|
26
|
-
for (const s of list) {
|
|
27
|
-
console.log(
|
|
28
|
-
s.id.padEnd(maxId + 2) +
|
|
29
|
-
(s.title ?? '').padEnd(maxTitle + 2) +
|
|
30
|
-
(s.shell ?? '')
|
|
31
|
-
);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export async function handleSurface(
|
|
36
|
-
cmd: string,
|
|
37
|
-
args: string[],
|
|
38
|
-
jsonMode: boolean
|
|
39
|
-
): Promise<void> {
|
|
40
|
-
let response: RpcResponse;
|
|
41
|
-
|
|
42
|
-
switch (cmd) {
|
|
43
|
-
case 'list-surfaces': {
|
|
44
|
-
response = await sendRequest('surface.list', {});
|
|
45
|
-
if (jsonMode) {
|
|
46
|
-
printResult(response);
|
|
47
|
-
} else {
|
|
48
|
-
if (!response.ok) { printError(response); return; }
|
|
49
|
-
formatSurfaceList(response.result);
|
|
50
|
-
}
|
|
51
|
-
break;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
case 'new-surface': {
|
|
55
|
-
response = await sendRequest('surface.new', {});
|
|
56
|
-
if (jsonMode) {
|
|
57
|
-
printResult(response);
|
|
58
|
-
} else {
|
|
59
|
-
if (!response.ok) { printError(response); return; }
|
|
60
|
-
const s = response.result as SurfaceInfo;
|
|
61
|
-
console.log(`Created surface: ${s?.id ?? '(unknown)'}`);
|
|
62
|
-
}
|
|
63
|
-
break;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
case 'focus-surface': {
|
|
67
|
-
const id = args[0];
|
|
68
|
-
if (!id) {
|
|
69
|
-
console.error('Error: focus-surface requires <id>');
|
|
70
|
-
process.exit(1);
|
|
71
|
-
}
|
|
72
|
-
response = await sendRequest('surface.focus', { id });
|
|
73
|
-
if (jsonMode) {
|
|
74
|
-
printResult(response);
|
|
75
|
-
} else {
|
|
76
|
-
if (!response.ok) { printError(response); return; }
|
|
77
|
-
console.log(`Focused surface: ${id}`);
|
|
78
|
-
}
|
|
79
|
-
break;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
case 'close-surface': {
|
|
83
|
-
const id = args[0];
|
|
84
|
-
if (!id) {
|
|
85
|
-
console.error('Error: close-surface requires <id>');
|
|
86
|
-
process.exit(1);
|
|
87
|
-
}
|
|
88
|
-
response = await sendRequest('surface.close', { id });
|
|
89
|
-
if (jsonMode) {
|
|
90
|
-
printResult(response);
|
|
91
|
-
} else {
|
|
92
|
-
if (!response.ok) { printError(response); return; }
|
|
93
|
-
console.log(`Closed surface: ${id}`);
|
|
94
|
-
}
|
|
95
|
-
break;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
default:
|
|
99
|
-
console.error(`Unknown surface command: ${cmd}`);
|
|
100
|
-
process.exit(1);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import { sendRequest } from '../client';
|
|
2
|
-
import { printResult, printError } from '../utils';
|
|
3
|
-
import type { RpcResponse } from '../../shared/rpc';
|
|
4
|
-
|
|
5
|
-
interface IdentifyResult {
|
|
6
|
-
app: string;
|
|
7
|
-
version: string;
|
|
8
|
-
platform: string;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export async function handleSystem(
|
|
12
|
-
cmd: string,
|
|
13
|
-
args: string[],
|
|
14
|
-
jsonMode: boolean
|
|
15
|
-
): Promise<void> {
|
|
16
|
-
let response: RpcResponse;
|
|
17
|
-
|
|
18
|
-
switch (cmd) {
|
|
19
|
-
case 'identify': {
|
|
20
|
-
response = await sendRequest('system.identify', {});
|
|
21
|
-
if (jsonMode) {
|
|
22
|
-
printResult(response);
|
|
23
|
-
} else {
|
|
24
|
-
if (!response.ok) { printError(response); return; }
|
|
25
|
-
const info = response.result as IdentifyResult;
|
|
26
|
-
console.log(`app: ${info?.app ?? 'wmux'}`);
|
|
27
|
-
console.log(`version: ${info?.version ?? '1.0.0'}`);
|
|
28
|
-
console.log(`platform: ${info?.platform ?? process.platform}`);
|
|
29
|
-
}
|
|
30
|
-
break;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
case 'capabilities': {
|
|
34
|
-
response = await sendRequest('system.capabilities', {});
|
|
35
|
-
if (jsonMode) {
|
|
36
|
-
printResult(response);
|
|
37
|
-
} else {
|
|
38
|
-
if (!response.ok) { printError(response); return; }
|
|
39
|
-
// server may return { methods: string[] } or string[] directly
|
|
40
|
-
const result = response.result as { methods?: string[] } | string[];
|
|
41
|
-
const methods = Array.isArray(result) ? result : (result?.methods || []);
|
|
42
|
-
if (methods.length > 0) {
|
|
43
|
-
console.log('Supported RPC methods:');
|
|
44
|
-
for (const m of methods) {
|
|
45
|
-
console.log(` ${m}`);
|
|
46
|
-
}
|
|
47
|
-
} else {
|
|
48
|
-
console.log(JSON.stringify(response.result, null, 2));
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
break;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
case 'set-status': {
|
|
55
|
-
const text = args[0];
|
|
56
|
-
if (text === undefined) {
|
|
57
|
-
console.error('Error: set-status requires <text>');
|
|
58
|
-
process.exit(1);
|
|
59
|
-
}
|
|
60
|
-
response = await sendRequest('meta.setStatus', { text });
|
|
61
|
-
if (jsonMode) {
|
|
62
|
-
printResult(response);
|
|
63
|
-
} else {
|
|
64
|
-
if (!response.ok) { printError(response); return; }
|
|
65
|
-
console.log(`Status set: "${text}"`);
|
|
66
|
-
}
|
|
67
|
-
break;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
case 'set-progress': {
|
|
71
|
-
const raw = args[0];
|
|
72
|
-
if (raw === undefined) {
|
|
73
|
-
console.error('Error: set-progress requires <0-100>');
|
|
74
|
-
process.exit(1);
|
|
75
|
-
}
|
|
76
|
-
const value = Number(raw);
|
|
77
|
-
if (isNaN(value) || value < 0 || value > 100) {
|
|
78
|
-
console.error('Error: progress value must be a number between 0 and 100');
|
|
79
|
-
process.exit(1);
|
|
80
|
-
}
|
|
81
|
-
response = await sendRequest('meta.setProgress', { value });
|
|
82
|
-
if (jsonMode) {
|
|
83
|
-
printResult(response);
|
|
84
|
-
} else {
|
|
85
|
-
if (!response.ok) { printError(response); return; }
|
|
86
|
-
console.log(`Progress set: ${value}%`);
|
|
87
|
-
}
|
|
88
|
-
break;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
default:
|
|
92
|
-
console.error(`Unknown system command: ${cmd}`);
|
|
93
|
-
process.exit(1);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
import { sendRequest } from '../client';
|
|
2
|
-
import { printResult, printError, parseFlag } from '../utils';
|
|
3
|
-
import type { RpcResponse } from '../../shared/rpc';
|
|
4
|
-
|
|
5
|
-
interface WorkspaceInfo {
|
|
6
|
-
id: string;
|
|
7
|
-
name: string;
|
|
8
|
-
isActive?: boolean;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
function formatWorkspaceList(result: unknown): void {
|
|
12
|
-
const list = result as WorkspaceInfo[];
|
|
13
|
-
if (!Array.isArray(list) || list.length === 0) {
|
|
14
|
-
console.log('No workspaces found.');
|
|
15
|
-
return;
|
|
16
|
-
}
|
|
17
|
-
const maxId = Math.max(...list.map((w) => w.id.length));
|
|
18
|
-
console.log(
|
|
19
|
-
'ID'.padEnd(maxId + 2) + 'NAME' + ' ' + 'STATUS'
|
|
20
|
-
);
|
|
21
|
-
console.log('-'.repeat(maxId + 30));
|
|
22
|
-
for (const ws of list) {
|
|
23
|
-
const active = ws.isActive ? ' (active)' : '';
|
|
24
|
-
console.log(ws.id.padEnd(maxId + 2) + ws.name + active);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function formatWorkspaceCurrent(result: unknown): void {
|
|
29
|
-
const ws = result as WorkspaceInfo | null;
|
|
30
|
-
if (!ws) {
|
|
31
|
-
console.log('No active workspace.');
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
console.log(`Current workspace: ${ws.name} (${ws.id})`);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export async function handleWorkspace(
|
|
38
|
-
cmd: string,
|
|
39
|
-
args: string[],
|
|
40
|
-
jsonMode: boolean
|
|
41
|
-
): Promise<void> {
|
|
42
|
-
let response: RpcResponse;
|
|
43
|
-
|
|
44
|
-
switch (cmd) {
|
|
45
|
-
case 'list-workspaces': {
|
|
46
|
-
response = await sendRequest('workspace.list', {});
|
|
47
|
-
if (jsonMode) {
|
|
48
|
-
printResult(response);
|
|
49
|
-
} else {
|
|
50
|
-
if (!response.ok) { printError(response); return; }
|
|
51
|
-
formatWorkspaceList(response.result);
|
|
52
|
-
}
|
|
53
|
-
break;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
case 'new-workspace': {
|
|
57
|
-
const name = parseFlag(args, '--name') ?? `workspace-${Date.now()}`;
|
|
58
|
-
response = await sendRequest('workspace.new', { name });
|
|
59
|
-
if (jsonMode) {
|
|
60
|
-
printResult(response);
|
|
61
|
-
} else {
|
|
62
|
-
if (!response.ok) { printError(response); return; }
|
|
63
|
-
const ws = response.result as WorkspaceInfo;
|
|
64
|
-
console.log(`Created workspace: ${ws?.name ?? name} (${ws?.id ?? ''})`);
|
|
65
|
-
}
|
|
66
|
-
break;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
case 'focus-workspace': {
|
|
70
|
-
const id = args[0];
|
|
71
|
-
if (!id) {
|
|
72
|
-
console.error('Error: focus-workspace requires <id>');
|
|
73
|
-
process.exit(1);
|
|
74
|
-
}
|
|
75
|
-
response = await sendRequest('workspace.focus', { id });
|
|
76
|
-
if (jsonMode) {
|
|
77
|
-
printResult(response);
|
|
78
|
-
} else {
|
|
79
|
-
if (!response.ok) { printError(response); return; }
|
|
80
|
-
console.log(`Focused workspace: ${id}`);
|
|
81
|
-
}
|
|
82
|
-
break;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
case 'close-workspace': {
|
|
86
|
-
const id = args[0];
|
|
87
|
-
if (!id) {
|
|
88
|
-
console.error('Error: close-workspace requires <id>');
|
|
89
|
-
process.exit(1);
|
|
90
|
-
}
|
|
91
|
-
response = await sendRequest('workspace.close', { id });
|
|
92
|
-
if (jsonMode) {
|
|
93
|
-
printResult(response);
|
|
94
|
-
} else {
|
|
95
|
-
if (!response.ok) { printError(response); return; }
|
|
96
|
-
console.log(`Closed workspace: ${id}`);
|
|
97
|
-
}
|
|
98
|
-
break;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
case 'current-workspace': {
|
|
102
|
-
response = await sendRequest('workspace.current', {});
|
|
103
|
-
if (jsonMode) {
|
|
104
|
-
printResult(response);
|
|
105
|
-
} else {
|
|
106
|
-
if (!response.ok) { printError(response); return; }
|
|
107
|
-
formatWorkspaceCurrent(response.result);
|
|
108
|
-
}
|
|
109
|
-
break;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
default:
|
|
113
|
-
console.error(`Unknown workspace command: ${cmd}`);
|
|
114
|
-
process.exit(1);
|
|
115
|
-
}
|
|
116
|
-
}
|
package/src/cli/index.ts
DELETED
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
process.on('SIGINT', () => {
|
|
4
|
-
process.exit(130);
|
|
5
|
-
});
|
|
6
|
-
|
|
7
|
-
import { hasFlag } from './utils';
|
|
8
|
-
import { handleWorkspace } from './commands/workspace';
|
|
9
|
-
import { handleSurface } from './commands/surface';
|
|
10
|
-
import { handlePane } from './commands/pane';
|
|
11
|
-
import { handleInput } from './commands/input';
|
|
12
|
-
import { handleNotify } from './commands/notify';
|
|
13
|
-
import { handleSystem } from './commands/system';
|
|
14
|
-
import { handleBrowser } from './commands/browser';
|
|
15
|
-
|
|
16
|
-
const HELP_TEXT = `
|
|
17
|
-
wmux CLI
|
|
18
|
-
|
|
19
|
-
USAGE
|
|
20
|
-
wmux <command> [options]
|
|
21
|
-
|
|
22
|
-
WORKSPACE COMMANDS
|
|
23
|
-
list-workspaces List all workspaces
|
|
24
|
-
new-workspace [--name <name>] Create a new workspace
|
|
25
|
-
focus-workspace <id> Focus a workspace by ID
|
|
26
|
-
close-workspace <id> Close a workspace by ID
|
|
27
|
-
current-workspace Show the active workspace
|
|
28
|
-
|
|
29
|
-
SURFACE COMMANDS
|
|
30
|
-
list-surfaces List all surfaces in the active workspace
|
|
31
|
-
new-surface Open a new surface (terminal tab)
|
|
32
|
-
focus-surface <id> Focus a surface by ID
|
|
33
|
-
close-surface <id> Close a surface by ID
|
|
34
|
-
|
|
35
|
-
PANE COMMANDS
|
|
36
|
-
list-panes List all panes in the active workspace
|
|
37
|
-
focus-pane <id> Focus a pane by ID
|
|
38
|
-
split [--direction right|down] Split the active pane (default: right)
|
|
39
|
-
|
|
40
|
-
INPUT COMMANDS
|
|
41
|
-
send <text> Send text to the active terminal
|
|
42
|
-
send-key <keystroke> Send a key (e.g. Enter, ctrl-c, Tab)
|
|
43
|
-
read-screen Read the current terminal screen content
|
|
44
|
-
|
|
45
|
-
NOTIFICATION COMMANDS
|
|
46
|
-
notify --title <title> --body <body> Show a notification in wmux
|
|
47
|
-
|
|
48
|
-
SYSTEM COMMANDS
|
|
49
|
-
set-status <text> Set a status message on the active workspace
|
|
50
|
-
set-progress <0-100> Set a progress value on the active workspace
|
|
51
|
-
identify Show wmux app info
|
|
52
|
-
capabilities List all supported RPC methods
|
|
53
|
-
|
|
54
|
-
BROWSER COMMANDS
|
|
55
|
-
browser snapshot Return the full page HTML of the active browser surface
|
|
56
|
-
browser click <selector> Click an element by CSS selector
|
|
57
|
-
browser fill <selector> <text> Fill an input field by CSS selector
|
|
58
|
-
browser eval <code> Execute JavaScript in the browser context
|
|
59
|
-
browser navigate <url> Navigate the browser surface to a URL
|
|
60
|
-
|
|
61
|
-
GLOBAL FLAGS
|
|
62
|
-
--json Output raw JSON (useful for scripting)
|
|
63
|
-
--help Show this help text
|
|
64
|
-
|
|
65
|
-
EXAMPLES
|
|
66
|
-
wmux list-workspaces
|
|
67
|
-
wmux new-workspace --name dev
|
|
68
|
-
wmux send "echo hello"
|
|
69
|
-
wmux notify --title "Done" --body "Build finished"
|
|
70
|
-
wmux identify --json
|
|
71
|
-
wmux browser snapshot
|
|
72
|
-
wmux browser navigate "https://example.com"
|
|
73
|
-
wmux browser click "#login-btn"
|
|
74
|
-
`.trimStart();
|
|
75
|
-
|
|
76
|
-
const WORKSPACE_CMDS = new Set([
|
|
77
|
-
'list-workspaces',
|
|
78
|
-
'new-workspace',
|
|
79
|
-
'focus-workspace',
|
|
80
|
-
'close-workspace',
|
|
81
|
-
'current-workspace',
|
|
82
|
-
]);
|
|
83
|
-
|
|
84
|
-
const SURFACE_CMDS = new Set([
|
|
85
|
-
'list-surfaces',
|
|
86
|
-
'new-surface',
|
|
87
|
-
'focus-surface',
|
|
88
|
-
'close-surface',
|
|
89
|
-
]);
|
|
90
|
-
|
|
91
|
-
const PANE_CMDS = new Set(['list-panes', 'focus-pane', 'split']);
|
|
92
|
-
|
|
93
|
-
const INPUT_CMDS = new Set(['send', 'send-key', 'read-screen']);
|
|
94
|
-
|
|
95
|
-
const SYSTEM_CMDS = new Set([
|
|
96
|
-
'identify',
|
|
97
|
-
'capabilities',
|
|
98
|
-
'set-status',
|
|
99
|
-
'set-progress',
|
|
100
|
-
]);
|
|
101
|
-
|
|
102
|
-
async function main(): Promise<void> {
|
|
103
|
-
// process.argv = ['node', 'index.js', ...userArgs]
|
|
104
|
-
const argv = process.argv.slice(2);
|
|
105
|
-
|
|
106
|
-
if (argv.length === 0 || hasFlag(argv, '--help') || hasFlag(argv, '-h')) {
|
|
107
|
-
process.stdout.write(HELP_TEXT);
|
|
108
|
-
process.exit(0);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
const jsonMode = hasFlag(argv, '--json');
|
|
112
|
-
|
|
113
|
-
// Strip global flags so commands see clean args
|
|
114
|
-
const args = argv.filter((a) => a !== '--json' && a !== '--help' && a !== '-h');
|
|
115
|
-
|
|
116
|
-
const cmd = args[0];
|
|
117
|
-
const rest = args.slice(1);
|
|
118
|
-
|
|
119
|
-
try {
|
|
120
|
-
if (WORKSPACE_CMDS.has(cmd)) {
|
|
121
|
-
await handleWorkspace(cmd, rest, jsonMode);
|
|
122
|
-
} else if (SURFACE_CMDS.has(cmd)) {
|
|
123
|
-
await handleSurface(cmd, rest, jsonMode);
|
|
124
|
-
} else if (PANE_CMDS.has(cmd)) {
|
|
125
|
-
await handlePane(cmd, rest, jsonMode);
|
|
126
|
-
} else if (INPUT_CMDS.has(cmd)) {
|
|
127
|
-
await handleInput(cmd, rest, jsonMode);
|
|
128
|
-
} else if (cmd === 'notify') {
|
|
129
|
-
await handleNotify(rest, jsonMode);
|
|
130
|
-
} else if (SYSTEM_CMDS.has(cmd)) {
|
|
131
|
-
await handleSystem(cmd, rest, jsonMode);
|
|
132
|
-
} else if (cmd === 'browser') {
|
|
133
|
-
await handleBrowser(rest, jsonMode);
|
|
134
|
-
} else {
|
|
135
|
-
console.error(`Unknown command: "${cmd}". Run 'wmux --help' for usage.`);
|
|
136
|
-
process.exit(1);
|
|
137
|
-
}
|
|
138
|
-
} catch (err: unknown) {
|
|
139
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
140
|
-
console.error(message);
|
|
141
|
-
process.exit(1);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
main();
|
package/src/cli/utils.ts
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import type { RpcResponse } from '../shared/rpc';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Print the result field of a successful RPC response as JSON.
|
|
5
|
-
* If the response contains an error, the error is printed to stderr and
|
|
6
|
-
* the process exits with code 1.
|
|
7
|
-
*/
|
|
8
|
-
export function printResult(response: RpcResponse): void {
|
|
9
|
-
if (!response.ok) {
|
|
10
|
-
printError(response);
|
|
11
|
-
return;
|
|
12
|
-
}
|
|
13
|
-
console.log(JSON.stringify(response.result, null, 2));
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Print the error field of a failed RPC response to stderr and exit with 1.
|
|
18
|
-
*/
|
|
19
|
-
export function printError(response: RpcResponse): void {
|
|
20
|
-
const msg = !response.ok ? response.error : 'Unknown error from wmux';
|
|
21
|
-
console.error(`Error: ${msg}`);
|
|
22
|
-
process.exit(1);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Parse a named flag value from an argv array.
|
|
27
|
-
* e.g. parseFlag(['--name', 'dev'], '--name') => 'dev'
|
|
28
|
-
* Returns undefined when the flag is not present.
|
|
29
|
-
*/
|
|
30
|
-
export function parseFlag(args: string[], flag: string): string | undefined {
|
|
31
|
-
const idx = args.indexOf(flag);
|
|
32
|
-
if (idx === -1) return undefined;
|
|
33
|
-
const value = args[idx + 1];
|
|
34
|
-
if (value === undefined || value.startsWith('-')) return undefined;
|
|
35
|
-
return value;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Check whether a bare flag is present in argv.
|
|
40
|
-
* e.g. hasFlag(['--json', 'identify'], '--json') => true
|
|
41
|
-
*/
|
|
42
|
-
export function hasFlag(args: string[], flag: string): boolean {
|
|
43
|
-
return args.includes(flag);
|
|
44
|
-
}
|
package/src/main/index.ts
DELETED
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
process.on('unhandledRejection', (reason) => {
|
|
2
|
-
console.error('[Main] Unhandled rejection:', reason);
|
|
3
|
-
});
|
|
4
|
-
process.on('uncaughtException', (err) => {
|
|
5
|
-
console.error('[Main] Uncaught exception:', err);
|
|
6
|
-
});
|
|
7
|
-
|
|
8
|
-
import { app, BrowserWindow } from 'electron';
|
|
9
|
-
import started from 'electron-squirrel-startup';
|
|
10
|
-
import { createWindow } from './window/createWindow';
|
|
11
|
-
import { PTYManager } from './pty/PTYManager';
|
|
12
|
-
import { PTYBridge } from './pty/PTYBridge';
|
|
13
|
-
import { registerAllHandlers } from './ipc/registerHandlers';
|
|
14
|
-
import { RpcRouter } from './pipe/RpcRouter';
|
|
15
|
-
import { PipeServer } from './pipe/PipeServer';
|
|
16
|
-
import { registerWorkspaceRpc } from './pipe/handlers/workspace.rpc';
|
|
17
|
-
import { registerSurfaceRpc } from './pipe/handlers/surface.rpc';
|
|
18
|
-
import { registerPaneRpc } from './pipe/handlers/pane.rpc';
|
|
19
|
-
import { registerInputRpc } from './pipe/handlers/input.rpc';
|
|
20
|
-
import { registerNotifyRpc } from './pipe/handlers/notify.rpc';
|
|
21
|
-
import { registerMetaRpc } from './pipe/handlers/meta.rpc';
|
|
22
|
-
import { registerSystemRpc } from './pipe/handlers/system.rpc';
|
|
23
|
-
import { registerBrowserRpc } from './pipe/handlers/browser.rpc';
|
|
24
|
-
import { AutoUpdater } from './updater/AutoUpdater';
|
|
25
|
-
import { McpRegistrar } from './mcp/McpRegistrar';
|
|
26
|
-
|
|
27
|
-
if (started) {
|
|
28
|
-
app.quit();
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const ptyManager = new PTYManager();
|
|
32
|
-
let mainWindow: BrowserWindow | null = null;
|
|
33
|
-
const ptyBridge = new PTYBridge(ptyManager, () => mainWindow);
|
|
34
|
-
const autoUpdater = new AutoUpdater(() => mainWindow);
|
|
35
|
-
|
|
36
|
-
const rpcRouter = new RpcRouter();
|
|
37
|
-
const pipeServer = new PipeServer(rpcRouter);
|
|
38
|
-
const mcpRegistrar = new McpRegistrar();
|
|
39
|
-
|
|
40
|
-
const cleanupHandlers = registerAllHandlers(ptyManager, ptyBridge, () => mainWindow);
|
|
41
|
-
registerWorkspaceRpc(rpcRouter, () => mainWindow);
|
|
42
|
-
registerSurfaceRpc(rpcRouter, () => mainWindow);
|
|
43
|
-
registerPaneRpc(rpcRouter, () => mainWindow);
|
|
44
|
-
registerInputRpc(rpcRouter, ptyManager, () => mainWindow);
|
|
45
|
-
registerNotifyRpc(rpcRouter, () => mainWindow);
|
|
46
|
-
registerMetaRpc(rpcRouter, () => mainWindow);
|
|
47
|
-
registerSystemRpc(rpcRouter);
|
|
48
|
-
registerBrowserRpc(rpcRouter, () => mainWindow);
|
|
49
|
-
|
|
50
|
-
app.on('ready', () => {
|
|
51
|
-
console.log('[Main] App ready, creating window...');
|
|
52
|
-
mainWindow = createWindow();
|
|
53
|
-
console.log('[Main] Window created:', !!mainWindow);
|
|
54
|
-
mainWindow.on('closed', () => {
|
|
55
|
-
mainWindow = null;
|
|
56
|
-
});
|
|
57
|
-
mainWindow.webContents.on('did-fail-load', (_e, code, desc) => {
|
|
58
|
-
console.error('[Main] Page failed to load:', code, desc);
|
|
59
|
-
});
|
|
60
|
-
mainWindow.webContents.on('did-finish-load', () => {
|
|
61
|
-
console.log('[Main] Page loaded successfully');
|
|
62
|
-
});
|
|
63
|
-
pipeServer.start();
|
|
64
|
-
const authToken = pipeServer.getAuthToken();
|
|
65
|
-
ptyManager.setAuthToken(authToken);
|
|
66
|
-
mcpRegistrar.register(authToken);
|
|
67
|
-
autoUpdater.start();
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
app.on('window-all-closed', () => {
|
|
71
|
-
app.quit();
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
app.on('before-quit', () => {
|
|
75
|
-
cleanupHandlers();
|
|
76
|
-
ptyManager.disposeAll();
|
|
77
|
-
pipeServer.stop();
|
|
78
|
-
mcpRegistrar.unregister();
|
|
79
|
-
autoUpdater.stop();
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
app.on('activate', () => {
|
|
83
|
-
if (BrowserWindow.getAllWindows().length === 0) {
|
|
84
|
-
mainWindow = createWindow();
|
|
85
|
-
}
|
|
86
|
-
});
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { ipcMain, clipboard } from 'electron';
|
|
2
|
-
import { IPC } from '../../../shared/constants';
|
|
3
|
-
|
|
4
|
-
export function registerClipboardHandlers(): void {
|
|
5
|
-
// Remove any previously registered handlers before re-registering.
|
|
6
|
-
// ipcMain.handle() throws if the same channel is registered twice (e.g.
|
|
7
|
-
// during dev HMR reloads), which silently kills clipboard IPC.
|
|
8
|
-
ipcMain.removeHandler(IPC.CLIPBOARD_WRITE);
|
|
9
|
-
ipcMain.removeHandler(IPC.CLIPBOARD_READ);
|
|
10
|
-
|
|
11
|
-
ipcMain.handle(IPC.CLIPBOARD_WRITE, (_event, text: string) => {
|
|
12
|
-
if (typeof text !== 'string') return;
|
|
13
|
-
if (text.length > 1_000_000) return; // 1MB limit
|
|
14
|
-
clipboard.writeText(text);
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
ipcMain.handle(IPC.CLIPBOARD_READ, () => {
|
|
18
|
-
return clipboard.readText();
|
|
19
|
-
});
|
|
20
|
-
}
|