@wangyaoshen/remux 0.3.8-dev.29e114b

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 (183) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.md +47 -0
  2. package/.github/ISSUE_TEMPLATE/feature_request.md +38 -0
  3. package/.github/PULL_REQUEST_TEMPLATE.md +28 -0
  4. package/.github/dependabot.yml +33 -0
  5. package/.github/workflows/ci.yml +65 -0
  6. package/.github/workflows/deploy.yml +65 -0
  7. package/.github/workflows/publish.yml +312 -0
  8. package/.github/workflows/release-please.yml +21 -0
  9. package/.gitmodules +3 -0
  10. package/.nvmrc +1 -0
  11. package/.release-please-manifest.json +3 -0
  12. package/CLAUDE.md +104 -0
  13. package/Dockerfile +23 -0
  14. package/LICENSE +21 -0
  15. package/README.md +120 -0
  16. package/apps/ios/Config/signing.xcconfig +4 -0
  17. package/apps/ios/Package.swift +26 -0
  18. package/apps/ios/Remux.xcodeproj/project.pbxproj +477 -0
  19. package/apps/ios/Remux.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
  20. package/apps/ios/Sources/Remux/Assets.xcassets/AppIcon.appiconset/Contents.json +23 -0
  21. package/apps/ios/Sources/Remux/Assets.xcassets/AppIcon.appiconset/icon_1024x1024.png +0 -0
  22. package/apps/ios/Sources/Remux/Assets.xcassets/AppIcon.appiconset/icon_120x120.png +0 -0
  23. package/apps/ios/Sources/Remux/Assets.xcassets/AppIcon.appiconset/icon_152x152.png +0 -0
  24. package/apps/ios/Sources/Remux/Assets.xcassets/AppIcon.appiconset/icon_167x167.png +0 -0
  25. package/apps/ios/Sources/Remux/Assets.xcassets/AppIcon.appiconset/icon_180x180.png +0 -0
  26. package/apps/ios/Sources/Remux/Assets.xcassets/AppIcon.appiconset/icon_20x20.png +0 -0
  27. package/apps/ios/Sources/Remux/Assets.xcassets/AppIcon.appiconset/icon_29x29.png +0 -0
  28. package/apps/ios/Sources/Remux/Assets.xcassets/AppIcon.appiconset/icon_40x40.png +0 -0
  29. package/apps/ios/Sources/Remux/Assets.xcassets/AppIcon.appiconset/icon_58x58.png +0 -0
  30. package/apps/ios/Sources/Remux/Assets.xcassets/AppIcon.appiconset/icon_60x60.png +0 -0
  31. package/apps/ios/Sources/Remux/Assets.xcassets/AppIcon.appiconset/icon_76x76.png +0 -0
  32. package/apps/ios/Sources/Remux/Assets.xcassets/AppIcon.appiconset/icon_80x80.png +0 -0
  33. package/apps/ios/Sources/Remux/Assets.xcassets/AppIcon.appiconset/icon_87x87.png +0 -0
  34. package/apps/ios/Sources/Remux/Assets.xcassets/Contents.json +6 -0
  35. package/apps/ios/Sources/Remux/Extensions/FaceIDManager.swift +29 -0
  36. package/apps/ios/Sources/Remux/Extensions/InspectCache.swift +66 -0
  37. package/apps/ios/Sources/Remux/MainTabView.swift +32 -0
  38. package/apps/ios/Sources/Remux/Remux.entitlements +8 -0
  39. package/apps/ios/Sources/Remux/RemuxiOSApp.swift +14 -0
  40. package/apps/ios/Sources/Remux/RootView.swift +130 -0
  41. package/apps/ios/Sources/Remux/Views/Control/ControlView.swift +102 -0
  42. package/apps/ios/Sources/Remux/Views/Inspect/InspectView.swift +98 -0
  43. package/apps/ios/Sources/Remux/Views/Live/LiveTerminalView.swift +132 -0
  44. package/apps/ios/Sources/Remux/Views/Now/NowView.swift +173 -0
  45. package/apps/ios/Sources/Remux/Views/Onboarding/ManualConnectView.swift +55 -0
  46. package/apps/ios/Sources/Remux/Views/Onboarding/OnboardingView.swift +70 -0
  47. package/apps/ios/Sources/Remux/Views/Onboarding/QRScannerView.swift +92 -0
  48. package/apps/ios/Sources/Remux/Views/Settings/MeView.swift +136 -0
  49. package/apps/macos/Package.swift +37 -0
  50. package/apps/macos/Resources/shell-integration/bash/bash-preexec.sh +382 -0
  51. package/apps/macos/Resources/shell-integration/bash/ghostty.bash +315 -0
  52. package/apps/macos/Resources/shell-integration/elvish/lib/ghostty-integration.elv +191 -0
  53. package/apps/macos/Resources/shell-integration/fish/vendor_conf.d/ghostty-shell-integration.fish +246 -0
  54. package/apps/macos/Resources/shell-integration/nushell/vendor/autoload/ghostty.nu +110 -0
  55. package/apps/macos/Resources/shell-integration/zsh/.zshenv +61 -0
  56. package/apps/macos/Resources/shell-integration/zsh/ghostty-integration +458 -0
  57. package/apps/macos/Resources/terminfo/67/ghostty +0 -0
  58. package/apps/macos/Resources/terminfo/78/xterm-ghostty +0 -0
  59. package/apps/macos/Sources/Remux/AppDelegate.swift +257 -0
  60. package/apps/macos/Sources/Remux/CrashReporter.swift +210 -0
  61. package/apps/macos/Sources/Remux/FinderIntegration.swift +117 -0
  62. package/apps/macos/Sources/Remux/GhosttyConfig.swift +311 -0
  63. package/apps/macos/Sources/Remux/KeyboardShortcuts/ShortcutAction.swift +115 -0
  64. package/apps/macos/Sources/Remux/KeyboardShortcuts/ShortcutSettingsView.swift +271 -0
  65. package/apps/macos/Sources/Remux/KeyboardShortcuts/StoredShortcut.swift +149 -0
  66. package/apps/macos/Sources/Remux/MainContentView.swift +308 -0
  67. package/apps/macos/Sources/Remux/MenuBarManager.swift +275 -0
  68. package/apps/macos/Sources/Remux/NotificationManager.swift +145 -0
  69. package/apps/macos/Sources/Remux/PortScanner.swift +152 -0
  70. package/apps/macos/Sources/Remux/RemuxApp.swift +13 -0
  71. package/apps/macos/Sources/Remux/SSHDetector.swift +151 -0
  72. package/apps/macos/Sources/Remux/SessionPersistence.swift +226 -0
  73. package/apps/macos/Sources/Remux/SocketController.swift +258 -0
  74. package/apps/macos/Sources/Remux/UpdateChecker.swift +152 -0
  75. package/apps/macos/Sources/Remux/Views/CommandPalette.swift +198 -0
  76. package/apps/macos/Sources/Remux/Views/ConnectionView.swift +84 -0
  77. package/apps/macos/Sources/Remux/Views/InspectView.swift +127 -0
  78. package/apps/macos/Sources/Remux/Views/SettingsView.swift +77 -0
  79. package/apps/macos/Sources/Remux/Views/Sidebar/SidebarView.swift +410 -0
  80. package/apps/macos/Sources/Remux/Views/SplitTree/BrowserPanel.swift +193 -0
  81. package/apps/macos/Sources/Remux/Views/SplitTree/MarkdownPanel.swift +277 -0
  82. package/apps/macos/Sources/Remux/Views/SplitTree/PanelProtocol.swift +14 -0
  83. package/apps/macos/Sources/Remux/Views/SplitTree/SplitNode.swift +149 -0
  84. package/apps/macos/Sources/Remux/Views/SplitTree/SplitView.swift +234 -0
  85. package/apps/macos/Sources/Remux/Views/SplitTree/TerminalPanel.swift +26 -0
  86. package/apps/macos/Sources/Remux/Views/TabBarView.swift +94 -0
  87. package/apps/macos/Sources/Remux/Views/Terminal/ClipboardHelper.swift +101 -0
  88. package/apps/macos/Sources/Remux/Views/Terminal/CopyModeOverlay.swift +325 -0
  89. package/apps/macos/Sources/Remux/Views/Terminal/GhosttyNativeTerminalView.swift +39 -0
  90. package/apps/macos/Sources/Remux/Views/Terminal/GhosttyNativeView.swift +559 -0
  91. package/apps/macos/Sources/Remux/Views/Terminal/SurfaceSearchOverlay.swift +109 -0
  92. package/apps/macos/Sources/Remux/Views/Terminal/TerminalContainerView.swift +95 -0
  93. package/apps/macos/Sources/Remux/Views/Terminal/TerminalRelay.swift +117 -0
  94. package/build.mjs +33 -0
  95. package/native/android/DecodeGoldenPayloads.kt +487 -0
  96. package/native/android/ProtocolModels.kt +188 -0
  97. package/native/ios/DecodeGoldenPayloads.swift +711 -0
  98. package/native/ios/ProtocolModels.swift +200 -0
  99. package/package.json +45 -0
  100. package/packages/RemuxKit/Package.swift +27 -0
  101. package/packages/RemuxKit/Sources/RemuxKit/Device/DeviceManager.swift +27 -0
  102. package/packages/RemuxKit/Sources/RemuxKit/Models/ProtocolModels.swift +206 -0
  103. package/packages/RemuxKit/Sources/RemuxKit/Networking/MessageRouter.swift +108 -0
  104. package/packages/RemuxKit/Sources/RemuxKit/Networking/RemuxConnection.swift +395 -0
  105. package/packages/RemuxKit/Sources/RemuxKit/State/RemuxState.swift +188 -0
  106. package/packages/RemuxKit/Sources/RemuxKit/Storage/KeychainStore.swift +142 -0
  107. package/packages/RemuxKit/Sources/RemuxKit/Terminal/GhosttyBridge.swift +145 -0
  108. package/packages/RemuxKit/Sources/RemuxKit/Terminal/GhosttyTerminalView.swift +35 -0
  109. package/packages/RemuxKit/Sources/RemuxKit/Terminal/Resources/ghostty-terminal.html +91 -0
  110. package/packages/RemuxKit/Tests/RemuxKitTests/ConnectionIntegrationTest.swift +74 -0
  111. package/packages/RemuxKit/Tests/RemuxKitTests/KeychainStoreTests.swift +81 -0
  112. package/packages/RemuxKit/Tests/RemuxKitTests/ProtocolModelsTests.swift +179 -0
  113. package/packages/RemuxKit/Tests/RemuxKitTests/RemuxStateTests.swift +62 -0
  114. package/playwright.config.ts +17 -0
  115. package/pnpm-lock.yaml +1588 -0
  116. package/pty-daemon.js +303 -0
  117. package/release-please-config.json +14 -0
  118. package/scripts/auto-deploy.sh +46 -0
  119. package/scripts/build-dmg.sh +121 -0
  120. package/scripts/build-ghostty-kit.sh +43 -0
  121. package/scripts/check-active-terminology.mjs +132 -0
  122. package/scripts/setup-ci-secrets.sh +80 -0
  123. package/scripts/sync-ghostty-web.sh +28 -0
  124. package/scripts/upload-testflight.sh +100 -0
  125. package/server.js +7074 -0
  126. package/src/adapters/agent-events.ts +246 -0
  127. package/src/adapters/claude-code.ts +158 -0
  128. package/src/adapters/codex.ts +210 -0
  129. package/src/adapters/generic-shell.ts +58 -0
  130. package/src/adapters/index.ts +15 -0
  131. package/src/adapters/registry.ts +99 -0
  132. package/src/adapters/types.ts +41 -0
  133. package/src/auth.ts +174 -0
  134. package/src/e2ee.ts +236 -0
  135. package/src/git-service.ts +168 -0
  136. package/src/message-buffer.ts +137 -0
  137. package/src/pty-daemon.ts +357 -0
  138. package/src/push.ts +127 -0
  139. package/src/renderers.ts +455 -0
  140. package/src/server.ts +2407 -0
  141. package/src/service.ts +226 -0
  142. package/src/session.ts +978 -0
  143. package/src/store.ts +1422 -0
  144. package/src/team.ts +123 -0
  145. package/src/tunnel.ts +126 -0
  146. package/src/types.d.ts +50 -0
  147. package/src/vt-tracker.ts +188 -0
  148. package/src/workspace-head.ts +144 -0
  149. package/src/workspace.ts +153 -0
  150. package/src/ws-handler.ts +1526 -0
  151. package/start.ps1 +83 -0
  152. package/tests/adapters.test.js +171 -0
  153. package/tests/auth.test.js +243 -0
  154. package/tests/codex-adapter.test.js +535 -0
  155. package/tests/durable-stream.test.js +153 -0
  156. package/tests/e2e/app.spec.js +530 -0
  157. package/tests/e2ee.test.js +325 -0
  158. package/tests/message-buffer.test.js +245 -0
  159. package/tests/message-routing.test.js +305 -0
  160. package/tests/pty-daemon.test.js +346 -0
  161. package/tests/push.test.js +281 -0
  162. package/tests/renderers.test.js +391 -0
  163. package/tests/search-shell.test.js +499 -0
  164. package/tests/server.test.js +882 -0
  165. package/tests/service.test.js +267 -0
  166. package/tests/store.test.js +369 -0
  167. package/tests/tunnel.test.js +67 -0
  168. package/tests/workspace-head.test.js +116 -0
  169. package/tests/workspace.test.js +417 -0
  170. package/tsconfig.backend.json +11 -0
  171. package/tsconfig.json +15 -0
  172. package/tui/client/client_test.go +125 -0
  173. package/tui/client/connection.go +342 -0
  174. package/tui/client/host_manager.go +141 -0
  175. package/tui/config/cache.go +81 -0
  176. package/tui/config/config.go +53 -0
  177. package/tui/config/config_test.go +89 -0
  178. package/tui/go.mod +32 -0
  179. package/tui/go.sum +50 -0
  180. package/tui/main.go +261 -0
  181. package/tui/tests/integration_test.go +283 -0
  182. package/tui/ui/model.go +310 -0
  183. package/vitest.config.js +10 -0
package/src/service.ts ADDED
@@ -0,0 +1,226 @@
1
+ /**
2
+ * Launchd service management for Remux.
3
+ * Provides install/uninstall/status for macOS background service.
4
+ *
5
+ * Plist goes to ~/Library/LaunchAgents/com.remux.agent.plist
6
+ * Logs go to ~/.remux/logs/
7
+ *
8
+ * Inspired by Homebrew's launchd service pattern and similar projects
9
+ * (e.g. remodex) that use launchd for daemon management.
10
+ */
11
+
12
+ import fs from "fs";
13
+ import path from "path";
14
+ import { homedir } from "os";
15
+ import { execSync } from "child_process";
16
+ import { fileURLToPath } from "url";
17
+
18
+ const __filename = fileURLToPath(import.meta.url);
19
+ const __dirname = path.dirname(__filename);
20
+
21
+ export const LABEL = "com.remux.agent";
22
+ export const PLIST_DIR = path.join(homedir(), "Library", "LaunchAgents");
23
+ export const PLIST_PATH = path.join(PLIST_DIR, `${LABEL}.plist`);
24
+ export const LOG_DIR = path.join(homedir(), ".remux", "logs");
25
+ export const SERVER_JS = path.join(__dirname, "server.js");
26
+
27
+ function escapeXml(str: string): string {
28
+ return str
29
+ .replace(/&/g, "&")
30
+ .replace(/</g, "&lt;")
31
+ .replace(/>/g, "&gt;")
32
+ .replace(/"/g, "&quot;")
33
+ .replace(/'/g, "&apos;");
34
+ }
35
+
36
+ /**
37
+ * Generate launchd plist XML content.
38
+ */
39
+ export function generatePlist(options: {
40
+ port?: number;
41
+ args?: string[];
42
+ } = {}): string {
43
+ const { port, args = [] } = options;
44
+
45
+ const programArgs = [process.execPath, SERVER_JS, ...args];
46
+ const programArgsXml = programArgs
47
+ .map((a) => ` <string>${escapeXml(a)}</string>`)
48
+ .join("\n");
49
+
50
+ // Build EnvironmentVariables section
51
+ const envVars: Record<string, string> = {};
52
+ if (port) envVars.PORT = String(port);
53
+ if (process.env.REMUX_TOKEN) envVars.REMUX_TOKEN = process.env.REMUX_TOKEN;
54
+
55
+ let envXml = "";
56
+ if (Object.keys(envVars).length > 0) {
57
+ const entries = Object.entries(envVars)
58
+ .map(
59
+ ([k, v]) =>
60
+ ` <key>${escapeXml(k)}</key>\n <string>${escapeXml(v)}</string>`,
61
+ )
62
+ .join("\n");
63
+ envXml = `
64
+ <key>EnvironmentVariables</key>
65
+ <dict>
66
+ ${entries}
67
+ </dict>`;
68
+ }
69
+
70
+ return `<?xml version="1.0" encoding="UTF-8"?>
71
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
72
+ <plist version="1.0">
73
+ <dict>
74
+ <key>Label</key>
75
+ <string>${LABEL}</string>
76
+ <key>ProgramArguments</key>
77
+ <array>
78
+ ${programArgsXml}
79
+ </array>
80
+ <key>RunAtLoad</key>
81
+ <true/>
82
+ <key>KeepAlive</key>
83
+ <true/>
84
+ <key>WorkingDirectory</key>
85
+ <string>${escapeXml(__dirname)}</string>
86
+ <key>StandardOutPath</key>
87
+ <string>${escapeXml(path.join(LOG_DIR, "remux.log"))}</string>
88
+ <key>StandardErrorPath</key>
89
+ <string>${escapeXml(path.join(LOG_DIR, "remux.err"))}</string>${envXml}
90
+ </dict>
91
+ </plist>
92
+ `;
93
+ }
94
+
95
+ /**
96
+ * Install and start the launchd service.
97
+ */
98
+ export function installService(options: {
99
+ port?: number;
100
+ args?: string[];
101
+ } = {}): void {
102
+ // Create log directory
103
+ fs.mkdirSync(LOG_DIR, { recursive: true });
104
+
105
+ // Unload existing service if present
106
+ if (fs.existsSync(PLIST_PATH)) {
107
+ try {
108
+ execSync(`launchctl unload "${PLIST_PATH}"`, { stdio: "pipe" });
109
+ } catch {
110
+ // May fail if not loaded, that's fine
111
+ }
112
+ }
113
+
114
+ // Write plist
115
+ const xml = generatePlist(options);
116
+ fs.writeFileSync(PLIST_PATH, xml);
117
+
118
+ // Load service
119
+ execSync(`launchctl load "${PLIST_PATH}"`, { stdio: "pipe" });
120
+
121
+ console.log(`[remux] Service installed and started.`);
122
+ console.log(`[remux] Plist: ${PLIST_PATH}`);
123
+ console.log(`[remux] Logs: ${LOG_DIR}/`);
124
+ }
125
+
126
+ /**
127
+ * Uninstall the launchd service.
128
+ */
129
+ export function uninstallService(): void {
130
+ if (!fs.existsSync(PLIST_PATH)) {
131
+ console.log(`[remux] Service is not installed.`);
132
+ return;
133
+ }
134
+
135
+ try {
136
+ execSync(`launchctl unload "${PLIST_PATH}"`, { stdio: "pipe" });
137
+ } catch {
138
+ // May fail if not loaded
139
+ }
140
+
141
+ fs.unlinkSync(PLIST_PATH);
142
+ console.log(`[remux] Service uninstalled.`);
143
+ }
144
+
145
+ /**
146
+ * Check service status.
147
+ */
148
+ export function serviceStatus(): {
149
+ installed: boolean;
150
+ running: boolean;
151
+ pid?: number;
152
+ } {
153
+ if (!fs.existsSync(PLIST_PATH)) {
154
+ return { installed: false, running: false };
155
+ }
156
+
157
+ try {
158
+ const output = execSync(`launchctl list ${LABEL}`, {
159
+ stdio: "pipe",
160
+ encoding: "utf8",
161
+ });
162
+ // Output format: "PID\tStatus\tLabel"
163
+ // PID is a number if running, "-" if not
164
+ const firstLine = output.trim().split("\n").pop();
165
+ const pid = firstLine?.split("\t")[0];
166
+ if (pid && pid !== "-" && !isNaN(Number(pid))) {
167
+ return { installed: true, running: true, pid: Number(pid) };
168
+ }
169
+ return { installed: true, running: false };
170
+ } catch {
171
+ return { installed: true, running: false };
172
+ }
173
+ }
174
+
175
+ /**
176
+ * Handle `remux service <subcommand>` from argv.
177
+ * Returns true if a service command was handled (caller should exit).
178
+ */
179
+ export function handleServiceCommand(argv: string[]): boolean {
180
+ // argv[0] = node, argv[1] = server.js, argv[2] = "service"
181
+ if (argv.length < 4 || argv[2] !== "service") return false;
182
+
183
+ const subcommand = argv[3];
184
+
185
+ switch (subcommand) {
186
+ case "install": {
187
+ const opts: { port?: number; args?: string[] } = {};
188
+ const portIdx = argv.indexOf("--port");
189
+ if (portIdx !== -1 && argv[portIdx + 1]) {
190
+ opts.port = Number(argv[portIdx + 1]);
191
+ }
192
+ // Collect extra args after install (excluding --port N)
193
+ const extra: string[] = [];
194
+ for (let i = 4; i < argv.length; i++) {
195
+ if (argv[i] === "--port") {
196
+ i++; // skip value
197
+ continue;
198
+ }
199
+ extra.push(argv[i]);
200
+ }
201
+ if (extra.length) opts.args = extra;
202
+ installService(opts);
203
+ return true;
204
+ }
205
+ case "uninstall":
206
+ uninstallService();
207
+ return true;
208
+ case "status": {
209
+ const st = serviceStatus();
210
+ if (!st.installed) {
211
+ console.log("[remux] Service is not installed.");
212
+ } else if (st.running) {
213
+ console.log(`[remux] Service is running (PID ${st.pid}).`);
214
+ } else {
215
+ console.log("[remux] Service is installed but not running.");
216
+ }
217
+ return true;
218
+ }
219
+ default:
220
+ console.error(
221
+ `[remux] Unknown service command: ${subcommand}\n` +
222
+ `Usage: remux service <install|uninstall|status>`,
223
+ );
224
+ return true;
225
+ }
226
+ }