@wong2kim/wmux 1.0.0

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 (122) hide show
  1. package/README.md +157 -0
  2. package/assets/icon.ico +0 -0
  3. package/assets/icon.svg +6 -0
  4. package/dist/cli/cli/client.js +102 -0
  5. package/dist/cli/cli/commands/browser.js +137 -0
  6. package/dist/cli/cli/commands/input.js +80 -0
  7. package/dist/cli/cli/commands/notify.js +28 -0
  8. package/dist/cli/cli/commands/pane.js +88 -0
  9. package/dist/cli/cli/commands/surface.js +98 -0
  10. package/dist/cli/cli/commands/system.js +98 -0
  11. package/dist/cli/cli/commands/workspace.js +117 -0
  12. package/dist/cli/cli/index.js +140 -0
  13. package/dist/cli/cli/utils.js +47 -0
  14. package/dist/cli/shared/constants.js +54 -0
  15. package/dist/cli/shared/rpc.js +33 -0
  16. package/dist/cli/shared/types.js +79 -0
  17. package/dist/mcp/mcp/index.js +60 -0
  18. package/dist/mcp/mcp/wmux-client.js +146 -0
  19. package/dist/mcp/shared/constants.js +54 -0
  20. package/dist/mcp/shared/rpc.js +33 -0
  21. package/dist/mcp/shared/types.js +79 -0
  22. package/forge.config.ts +61 -0
  23. package/index.html +12 -0
  24. package/package.json +84 -0
  25. package/postcss.config.js +6 -0
  26. package/src/cli/client.ts +76 -0
  27. package/src/cli/commands/browser.ts +128 -0
  28. package/src/cli/commands/input.ts +72 -0
  29. package/src/cli/commands/notify.ts +29 -0
  30. package/src/cli/commands/pane.ts +90 -0
  31. package/src/cli/commands/surface.ts +102 -0
  32. package/src/cli/commands/system.ts +95 -0
  33. package/src/cli/commands/workspace.ts +116 -0
  34. package/src/cli/index.ts +145 -0
  35. package/src/cli/utils.ts +44 -0
  36. package/src/main/index.ts +86 -0
  37. package/src/main/ipc/handlers/clipboard.handler.ts +20 -0
  38. package/src/main/ipc/handlers/metadata.handler.ts +56 -0
  39. package/src/main/ipc/handlers/pty.handler.ts +69 -0
  40. package/src/main/ipc/handlers/session.handler.ts +17 -0
  41. package/src/main/ipc/handlers/shell.handler.ts +11 -0
  42. package/src/main/ipc/registerHandlers.ts +31 -0
  43. package/src/main/mcp/McpRegistrar.ts +156 -0
  44. package/src/main/metadata/MetadataCollector.ts +58 -0
  45. package/src/main/notification/ToastManager.ts +32 -0
  46. package/src/main/pipe/PipeServer.ts +190 -0
  47. package/src/main/pipe/RpcRouter.ts +46 -0
  48. package/src/main/pipe/handlers/_bridge.ts +40 -0
  49. package/src/main/pipe/handlers/browser.rpc.ts +132 -0
  50. package/src/main/pipe/handlers/input.rpc.ts +120 -0
  51. package/src/main/pipe/handlers/meta.rpc.ts +59 -0
  52. package/src/main/pipe/handlers/notify.rpc.ts +53 -0
  53. package/src/main/pipe/handlers/pane.rpc.ts +39 -0
  54. package/src/main/pipe/handlers/surface.rpc.ts +43 -0
  55. package/src/main/pipe/handlers/system.rpc.ts +36 -0
  56. package/src/main/pipe/handlers/workspace.rpc.ts +52 -0
  57. package/src/main/pty/AgentDetector.ts +247 -0
  58. package/src/main/pty/OscParser.ts +81 -0
  59. package/src/main/pty/PTYBridge.ts +88 -0
  60. package/src/main/pty/PTYManager.ts +104 -0
  61. package/src/main/pty/ShellDetector.ts +63 -0
  62. package/src/main/session/SessionManager.ts +53 -0
  63. package/src/main/updater/AutoUpdater.ts +132 -0
  64. package/src/main/window/createWindow.ts +71 -0
  65. package/src/mcp/README.md +56 -0
  66. package/src/mcp/index.ts +153 -0
  67. package/src/mcp/wmux-client.ts +127 -0
  68. package/src/preload/index.ts +111 -0
  69. package/src/preload/preload.ts +108 -0
  70. package/src/renderer/App.tsx +5 -0
  71. package/src/renderer/components/Browser/BrowserPanel.tsx +219 -0
  72. package/src/renderer/components/Browser/BrowserToolbar.tsx +253 -0
  73. package/src/renderer/components/Company/ApprovalDialog.tsx +3 -0
  74. package/src/renderer/components/Company/CompanyView.tsx +7 -0
  75. package/src/renderer/components/Company/MessageFeedPanel.tsx +3 -0
  76. package/src/renderer/components/Layout/AppLayout.tsx +234 -0
  77. package/src/renderer/components/Notification/NotificationPanel.tsx +129 -0
  78. package/src/renderer/components/Palette/CommandPalette.tsx +409 -0
  79. package/src/renderer/components/Palette/PaletteItem.tsx +55 -0
  80. package/src/renderer/components/Pane/Pane.tsx +122 -0
  81. package/src/renderer/components/Pane/PaneContainer.tsx +41 -0
  82. package/src/renderer/components/Pane/SurfaceTabs.tsx +46 -0
  83. package/src/renderer/components/Settings/SettingsPanel.tsx +886 -0
  84. package/src/renderer/components/Sidebar/MiniSidebar.tsx +67 -0
  85. package/src/renderer/components/Sidebar/Sidebar.tsx +84 -0
  86. package/src/renderer/components/Sidebar/WorkspaceItem.tsx +241 -0
  87. package/src/renderer/components/StatusBar/StatusBar.tsx +93 -0
  88. package/src/renderer/components/Terminal/SearchBar.tsx +126 -0
  89. package/src/renderer/components/Terminal/Terminal.tsx +102 -0
  90. package/src/renderer/components/Terminal/ViCopyMode.tsx +104 -0
  91. package/src/renderer/hooks/useKeyboard.ts +310 -0
  92. package/src/renderer/hooks/useNotificationListener.ts +80 -0
  93. package/src/renderer/hooks/useNotificationSound.ts +75 -0
  94. package/src/renderer/hooks/useRpcBridge.ts +451 -0
  95. package/src/renderer/hooks/useT.ts +11 -0
  96. package/src/renderer/hooks/useTerminal.ts +349 -0
  97. package/src/renderer/hooks/useViCopyMode.ts +320 -0
  98. package/src/renderer/i18n/index.ts +69 -0
  99. package/src/renderer/i18n/locales/en.ts +157 -0
  100. package/src/renderer/i18n/locales/ja.ts +155 -0
  101. package/src/renderer/i18n/locales/ko.ts +155 -0
  102. package/src/renderer/i18n/locales/zh.ts +155 -0
  103. package/src/renderer/index.tsx +6 -0
  104. package/src/renderer/stores/index.ts +19 -0
  105. package/src/renderer/stores/slices/notificationSlice.ts +56 -0
  106. package/src/renderer/stores/slices/paneSlice.ts +141 -0
  107. package/src/renderer/stores/slices/surfaceSlice.ts +122 -0
  108. package/src/renderer/stores/slices/uiSlice.ts +247 -0
  109. package/src/renderer/stores/slices/workspaceSlice.ts +120 -0
  110. package/src/renderer/styles/globals.css +150 -0
  111. package/src/renderer/themes.ts +99 -0
  112. package/src/shared/constants.ts +53 -0
  113. package/src/shared/electron.d.ts +11 -0
  114. package/src/shared/rpc.ts +71 -0
  115. package/src/shared/types.ts +176 -0
  116. package/tailwind.config.js +11 -0
  117. package/tsconfig.cli.json +24 -0
  118. package/tsconfig.json +21 -0
  119. package/tsconfig.mcp.json +25 -0
  120. package/vite.main.config.ts +14 -0
  121. package/vite.preload.config.ts +9 -0
  122. package/vite.renderer.config.ts +6 -0
@@ -0,0 +1,71 @@
1
+ // === JSON-RPC Protocol Types ===
2
+
3
+ export interface RpcRequest {
4
+ id: string;
5
+ method: RpcMethod;
6
+ params: Record<string, unknown>;
7
+ token?: string;
8
+ }
9
+
10
+ export type RpcResponse =
11
+ | { id: string; ok: true; result: unknown }
12
+ | { id: string; ok: false; error: string };
13
+
14
+ // === RPC Method definitions ===
15
+ export type RpcMethod =
16
+ | 'workspace.list'
17
+ | 'workspace.new'
18
+ | 'workspace.focus'
19
+ | 'workspace.close'
20
+ | 'workspace.current'
21
+ | 'surface.list'
22
+ | 'surface.new'
23
+ | 'surface.focus'
24
+ | 'surface.close'
25
+ | 'pane.list'
26
+ | 'pane.focus'
27
+ | 'pane.split'
28
+ | 'input.send'
29
+ | 'input.sendKey'
30
+ | 'input.readScreen'
31
+ | 'notify'
32
+ | 'meta.setStatus'
33
+ | 'meta.setProgress'
34
+ | 'system.identify'
35
+ | 'system.capabilities'
36
+ | 'browser.open'
37
+ | 'browser.snapshot'
38
+ | 'browser.click'
39
+ | 'browser.fill'
40
+ | 'browser.eval'
41
+ | 'browser.navigate';
42
+
43
+ // All available methods as array (for system.capabilities)
44
+ export const ALL_RPC_METHODS = [
45
+ 'workspace.list',
46
+ 'workspace.new',
47
+ 'workspace.focus',
48
+ 'workspace.close',
49
+ 'workspace.current',
50
+ 'surface.list',
51
+ 'surface.new',
52
+ 'surface.focus',
53
+ 'surface.close',
54
+ 'pane.list',
55
+ 'pane.focus',
56
+ 'pane.split',
57
+ 'input.send',
58
+ 'input.sendKey',
59
+ 'input.readScreen',
60
+ 'notify',
61
+ 'meta.setStatus',
62
+ 'meta.setProgress',
63
+ 'system.identify',
64
+ 'system.capabilities',
65
+ 'browser.open',
66
+ 'browser.snapshot',
67
+ 'browser.click',
68
+ 'browser.fill',
69
+ 'browser.eval',
70
+ 'browser.navigate',
71
+ ] as const satisfies readonly RpcMethod[];
@@ -0,0 +1,176 @@
1
+ // === Surface: a single terminal instance within a Pane ===
2
+ export interface Surface {
3
+ id: string;
4
+ ptyId: string;
5
+ title: string;
6
+ shell: string;
7
+ cwd: string;
8
+ surfaceType?: 'terminal' | 'browser';
9
+ browserUrl?: string;
10
+ }
11
+
12
+ // === Pane: either a leaf (has surfaces) or a branch (has children) ===
13
+ export interface PaneLeaf {
14
+ id: string;
15
+ type: 'leaf';
16
+ surfaces: Surface[];
17
+ activeSurfaceId: string;
18
+ }
19
+
20
+ export interface PaneBranch {
21
+ id: string;
22
+ type: 'branch';
23
+ direction: 'horizontal' | 'vertical';
24
+ children: Pane[];
25
+ sizes?: number[];
26
+ }
27
+
28
+ export type Pane = PaneLeaf | PaneBranch;
29
+
30
+ // === Workspace: a named collection of panes ===
31
+ export interface Workspace {
32
+ id: string;
33
+ name: string;
34
+ rootPane: Pane;
35
+ activePaneId: string;
36
+ metadata?: WorkspaceMetadata;
37
+ }
38
+
39
+ // === Notification ===
40
+ export type NotificationType = 'info' | 'warning' | 'error' | 'agent';
41
+
42
+ export interface Notification {
43
+ id: string;
44
+ surfaceId: string;
45
+ workspaceId: string;
46
+ type: NotificationType;
47
+ title: string;
48
+ body: string;
49
+ timestamp: number;
50
+ read: boolean;
51
+ }
52
+
53
+ // === Workspace Metadata ===
54
+ export interface WorkspaceMetadata {
55
+ gitBranch?: string;
56
+ cwd?: string;
57
+ listeningPorts?: number[];
58
+ lastNotification?: number;
59
+ status?: string;
60
+ progress?: number;
61
+ agentName?: string;
62
+ agentStatus?: AgentStatus;
63
+ }
64
+
65
+ // === Agent status ===
66
+ export type AgentStatus = 'running' | 'complete' | 'error' | 'waiting' | 'idle';
67
+
68
+ // === Status indicator colors ===
69
+ export type WorkspaceStatus = 'active' | 'idle' | 'error' | 'running';
70
+
71
+ // === Custom keybinding ===
72
+ export interface CustomKeybinding {
73
+ id: string;
74
+ key: string; // e.g. 'F7', 'Ctrl+Shift+1'
75
+ label: string; // user-defined name
76
+ command: string; // text to send to terminal
77
+ sendEnter: boolean; // append \n after command
78
+ }
79
+
80
+ // === Session: serialized app state ===
81
+ export interface SessionData {
82
+ workspaces: Workspace[];
83
+ activeWorkspaceId: string;
84
+ sidebarVisible: boolean;
85
+ // User preferences (persisted across restarts)
86
+ theme?: string;
87
+ locale?: string;
88
+ terminalFontSize?: number;
89
+ terminalFontFamily?: string;
90
+ defaultShell?: string;
91
+ scrollbackLines?: number;
92
+ sidebarPosition?: 'left' | 'right';
93
+ notificationSoundEnabled?: boolean;
94
+ toastEnabled?: boolean;
95
+ notificationRingEnabled?: boolean;
96
+ customKeybindings?: CustomKeybinding[];
97
+ }
98
+
99
+ // === Utility: generate unique IDs ===
100
+ export function generateId(prefix: string): string {
101
+ return `${prefix}-${crypto.randomUUID()}`;
102
+ }
103
+
104
+ // === Security: sanitize text before PTY write ===
105
+
106
+ /**
107
+ * Strips control characters (\r, \n, \x00-\x1f except \t) from text
108
+ * that will be written to a PTY, preventing embedded command injection.
109
+ */
110
+ export function sanitizePtyText(text: string): string {
111
+ // Remove all control chars except tab (\x09)
112
+ // eslint-disable-next-line no-control-regex
113
+ return text.replace(/[\x00-\x08\x0a-\x1f\x7f\u0080-\u009f]/g, '');
114
+ }
115
+
116
+ /**
117
+ * Validates and clamps a user-supplied name string.
118
+ * Returns the trimmed string if valid, or throws if invalid.
119
+ */
120
+ export function validateName(value: string, label: string, maxLength = 100): string {
121
+ const trimmed = value.trim();
122
+ if (trimmed.length === 0) {
123
+ throw new Error(`${label} must not be empty`);
124
+ }
125
+ if (trimmed.length > maxLength) {
126
+ throw new Error(`${label} must be ${maxLength} characters or fewer`);
127
+ }
128
+ return trimmed;
129
+ }
130
+
131
+ /**
132
+ * Validates a message body string.
133
+ * Returns the trimmed string if valid, or throws if invalid.
134
+ */
135
+ export function validateMessage(value: string, maxLength = 10000): string {
136
+ const trimmed = value.trim();
137
+ if (trimmed.length === 0) {
138
+ throw new Error('Message must not be empty');
139
+ }
140
+ if (trimmed.length > maxLength) {
141
+ throw new Error(`Message must be ${maxLength} characters or fewer`);
142
+ }
143
+ return trimmed;
144
+ }
145
+
146
+ // === Factory functions ===
147
+ export function createSurface(ptyId: string, shell: string, cwd: string): Surface {
148
+ return {
149
+ id: generateId('surface'),
150
+ ptyId,
151
+ title: shell,
152
+ shell,
153
+ cwd,
154
+ };
155
+ }
156
+
157
+ export function createLeafPane(surface?: Surface): PaneLeaf {
158
+ const surfaces = surface ? [surface] : [];
159
+ return {
160
+ id: generateId('pane'),
161
+ type: 'leaf',
162
+ surfaces,
163
+ activeSurfaceId: surfaces[0]?.id || '',
164
+ };
165
+ }
166
+
167
+ export function createWorkspace(name: string): Workspace {
168
+ const rootPane = createLeafPane();
169
+ return {
170
+ id: generateId('ws'),
171
+ name,
172
+ rootPane,
173
+ activePaneId: rootPane.id,
174
+ };
175
+ }
176
+
@@ -0,0 +1,11 @@
1
+ /** @type {import('tailwindcss').Config} */
2
+ module.exports = {
3
+ content: [
4
+ './index.html',
5
+ './src/renderer/**/*.{ts,tsx}',
6
+ ],
7
+ theme: {
8
+ extend: {},
9
+ },
10
+ plugins: [],
11
+ };
@@ -0,0 +1,24 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "target": "ES2020",
5
+ "module": "commonjs",
6
+ "moduleResolution": "node",
7
+ "outDir": "dist/cli",
8
+ "rootDir": "src",
9
+ "declaration": false,
10
+ "sourceMap": false
11
+ },
12
+ "include": [
13
+ "src/cli/**/*",
14
+ "src/shared/rpc.ts",
15
+ "src/shared/constants.ts",
16
+ "src/shared/types.ts"
17
+ ],
18
+ "exclude": [
19
+ "node_modules",
20
+ "src/main/**/*",
21
+ "src/renderer/**/*",
22
+ "src/preload/**/*"
23
+ ]
24
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,21 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ESNext",
4
+ "module": "commonjs",
5
+ "allowJs": true,
6
+ "skipLibCheck": true,
7
+ "esModuleInterop": true,
8
+ "noImplicitAny": true,
9
+ "sourceMap": true,
10
+ "baseUrl": ".",
11
+ "outDir": "dist",
12
+ "moduleResolution": "node",
13
+ "resolveJsonModule": true,
14
+ "jsx": "react-jsx",
15
+ "strict": true,
16
+ "paths": {
17
+ "@shared/*": ["src/shared/*"]
18
+ }
19
+ },
20
+ "include": ["src/**/*", "forge.env.d.ts"]
21
+ }
@@ -0,0 +1,25 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "target": "ES2020",
5
+ "module": "commonjs",
6
+ "moduleResolution": "node",
7
+ "outDir": "dist/mcp",
8
+ "rootDir": "src",
9
+ "declaration": false,
10
+ "sourceMap": false
11
+ },
12
+ "include": [
13
+ "src/mcp/**/*",
14
+ "src/shared/rpc.ts",
15
+ "src/shared/constants.ts",
16
+ "src/shared/types.ts"
17
+ ],
18
+ "exclude": [
19
+ "node_modules",
20
+ "src/main/**/*",
21
+ "src/renderer/**/*",
22
+ "src/preload/**/*",
23
+ "src/cli/**/*"
24
+ ]
25
+ }
@@ -0,0 +1,14 @@
1
+ import { defineConfig } from 'vite';
2
+
3
+ export default defineConfig({
4
+ resolve: {
5
+ browserField: false,
6
+ conditions: ['node'],
7
+ mainFields: ['module', 'jsnext:main', 'jsnext'],
8
+ },
9
+ build: {
10
+ rollupOptions: {
11
+ external: ['node-pty'],
12
+ },
13
+ },
14
+ });
@@ -0,0 +1,9 @@
1
+ import { defineConfig } from 'vite';
2
+
3
+ export default defineConfig({
4
+ resolve: {
5
+ browserField: false,
6
+ conditions: ['node'],
7
+ mainFields: ['module', 'jsnext:main', 'jsnext'],
8
+ },
9
+ });
@@ -0,0 +1,6 @@
1
+ import { defineConfig } from 'vite';
2
+ import react from '@vitejs/plugin-react';
3
+
4
+ export default defineConfig({
5
+ plugins: [react()],
6
+ });