@wangyaoshen/remux 0.3.8-dev.a8ceb0c
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/.github/ISSUE_TEMPLATE/bug_report.md +47 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +38 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +28 -0
- package/.github/dependabot.yml +33 -0
- package/.github/workflows/ci.yml +65 -0
- package/.github/workflows/deploy.yml +65 -0
- package/.github/workflows/publish.yml +312 -0
- package/.github/workflows/release-please.yml +21 -0
- package/.gitmodules +3 -0
- package/.nvmrc +1 -0
- package/.release-please-manifest.json +3 -0
- package/CLAUDE.md +104 -0
- package/Dockerfile +23 -0
- package/LICENSE +21 -0
- package/README.md +120 -0
- package/apps/ios/Config/signing.xcconfig +4 -0
- package/apps/ios/Package.swift +26 -0
- package/apps/ios/Remux.xcodeproj/project.pbxproj +477 -0
- package/apps/ios/Remux.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
- package/apps/ios/Sources/Remux/Assets.xcassets/AppIcon.appiconset/Contents.json +23 -0
- package/apps/ios/Sources/Remux/Assets.xcassets/AppIcon.appiconset/icon_1024x1024.png +0 -0
- package/apps/ios/Sources/Remux/Assets.xcassets/AppIcon.appiconset/icon_120x120.png +0 -0
- package/apps/ios/Sources/Remux/Assets.xcassets/AppIcon.appiconset/icon_152x152.png +0 -0
- package/apps/ios/Sources/Remux/Assets.xcassets/AppIcon.appiconset/icon_167x167.png +0 -0
- package/apps/ios/Sources/Remux/Assets.xcassets/AppIcon.appiconset/icon_180x180.png +0 -0
- package/apps/ios/Sources/Remux/Assets.xcassets/AppIcon.appiconset/icon_20x20.png +0 -0
- package/apps/ios/Sources/Remux/Assets.xcassets/AppIcon.appiconset/icon_29x29.png +0 -0
- package/apps/ios/Sources/Remux/Assets.xcassets/AppIcon.appiconset/icon_40x40.png +0 -0
- package/apps/ios/Sources/Remux/Assets.xcassets/AppIcon.appiconset/icon_58x58.png +0 -0
- package/apps/ios/Sources/Remux/Assets.xcassets/AppIcon.appiconset/icon_60x60.png +0 -0
- package/apps/ios/Sources/Remux/Assets.xcassets/AppIcon.appiconset/icon_76x76.png +0 -0
- package/apps/ios/Sources/Remux/Assets.xcassets/AppIcon.appiconset/icon_80x80.png +0 -0
- package/apps/ios/Sources/Remux/Assets.xcassets/AppIcon.appiconset/icon_87x87.png +0 -0
- package/apps/ios/Sources/Remux/Assets.xcassets/Contents.json +6 -0
- package/apps/ios/Sources/Remux/Extensions/FaceIDManager.swift +29 -0
- package/apps/ios/Sources/Remux/Extensions/InspectCache.swift +66 -0
- package/apps/ios/Sources/Remux/MainTabView.swift +32 -0
- package/apps/ios/Sources/Remux/Remux.entitlements +8 -0
- package/apps/ios/Sources/Remux/RemuxiOSApp.swift +14 -0
- package/apps/ios/Sources/Remux/RootView.swift +130 -0
- package/apps/ios/Sources/Remux/Views/Control/ControlView.swift +102 -0
- package/apps/ios/Sources/Remux/Views/Inspect/InspectView.swift +98 -0
- package/apps/ios/Sources/Remux/Views/Live/LiveTerminalView.swift +132 -0
- package/apps/ios/Sources/Remux/Views/Now/NowView.swift +173 -0
- package/apps/ios/Sources/Remux/Views/Onboarding/ManualConnectView.swift +55 -0
- package/apps/ios/Sources/Remux/Views/Onboarding/OnboardingView.swift +70 -0
- package/apps/ios/Sources/Remux/Views/Onboarding/QRScannerView.swift +92 -0
- package/apps/ios/Sources/Remux/Views/Settings/MeView.swift +136 -0
- package/apps/macos/Package.swift +37 -0
- package/apps/macos/Resources/shell-integration/bash/bash-preexec.sh +382 -0
- package/apps/macos/Resources/shell-integration/bash/ghostty.bash +315 -0
- package/apps/macos/Resources/shell-integration/elvish/lib/ghostty-integration.elv +191 -0
- package/apps/macos/Resources/shell-integration/fish/vendor_conf.d/ghostty-shell-integration.fish +246 -0
- package/apps/macos/Resources/shell-integration/nushell/vendor/autoload/ghostty.nu +110 -0
- package/apps/macos/Resources/shell-integration/zsh/.zshenv +61 -0
- package/apps/macos/Resources/shell-integration/zsh/ghostty-integration +458 -0
- package/apps/macos/Resources/terminfo/67/ghostty +0 -0
- package/apps/macos/Resources/terminfo/78/xterm-ghostty +0 -0
- package/apps/macos/Sources/Remux/AppDelegate.swift +257 -0
- package/apps/macos/Sources/Remux/CrashReporter.swift +210 -0
- package/apps/macos/Sources/Remux/FinderIntegration.swift +117 -0
- package/apps/macos/Sources/Remux/GhosttyConfig.swift +311 -0
- package/apps/macos/Sources/Remux/KeyboardShortcuts/ShortcutAction.swift +115 -0
- package/apps/macos/Sources/Remux/KeyboardShortcuts/ShortcutSettingsView.swift +271 -0
- package/apps/macos/Sources/Remux/KeyboardShortcuts/StoredShortcut.swift +149 -0
- package/apps/macos/Sources/Remux/MainContentView.swift +308 -0
- package/apps/macos/Sources/Remux/MenuBarManager.swift +275 -0
- package/apps/macos/Sources/Remux/NotificationManager.swift +145 -0
- package/apps/macos/Sources/Remux/PortScanner.swift +152 -0
- package/apps/macos/Sources/Remux/RemuxApp.swift +13 -0
- package/apps/macos/Sources/Remux/SSHDetector.swift +151 -0
- package/apps/macos/Sources/Remux/SessionPersistence.swift +226 -0
- package/apps/macos/Sources/Remux/SocketController.swift +258 -0
- package/apps/macos/Sources/Remux/UpdateChecker.swift +152 -0
- package/apps/macos/Sources/Remux/Views/CommandPalette.swift +198 -0
- package/apps/macos/Sources/Remux/Views/ConnectionView.swift +84 -0
- package/apps/macos/Sources/Remux/Views/InspectView.swift +127 -0
- package/apps/macos/Sources/Remux/Views/SettingsView.swift +77 -0
- package/apps/macos/Sources/Remux/Views/Sidebar/SidebarView.swift +410 -0
- package/apps/macos/Sources/Remux/Views/SplitTree/BrowserPanel.swift +193 -0
- package/apps/macos/Sources/Remux/Views/SplitTree/MarkdownPanel.swift +277 -0
- package/apps/macos/Sources/Remux/Views/SplitTree/PanelProtocol.swift +14 -0
- package/apps/macos/Sources/Remux/Views/SplitTree/SplitNode.swift +149 -0
- package/apps/macos/Sources/Remux/Views/SplitTree/SplitView.swift +234 -0
- package/apps/macos/Sources/Remux/Views/SplitTree/TerminalPanel.swift +26 -0
- package/apps/macos/Sources/Remux/Views/TabBarView.swift +94 -0
- package/apps/macos/Sources/Remux/Views/Terminal/ClipboardHelper.swift +101 -0
- package/apps/macos/Sources/Remux/Views/Terminal/CopyModeOverlay.swift +325 -0
- package/apps/macos/Sources/Remux/Views/Terminal/GhosttyNativeTerminalView.swift +39 -0
- package/apps/macos/Sources/Remux/Views/Terminal/GhosttyNativeView.swift +559 -0
- package/apps/macos/Sources/Remux/Views/Terminal/SurfaceSearchOverlay.swift +109 -0
- package/apps/macos/Sources/Remux/Views/Terminal/TerminalContainerView.swift +95 -0
- package/apps/macos/Sources/Remux/Views/Terminal/TerminalRelay.swift +117 -0
- package/build.mjs +33 -0
- package/native/android/DecodeGoldenPayloads.kt +487 -0
- package/native/android/ProtocolModels.kt +188 -0
- package/native/ios/DecodeGoldenPayloads.swift +711 -0
- package/native/ios/ProtocolModels.swift +200 -0
- package/package.json +45 -0
- package/packages/RemuxKit/Package.swift +27 -0
- package/packages/RemuxKit/Sources/RemuxKit/Device/DeviceManager.swift +27 -0
- package/packages/RemuxKit/Sources/RemuxKit/Models/ProtocolModels.swift +206 -0
- package/packages/RemuxKit/Sources/RemuxKit/Networking/MessageRouter.swift +108 -0
- package/packages/RemuxKit/Sources/RemuxKit/Networking/RemuxConnection.swift +395 -0
- package/packages/RemuxKit/Sources/RemuxKit/State/RemuxState.swift +188 -0
- package/packages/RemuxKit/Sources/RemuxKit/Storage/KeychainStore.swift +142 -0
- package/packages/RemuxKit/Sources/RemuxKit/Terminal/GhosttyBridge.swift +145 -0
- package/packages/RemuxKit/Sources/RemuxKit/Terminal/GhosttyTerminalView.swift +35 -0
- package/packages/RemuxKit/Sources/RemuxKit/Terminal/Resources/ghostty-terminal.html +91 -0
- package/packages/RemuxKit/Tests/RemuxKitTests/ConnectionIntegrationTest.swift +74 -0
- package/packages/RemuxKit/Tests/RemuxKitTests/KeychainStoreTests.swift +81 -0
- package/packages/RemuxKit/Tests/RemuxKitTests/ProtocolModelsTests.swift +179 -0
- package/packages/RemuxKit/Tests/RemuxKitTests/RemuxStateTests.swift +62 -0
- package/playwright.config.ts +17 -0
- package/pnpm-lock.yaml +1588 -0
- package/pty-daemon.js +303 -0
- package/release-please-config.json +14 -0
- package/scripts/auto-deploy.sh +46 -0
- package/scripts/build-dmg.sh +121 -0
- package/scripts/build-ghostty-kit.sh +43 -0
- package/scripts/check-active-terminology.mjs +132 -0
- package/scripts/setup-ci-secrets.sh +80 -0
- package/scripts/sync-ghostty-web.sh +28 -0
- package/scripts/upload-testflight.sh +100 -0
- package/server.js +7074 -0
- package/src/adapters/agent-events.ts +246 -0
- package/src/adapters/claude-code.ts +158 -0
- package/src/adapters/codex.ts +210 -0
- package/src/adapters/generic-shell.ts +58 -0
- package/src/adapters/index.ts +15 -0
- package/src/adapters/registry.ts +99 -0
- package/src/adapters/types.ts +41 -0
- package/src/auth.ts +174 -0
- package/src/e2ee.ts +236 -0
- package/src/git-service.ts +168 -0
- package/src/message-buffer.ts +137 -0
- package/src/pty-daemon.ts +357 -0
- package/src/push.ts +127 -0
- package/src/renderers.ts +455 -0
- package/src/server.ts +2407 -0
- package/src/service.ts +226 -0
- package/src/session.ts +978 -0
- package/src/store.ts +1422 -0
- package/src/team.ts +123 -0
- package/src/tunnel.ts +126 -0
- package/src/types.d.ts +50 -0
- package/src/vt-tracker.ts +188 -0
- package/src/workspace-head.ts +144 -0
- package/src/workspace.ts +153 -0
- package/src/ws-handler.ts +1526 -0
- package/start.ps1 +83 -0
- package/tests/adapters.test.js +171 -0
- package/tests/auth.test.js +243 -0
- package/tests/codex-adapter.test.js +535 -0
- package/tests/durable-stream.test.js +153 -0
- package/tests/e2e/app.spec.js +530 -0
- package/tests/e2ee.test.js +325 -0
- package/tests/message-buffer.test.js +245 -0
- package/tests/message-routing.test.js +305 -0
- package/tests/pty-daemon.test.js +346 -0
- package/tests/push.test.js +281 -0
- package/tests/renderers.test.js +391 -0
- package/tests/search-shell.test.js +499 -0
- package/tests/server.test.js +882 -0
- package/tests/service.test.js +267 -0
- package/tests/store.test.js +369 -0
- package/tests/tunnel.test.js +67 -0
- package/tests/workspace-head.test.js +116 -0
- package/tests/workspace.test.js +417 -0
- package/tsconfig.backend.json +11 -0
- package/tsconfig.json +15 -0
- package/tui/client/client_test.go +125 -0
- package/tui/client/connection.go +342 -0
- package/tui/client/host_manager.go +141 -0
- package/tui/config/cache.go +81 -0
- package/tui/config/config.go +53 -0
- package/tui/config/config_test.go +89 -0
- package/tui/go.mod +32 -0
- package/tui/go.sum +50 -0
- package/tui/main.go +261 -0
- package/tui/tests/integration_test.go +283 -0
- package/tui/ui/model.go +310 -0
- package/vitest.config.js +10 -0
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
public struct ProtocolCapabilities: Codable, Equatable {
|
|
2
|
+
public let envelope: Bool
|
|
3
|
+
public let inspectV2: Bool
|
|
4
|
+
public let deviceTrust: Bool
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
public struct AuthPayload: Codable, Equatable {
|
|
8
|
+
public let token: String
|
|
9
|
+
public let password: String?
|
|
10
|
+
public let cols: Int?
|
|
11
|
+
public let rows: Int?
|
|
12
|
+
public let capabilities: ProtocolCapabilities?
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
public struct AuthOkPayload: Codable, Equatable {
|
|
16
|
+
public let capabilities: ProtocolCapabilities
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
public struct AuthErrorPayload: Codable, Equatable {
|
|
20
|
+
public let reason: String
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
public struct InspectContentPayload: Codable, Equatable {
|
|
24
|
+
public let content: String
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
public struct RemuxEnvelope<Payload: Codable & Equatable>: Codable, Equatable {
|
|
28
|
+
public let domain: String
|
|
29
|
+
public let type: String
|
|
30
|
+
public let version: Int
|
|
31
|
+
public let requestId: String?
|
|
32
|
+
public let emittedAt: String
|
|
33
|
+
public let source: String
|
|
34
|
+
public let payload: Payload
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
public struct WorkspacePane: Codable, Equatable {
|
|
38
|
+
public let id: String
|
|
39
|
+
public let focused: Bool
|
|
40
|
+
public let title: String
|
|
41
|
+
public let command: String?
|
|
42
|
+
public let cwd: String?
|
|
43
|
+
public let rows: Int
|
|
44
|
+
public let cols: Int
|
|
45
|
+
public let x: Int
|
|
46
|
+
public let y: Int
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
public struct WorkspaceTab: Codable, Equatable {
|
|
50
|
+
public let index: Int
|
|
51
|
+
public let name: String
|
|
52
|
+
public let active: Bool
|
|
53
|
+
public let isFullscreen: Bool
|
|
54
|
+
public let hasBell: Bool
|
|
55
|
+
public let panes: [WorkspacePane]
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
public struct WorkspaceState: Codable, Equatable {
|
|
59
|
+
public let session: String
|
|
60
|
+
public let tabs: [WorkspaceTab]
|
|
61
|
+
public let activeTabIndex: Int
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
public struct InspectHighlight: Codable, Equatable {
|
|
65
|
+
public let start: Int
|
|
66
|
+
public let end: Int
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
public struct InspectDescriptor: Codable, Equatable {
|
|
70
|
+
public let scope: String
|
|
71
|
+
public let source: String
|
|
72
|
+
public let precision: String
|
|
73
|
+
public let staleness: String
|
|
74
|
+
public let capturedAt: String
|
|
75
|
+
public let paneId: String?
|
|
76
|
+
public let tabIndex: Int?
|
|
77
|
+
public let totalItems: Int?
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
public struct InspectItem: Codable, Equatable {
|
|
81
|
+
public let type: String
|
|
82
|
+
public let content: String
|
|
83
|
+
public let lineNumber: Int?
|
|
84
|
+
public let timestamp: String
|
|
85
|
+
public let paneId: String?
|
|
86
|
+
public let highlights: [InspectHighlight]?
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
public struct InspectSnapshot: Codable, Equatable {
|
|
90
|
+
public let descriptor: InspectDescriptor
|
|
91
|
+
public let items: [InspectItem]
|
|
92
|
+
public let cursor: String?
|
|
93
|
+
public let truncated: Bool
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
public struct InspectRequest: Codable, Equatable {
|
|
97
|
+
public let scope: String
|
|
98
|
+
public let paneId: String?
|
|
99
|
+
public let tabIndex: Int?
|
|
100
|
+
public let cursor: String?
|
|
101
|
+
public let query: String?
|
|
102
|
+
public let limit: Int?
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
public struct BandwidthStats: Codable, Equatable {
|
|
106
|
+
public let rawBytesPerSec: Double
|
|
107
|
+
public let compressedBytesPerSec: Double
|
|
108
|
+
public let savedPercent: Double
|
|
109
|
+
public let fullSnapshotsSent: Int
|
|
110
|
+
public let diffUpdatesSent: Int
|
|
111
|
+
public let avgChangedRowsPerDiff: Double
|
|
112
|
+
public let totalRawBytes: Int
|
|
113
|
+
public let totalCompressedBytes: Int
|
|
114
|
+
public let totalSavedBytes: Int
|
|
115
|
+
public let rttMs: Int?
|
|
116
|
+
public let protocolName: String
|
|
117
|
+
|
|
118
|
+
enum CodingKeys: String, CodingKey {
|
|
119
|
+
case rawBytesPerSec
|
|
120
|
+
case compressedBytesPerSec
|
|
121
|
+
case savedPercent
|
|
122
|
+
case fullSnapshotsSent
|
|
123
|
+
case diffUpdatesSent
|
|
124
|
+
case avgChangedRowsPerDiff
|
|
125
|
+
case totalRawBytes
|
|
126
|
+
case totalCompressedBytes
|
|
127
|
+
case totalSavedBytes
|
|
128
|
+
case rttMs
|
|
129
|
+
case protocolName = "protocol"
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
public struct BandwidthStatsPayload: Codable, Equatable {
|
|
134
|
+
public let stats: BandwidthStats
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
public struct LegacyAuthOk: Codable, Equatable {
|
|
138
|
+
public let type: String
|
|
139
|
+
public let capabilities: ProtocolCapabilities
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
public struct LegacyAuth: Codable, Equatable {
|
|
143
|
+
public let type: String
|
|
144
|
+
public let token: String
|
|
145
|
+
public let password: String?
|
|
146
|
+
public let cols: Int?
|
|
147
|
+
public let rows: Int?
|
|
148
|
+
public let capabilities: ProtocolCapabilities?
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
public struct LegacyAuthError: Codable, Equatable {
|
|
152
|
+
public let type: String
|
|
153
|
+
public let reason: String
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
public struct LegacyErrorMessage: Codable, Equatable {
|
|
157
|
+
public let type: String
|
|
158
|
+
public let code: Int?
|
|
159
|
+
public let message: String
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
public struct LegacyPong: Codable, Equatable {
|
|
163
|
+
public let type: String
|
|
164
|
+
public let timestamp: Double
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
public struct LegacyWorkspaceState: Codable, Equatable {
|
|
168
|
+
public let type: String
|
|
169
|
+
public let session: String
|
|
170
|
+
public let tabs: [WorkspaceTab]
|
|
171
|
+
public let activeTabIndex: Int
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
public struct LegacyInspectRequest: Codable, Equatable {
|
|
175
|
+
public let type: String
|
|
176
|
+
public let scope: String
|
|
177
|
+
public let paneId: String?
|
|
178
|
+
public let tabIndex: Int?
|
|
179
|
+
public let cursor: String?
|
|
180
|
+
public let query: String?
|
|
181
|
+
public let limit: Int?
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
public struct LegacyInspectSnapshot: Codable, Equatable {
|
|
185
|
+
public let type: String
|
|
186
|
+
public let descriptor: InspectDescriptor
|
|
187
|
+
public let items: [InspectItem]
|
|
188
|
+
public let cursor: String?
|
|
189
|
+
public let truncated: Bool
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
public struct LegacyBandwidthStats: Codable, Equatable {
|
|
193
|
+
public let type: String
|
|
194
|
+
public let stats: BandwidthStats
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
public struct LegacyInspectContent: Codable, Equatable {
|
|
198
|
+
public let type: String
|
|
199
|
+
public let content: String
|
|
200
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@wangyaoshen/remux",
|
|
3
|
+
"version": "0.3.8-dev.a8ceb0c",
|
|
4
|
+
"description": "Remote terminal workspace — powered by ghostty-web",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/yaoshenwang/remux.git"
|
|
9
|
+
},
|
|
10
|
+
"type": "module",
|
|
11
|
+
"bin": {
|
|
12
|
+
"remux": "server.js"
|
|
13
|
+
},
|
|
14
|
+
"engines": {
|
|
15
|
+
"node": ">=20"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"better-sqlite3": "^12.8.0",
|
|
19
|
+
"ghostty-web": "^0.4.0",
|
|
20
|
+
"node-pty": "^1.1.0",
|
|
21
|
+
"qrcode-terminal": "^0.12.0",
|
|
22
|
+
"simple-git": "^3.33.0",
|
|
23
|
+
"web-push": "^3.6.7",
|
|
24
|
+
"ws": "^8.20.0"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@playwright/test": "^1.58.2",
|
|
28
|
+
"@types/better-sqlite3": "^7.6.13",
|
|
29
|
+
"@types/node": "^25.5.0",
|
|
30
|
+
"@types/ws": "^8.18.1",
|
|
31
|
+
"esbuild": "^0.27.4",
|
|
32
|
+
"tsx": "^4.21.0",
|
|
33
|
+
"typescript": "^6.0.2",
|
|
34
|
+
"vitest": "^4.1.2"
|
|
35
|
+
},
|
|
36
|
+
"scripts": {
|
|
37
|
+
"start": "node server.js",
|
|
38
|
+
"dev": "pnpm build && node server.js",
|
|
39
|
+
"build": "node build.mjs",
|
|
40
|
+
"typecheck": "tsc --noEmit",
|
|
41
|
+
"test": "vitest run",
|
|
42
|
+
"test:e2e": "npx playwright test",
|
|
43
|
+
"postinstall": "node --input-type=commonjs -e \"var fs=require('fs'),p=require('path');['darwin-arm64','darwin-x64'].forEach(function(d){var f=p.join('node_modules','node-pty','prebuilds',d,'spawn-helper');try{fs.chmodSync(f,0o755)}catch(e){}})\""
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// swift-tools-version: 6.0
|
|
2
|
+
|
|
3
|
+
import PackageDescription
|
|
4
|
+
|
|
5
|
+
let package = Package(
|
|
6
|
+
name: "RemuxKit",
|
|
7
|
+
platforms: [
|
|
8
|
+
.iOS(.v17),
|
|
9
|
+
.macOS(.v14),
|
|
10
|
+
],
|
|
11
|
+
products: [
|
|
12
|
+
.library(
|
|
13
|
+
name: "RemuxKit",
|
|
14
|
+
targets: ["RemuxKit"]
|
|
15
|
+
),
|
|
16
|
+
],
|
|
17
|
+
targets: [
|
|
18
|
+
.target(
|
|
19
|
+
name: "RemuxKit",
|
|
20
|
+
exclude: ["Terminal/Resources"]
|
|
21
|
+
),
|
|
22
|
+
.testTarget(
|
|
23
|
+
name: "RemuxKitTests",
|
|
24
|
+
dependencies: ["RemuxKit"]
|
|
25
|
+
),
|
|
26
|
+
]
|
|
27
|
+
)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
|
|
3
|
+
/// Manages device trust operations via WebSocket messages.
|
|
4
|
+
/// All messages use JSONSerialization for safe construction.
|
|
5
|
+
@MainActor
|
|
6
|
+
public final class DeviceManager {
|
|
7
|
+
|
|
8
|
+
private weak var connection: RemuxConnection?
|
|
9
|
+
|
|
10
|
+
public init(connection: RemuxConnection) {
|
|
11
|
+
self.connection = connection
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
public func listDevices() { sendJSON(["type": "list_devices"]) }
|
|
15
|
+
public func trustDevice(id: String) { sendJSON(["type": "trust_device", "deviceId": id]) }
|
|
16
|
+
public func blockDevice(id: String) { sendJSON(["type": "block_device", "deviceId": id]) }
|
|
17
|
+
public func renameDevice(id: String, name: String) { sendJSON(["type": "rename_device", "deviceId": id, "name": name]) }
|
|
18
|
+
public func revokeDevice(id: String) { sendJSON(["type": "revoke_device", "deviceId": id]) }
|
|
19
|
+
public func generatePairCode() { sendJSON(["type": "generate_pair_code"]) }
|
|
20
|
+
public func pair(code: String) { sendJSON(["type": "pair", "code": code]) }
|
|
21
|
+
|
|
22
|
+
private func sendJSON(_ dict: [String: Any]) {
|
|
23
|
+
guard let data = try? JSONSerialization.data(withJSONObject: dict),
|
|
24
|
+
let str = String(data: data, encoding: .utf8) else { return }
|
|
25
|
+
connection?.sendString(str)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
public struct ProtocolCapabilities: Codable, Equatable, Sendable {
|
|
2
|
+
public let envelope: Bool
|
|
3
|
+
public let inspectV2: Bool
|
|
4
|
+
public let deviceTrust: Bool
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
public struct AuthPayload: Codable, Equatable, Sendable {
|
|
8
|
+
public let token: String
|
|
9
|
+
public let password: String?
|
|
10
|
+
public let cols: Int?
|
|
11
|
+
public let rows: Int?
|
|
12
|
+
public let capabilities: ProtocolCapabilities?
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
public struct AuthOkPayload: Codable, Equatable, Sendable {
|
|
16
|
+
public let capabilities: ProtocolCapabilities
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
public struct AuthErrorPayload: Codable, Equatable, Sendable {
|
|
20
|
+
public let reason: String
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
public struct InspectContentPayload: Codable, Equatable, Sendable {
|
|
24
|
+
public let content: String
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
public struct RemuxEnvelope<Payload: Codable & Equatable & Sendable>: Codable, Equatable, Sendable {
|
|
28
|
+
public let domain: String
|
|
29
|
+
public let type: String
|
|
30
|
+
public let version: Int
|
|
31
|
+
public let requestId: String?
|
|
32
|
+
public let emittedAt: String
|
|
33
|
+
public let source: String
|
|
34
|
+
public let payload: Payload
|
|
35
|
+
|
|
36
|
+
enum CodingKeys: String, CodingKey {
|
|
37
|
+
case domain, type
|
|
38
|
+
case version = "v"
|
|
39
|
+
case requestId, emittedAt, source, payload
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
public struct WorkspacePane: Codable, Equatable, Sendable {
|
|
44
|
+
public let id: String
|
|
45
|
+
public let focused: Bool
|
|
46
|
+
public let title: String
|
|
47
|
+
public let command: String?
|
|
48
|
+
public let cwd: String?
|
|
49
|
+
public let rows: Int
|
|
50
|
+
public let cols: Int
|
|
51
|
+
public let x: Int
|
|
52
|
+
public let y: Int
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
public struct WorkspaceTab: Codable, Equatable, Sendable {
|
|
56
|
+
public let index: Int
|
|
57
|
+
public let name: String
|
|
58
|
+
public let active: Bool
|
|
59
|
+
public let isFullscreen: Bool
|
|
60
|
+
public let hasBell: Bool
|
|
61
|
+
public let panes: [WorkspacePane]
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
public struct WorkspaceState: Codable, Equatable, Sendable {
|
|
65
|
+
public let session: String
|
|
66
|
+
public let tabs: [WorkspaceTab]
|
|
67
|
+
public let activeTabIndex: Int
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
public struct InspectHighlight: Codable, Equatable, Sendable {
|
|
71
|
+
public let start: Int
|
|
72
|
+
public let end: Int
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
public struct InspectDescriptor: Codable, Equatable, Sendable {
|
|
76
|
+
public let scope: String
|
|
77
|
+
public let source: String
|
|
78
|
+
public let precision: String
|
|
79
|
+
public let staleness: String
|
|
80
|
+
public let capturedAt: String
|
|
81
|
+
public let paneId: String?
|
|
82
|
+
public let tabIndex: Int?
|
|
83
|
+
public let totalItems: Int?
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
public struct InspectItem: Codable, Equatable, Sendable {
|
|
87
|
+
public let type: String
|
|
88
|
+
public let content: String
|
|
89
|
+
public let lineNumber: Int?
|
|
90
|
+
public let timestamp: String
|
|
91
|
+
public let paneId: String?
|
|
92
|
+
public let highlights: [InspectHighlight]?
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
public struct InspectSnapshot: Codable, Equatable, Sendable {
|
|
96
|
+
public let descriptor: InspectDescriptor
|
|
97
|
+
public let items: [InspectItem]
|
|
98
|
+
public let cursor: String?
|
|
99
|
+
public let truncated: Bool
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
public struct InspectRequest: Codable, Equatable, Sendable {
|
|
103
|
+
public let scope: String
|
|
104
|
+
public let paneId: String?
|
|
105
|
+
public let tabIndex: Int?
|
|
106
|
+
public let cursor: String?
|
|
107
|
+
public let query: String?
|
|
108
|
+
public let limit: Int?
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
public struct BandwidthStats: Codable, Equatable, Sendable {
|
|
112
|
+
public let rawBytesPerSec: Double
|
|
113
|
+
public let compressedBytesPerSec: Double
|
|
114
|
+
public let savedPercent: Double
|
|
115
|
+
public let fullSnapshotsSent: Int
|
|
116
|
+
public let diffUpdatesSent: Int
|
|
117
|
+
public let avgChangedRowsPerDiff: Double
|
|
118
|
+
public let totalRawBytes: Int
|
|
119
|
+
public let totalCompressedBytes: Int
|
|
120
|
+
public let totalSavedBytes: Int
|
|
121
|
+
public let rttMs: Int?
|
|
122
|
+
public let protocolName: String
|
|
123
|
+
|
|
124
|
+
enum CodingKeys: String, CodingKey {
|
|
125
|
+
case rawBytesPerSec
|
|
126
|
+
case compressedBytesPerSec
|
|
127
|
+
case savedPercent
|
|
128
|
+
case fullSnapshotsSent
|
|
129
|
+
case diffUpdatesSent
|
|
130
|
+
case avgChangedRowsPerDiff
|
|
131
|
+
case totalRawBytes
|
|
132
|
+
case totalCompressedBytes
|
|
133
|
+
case totalSavedBytes
|
|
134
|
+
case rttMs
|
|
135
|
+
case protocolName = "protocol"
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
public struct BandwidthStatsPayload: Codable, Equatable, Sendable {
|
|
140
|
+
public let stats: BandwidthStats
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
public struct LegacyAuthOk: Codable, Equatable, Sendable {
|
|
144
|
+
public let type: String
|
|
145
|
+
public let capabilities: ProtocolCapabilities
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
public struct LegacyAuth: Codable, Equatable, Sendable {
|
|
149
|
+
public let type: String
|
|
150
|
+
public let token: String
|
|
151
|
+
public let password: String?
|
|
152
|
+
public let cols: Int?
|
|
153
|
+
public let rows: Int?
|
|
154
|
+
public let capabilities: ProtocolCapabilities?
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
public struct LegacyAuthError: Codable, Equatable, Sendable {
|
|
158
|
+
public let type: String
|
|
159
|
+
public let reason: String
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
public struct LegacyErrorMessage: Codable, Equatable, Sendable {
|
|
163
|
+
public let type: String
|
|
164
|
+
public let code: Int?
|
|
165
|
+
public let message: String
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
public struct LegacyPong: Codable, Equatable, Sendable {
|
|
169
|
+
public let type: String
|
|
170
|
+
public let timestamp: Double
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
public struct LegacyWorkspaceState: Codable, Equatable, Sendable {
|
|
174
|
+
public let type: String
|
|
175
|
+
public let session: String
|
|
176
|
+
public let tabs: [WorkspaceTab]
|
|
177
|
+
public let activeTabIndex: Int
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
public struct LegacyInspectRequest: Codable, Equatable, Sendable {
|
|
181
|
+
public let type: String
|
|
182
|
+
public let scope: String
|
|
183
|
+
public let paneId: String?
|
|
184
|
+
public let tabIndex: Int?
|
|
185
|
+
public let cursor: String?
|
|
186
|
+
public let query: String?
|
|
187
|
+
public let limit: Int?
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
public struct LegacyInspectSnapshot: Codable, Equatable, Sendable {
|
|
191
|
+
public let type: String
|
|
192
|
+
public let descriptor: InspectDescriptor
|
|
193
|
+
public let items: [InspectItem]
|
|
194
|
+
public let cursor: String?
|
|
195
|
+
public let truncated: Bool
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
public struct LegacyBandwidthStats: Codable, Equatable, Sendable {
|
|
199
|
+
public let type: String
|
|
200
|
+
public let stats: BandwidthStats
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
public struct LegacyInspectContent: Codable, Equatable, Sendable {
|
|
204
|
+
public let type: String
|
|
205
|
+
public let content: String
|
|
206
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
|
|
3
|
+
/// Routes incoming WebSocket messages to the appropriate handler.
|
|
4
|
+
/// Supports both envelope format (v:1) and legacy bare messages.
|
|
5
|
+
public struct MessageRouter: Sendable {
|
|
6
|
+
|
|
7
|
+
/// Parsed message with type info extracted
|
|
8
|
+
public enum RoutedMessage: Sendable {
|
|
9
|
+
case state(WorkspaceState)
|
|
10
|
+
case inspectResult(InspectSnapshot)
|
|
11
|
+
case roleChanged(String) // "active" or "observer"
|
|
12
|
+
case deviceList([DeviceInfo])
|
|
13
|
+
case pairResult(PairResultPayload)
|
|
14
|
+
case pushStatus(PushStatusPayload)
|
|
15
|
+
case error(String)
|
|
16
|
+
case unknown(type: String, raw: String)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
public init() {}
|
|
20
|
+
|
|
21
|
+
/// Parse and route a raw JSON message string.
|
|
22
|
+
public func route(_ text: String) -> RoutedMessage? {
|
|
23
|
+
guard let data = text.data(using: .utf8),
|
|
24
|
+
let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else {
|
|
25
|
+
return nil
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Extract type — handle both envelope (v:1) and legacy format
|
|
29
|
+
let msgType: String?
|
|
30
|
+
let payload: [String: Any]?
|
|
31
|
+
|
|
32
|
+
if let v = json["v"] as? Int, v >= 1 {
|
|
33
|
+
// Envelope format
|
|
34
|
+
msgType = json["type"] as? String
|
|
35
|
+
payload = json["payload"] as? [String: Any]
|
|
36
|
+
} else {
|
|
37
|
+
// Legacy format — type is top-level
|
|
38
|
+
msgType = json["type"] as? String
|
|
39
|
+
payload = json
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
guard let type = msgType else { return nil }
|
|
43
|
+
|
|
44
|
+
switch type {
|
|
45
|
+
case "state":
|
|
46
|
+
if let p = payload, let state = decode(WorkspaceState.self, from: p) {
|
|
47
|
+
return .state(state)
|
|
48
|
+
}
|
|
49
|
+
case "inspect_result":
|
|
50
|
+
if let p = payload, let snapshot = decode(InspectSnapshot.self, from: p) {
|
|
51
|
+
return .inspectResult(snapshot)
|
|
52
|
+
}
|
|
53
|
+
case "role_changed":
|
|
54
|
+
if let role = payload?["role"] as? String {
|
|
55
|
+
return .roleChanged(role)
|
|
56
|
+
}
|
|
57
|
+
case "device_list":
|
|
58
|
+
if let p = payload, let list = decode(DeviceListPayload.self, from: p) {
|
|
59
|
+
return .deviceList(list.devices)
|
|
60
|
+
}
|
|
61
|
+
case "pair_result":
|
|
62
|
+
if let p = payload, let result = decode(PairResultPayload.self, from: p) {
|
|
63
|
+
return .pairResult(result)
|
|
64
|
+
}
|
|
65
|
+
case "push_status":
|
|
66
|
+
if let p = payload, let status = decode(PushStatusPayload.self, from: p) {
|
|
67
|
+
return .pushStatus(status)
|
|
68
|
+
}
|
|
69
|
+
case "error":
|
|
70
|
+
let message = payload?["message"] as? String ?? "Unknown error"
|
|
71
|
+
return .error(message)
|
|
72
|
+
default:
|
|
73
|
+
return .unknown(type: type, raw: text)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return .unknown(type: type, raw: text)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
private func decode<T: Decodable>(_ type: T.Type, from dict: [String: Any]) -> T? {
|
|
80
|
+
guard let data = try? JSONSerialization.data(withJSONObject: dict) else { return nil }
|
|
81
|
+
return try? JSONDecoder().decode(type, from: data)
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// MARK: - Additional payload types needed by router
|
|
86
|
+
|
|
87
|
+
public struct DeviceInfo: Codable, Equatable, Sendable {
|
|
88
|
+
public let id: String
|
|
89
|
+
public let fingerprint: String?
|
|
90
|
+
public let name: String?
|
|
91
|
+
public let platform: String?
|
|
92
|
+
public let trustLevel: String
|
|
93
|
+
public let lastSeen: String?
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
public struct DeviceListPayload: Codable, Equatable, Sendable {
|
|
97
|
+
public let devices: [DeviceInfo]
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
public struct PairResultPayload: Codable, Equatable, Sendable {
|
|
101
|
+
public let success: Bool
|
|
102
|
+
public let deviceId: String?
|
|
103
|
+
public let error: String?
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
public struct PushStatusPayload: Codable, Equatable, Sendable {
|
|
107
|
+
public let subscribed: Bool
|
|
108
|
+
}
|