@hmduc16031996/claude-mb-bridge 2.4.2 → 2.4.4
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/dist/index.js +3 -2
- package/dist/server.d.ts +1 -1
- package/dist/server.js +16 -10
- package/package.json +1 -1
- package/public/app.js +33 -0
- package/public/index.html +2 -2
package/dist/index.js
CHANGED
|
@@ -11,8 +11,9 @@ program
|
|
|
11
11
|
.option('--server <url>', 'Backend server URL', 'http://127.0.0.1:3110')
|
|
12
12
|
.option('--path <path>', 'Working directory', process.cwd())
|
|
13
13
|
.option('--port <port>', 'Local port for terminal server', '38473')
|
|
14
|
+
.option('--ide <type>', 'IDE type: claude_code or cursor', 'claude_code')
|
|
14
15
|
.action(async (options) => {
|
|
15
|
-
const { token, server, path, port } = options;
|
|
16
|
+
const { token, server, path, port, ide } = options;
|
|
16
17
|
if (!token) {
|
|
17
18
|
console.error('Error: --token is required');
|
|
18
19
|
process.exit(1);
|
|
@@ -33,7 +34,7 @@ program
|
|
|
33
34
|
// 1. Start local terminal server
|
|
34
35
|
console.log('📦 Starting terminal server...');
|
|
35
36
|
const localPort = parseInt(port, 10);
|
|
36
|
-
const { server: terminalServer, actualPort } = await startTerminalServer(localPort, path, token,
|
|
37
|
+
const { server: terminalServer, actualPort } = await startTerminalServer(localPort, path, token, ide);
|
|
37
38
|
console.log(`✅ Terminal server started on port ${actualPort}`);
|
|
38
39
|
// 2. Start Cloudflare Tunnel
|
|
39
40
|
console.log('🌐 Establishing secure tunnel...');
|
package/dist/server.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare function startTerminalServer(port: number, workingDir: string, terminalToken: string, onDisconnect?: () => void): Promise<{
|
|
1
|
+
export declare function startTerminalServer(port: number, workingDir: string, terminalToken: string, ide?: string, onDisconnect?: () => void): Promise<{
|
|
2
2
|
server: any;
|
|
3
3
|
actualPort: number;
|
|
4
4
|
}>;
|
package/dist/server.js
CHANGED
|
@@ -12,12 +12,14 @@ const pty = require('node-pty');
|
|
|
12
12
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
13
13
|
class Session {
|
|
14
14
|
term;
|
|
15
|
+
ide;
|
|
15
16
|
id;
|
|
16
17
|
cwd;
|
|
17
18
|
createdAt;
|
|
18
|
-
constructor(id, cwd, shell) {
|
|
19
|
+
constructor(id, cwd, shell, ide = 'claude_code') {
|
|
19
20
|
this.id = id;
|
|
20
21
|
this.cwd = cwd;
|
|
22
|
+
this.ide = ide;
|
|
21
23
|
this.createdAt = new Date().toISOString();
|
|
22
24
|
this.term = pty.spawn(shell, [], {
|
|
23
25
|
name: 'xterm-256color',
|
|
@@ -30,7 +32,9 @@ class Session {
|
|
|
30
32
|
FORCE_COLOR: '1',
|
|
31
33
|
}
|
|
32
34
|
});
|
|
33
|
-
|
|
35
|
+
// Map IDE type to command
|
|
36
|
+
const command = ide === 'cursor' ? 'agent' : (ide === 'gemini' ? 'gemini' : 'claude');
|
|
37
|
+
this.term.write(`${command}\r`);
|
|
34
38
|
}
|
|
35
39
|
getInfo() {
|
|
36
40
|
return {
|
|
@@ -51,7 +55,7 @@ class Session {
|
|
|
51
55
|
}
|
|
52
56
|
class SessionManager {
|
|
53
57
|
sessions = new Map();
|
|
54
|
-
createSession(cwd) {
|
|
58
|
+
createSession(cwd, ide = 'claude_code') {
|
|
55
59
|
const id = randomUUID().slice(0, 8);
|
|
56
60
|
let shell = '/bin/bash';
|
|
57
61
|
if (process.platform === 'win32') {
|
|
@@ -60,7 +64,7 @@ class SessionManager {
|
|
|
60
64
|
else if (process.platform === 'darwin') {
|
|
61
65
|
shell = fs.existsSync('/bin/zsh') ? '/bin/zsh' : '/bin/bash';
|
|
62
66
|
}
|
|
63
|
-
const session = new Session(id, cwd, shell);
|
|
67
|
+
const session = new Session(id, cwd, shell, ide);
|
|
64
68
|
this.sessions.set(id, session);
|
|
65
69
|
return session;
|
|
66
70
|
}
|
|
@@ -78,7 +82,7 @@ class SessionManager {
|
|
|
78
82
|
return Array.from(this.sessions.values()).map(s => s.getInfo());
|
|
79
83
|
}
|
|
80
84
|
}
|
|
81
|
-
export function startTerminalServer(port, workingDir, terminalToken, onDisconnect) {
|
|
85
|
+
export function startTerminalServer(port, workingDir, terminalToken, ide = 'claude_code', onDisconnect) {
|
|
82
86
|
const app = express();
|
|
83
87
|
const server = createServer(app);
|
|
84
88
|
const wss = new WebSocketServer({ server });
|
|
@@ -88,6 +92,10 @@ export function startTerminalServer(port, workingDir, terminalToken, onDisconnec
|
|
|
88
92
|
app.get('/health', (req, res) => {
|
|
89
93
|
res.json({ status: 'ok' });
|
|
90
94
|
});
|
|
95
|
+
// Session Info endpoint (used by frontend to know which IDE it is bridging)
|
|
96
|
+
app.get('/api/session-info', (req, res) => {
|
|
97
|
+
res.json({ ide });
|
|
98
|
+
});
|
|
91
99
|
// Ports endpoint - returns empty list (no port detection in bridge mode)
|
|
92
100
|
app.get('/api/ports', (req, res) => {
|
|
93
101
|
res.json([]);
|
|
@@ -181,7 +189,7 @@ export function startTerminalServer(port, workingDir, terminalToken, onDisconnec
|
|
|
181
189
|
authenticated = true;
|
|
182
190
|
sendControl({ type: 'auth:success' });
|
|
183
191
|
// Auto-create initial session and attach
|
|
184
|
-
const initialSession = sessionManager.createSession(workingDir);
|
|
192
|
+
const initialSession = sessionManager.createSession(workingDir, ide);
|
|
185
193
|
attachToSession(initialSession.id);
|
|
186
194
|
console.log('✅ Client authenticated');
|
|
187
195
|
}
|
|
@@ -205,7 +213,7 @@ export function startTerminalServer(port, workingDir, terminalToken, onDisconnec
|
|
|
205
213
|
sendControl({ type: 'error', error: 'Directory not found' });
|
|
206
214
|
break;
|
|
207
215
|
}
|
|
208
|
-
const session = sessionManager.createSession(cwd);
|
|
216
|
+
const session = sessionManager.createSession(cwd, ide);
|
|
209
217
|
sendControl({ type: 'session:created', session: session.getInfo() });
|
|
210
218
|
attachToSession(session.id);
|
|
211
219
|
break;
|
|
@@ -296,15 +304,13 @@ export function startTerminalServer(port, workingDir, terminalToken, onDisconnec
|
|
|
296
304
|
session.term.removeListener('data', outputHandler);
|
|
297
305
|
}
|
|
298
306
|
}
|
|
299
|
-
if (onDisconnect)
|
|
300
|
-
onDisconnect();
|
|
301
307
|
});
|
|
302
308
|
});
|
|
303
309
|
return new Promise((resolve, reject) => {
|
|
304
310
|
server.on('error', (err) => {
|
|
305
311
|
if (err.code === 'EADDRINUSE' && port !== 0) {
|
|
306
312
|
console.warn(`⚠️ Port ${port} is busy, trying a random port...`);
|
|
307
|
-
resolve(startTerminalServer(0, workingDir, terminalToken, onDisconnect));
|
|
313
|
+
resolve(startTerminalServer(0, workingDir, terminalToken, ide, onDisconnect));
|
|
308
314
|
}
|
|
309
315
|
else {
|
|
310
316
|
reject(err);
|
package/package.json
CHANGED
package/public/app.js
CHANGED
|
@@ -378,6 +378,9 @@ class ClaudeRemote {
|
|
|
378
378
|
this.bindEvents();
|
|
379
379
|
this.initTerminal();
|
|
380
380
|
|
|
381
|
+
// Fetch IDE info for branding
|
|
382
|
+
this.fetchSessionInfo();
|
|
383
|
+
|
|
381
384
|
// Initialize notification manager
|
|
382
385
|
this.notificationManager = new NotificationManager(this);
|
|
383
386
|
this.updateNotifyToggleState();
|
|
@@ -408,6 +411,8 @@ class ClaudeRemote {
|
|
|
408
411
|
tokenInput: document.getElementById('token-input'),
|
|
409
412
|
connectBtn: document.getElementById('connect-btn'),
|
|
410
413
|
authError: document.getElementById('auth-error'),
|
|
414
|
+
mainTitle: document.getElementById('main-title'),
|
|
415
|
+
mainSubtitle: document.getElementById('main-subtitle'),
|
|
411
416
|
|
|
412
417
|
// Main
|
|
413
418
|
header: document.getElementById('header'),
|
|
@@ -494,6 +499,34 @@ class ClaudeRemote {
|
|
|
494
499
|
this.scheduleDebounceTimer = null;
|
|
495
500
|
}
|
|
496
501
|
|
|
502
|
+
async fetchSessionInfo() {
|
|
503
|
+
try {
|
|
504
|
+
const res = await fetch('/api/session-info');
|
|
505
|
+
const data = await res.json();
|
|
506
|
+
if (data.ide) {
|
|
507
|
+
this.updateBranding(data.ide);
|
|
508
|
+
}
|
|
509
|
+
} catch (err) {
|
|
510
|
+
console.warn('Failed to fetch session info:', err);
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
updateBranding(ide) {
|
|
515
|
+
const isCursor = ide === 'cursor';
|
|
516
|
+
const isGemini = ide === 'gemini';
|
|
517
|
+
const name = isGemini ? 'Gemini' : (isCursor ? 'Cursor' : 'Claude Code');
|
|
518
|
+
|
|
519
|
+
if (this.elements.mainTitle) {
|
|
520
|
+
this.elements.mainTitle.textContent = `${name} Remote`;
|
|
521
|
+
}
|
|
522
|
+
if (this.elements.mainSubtitle) {
|
|
523
|
+
this.elements.mainSubtitle.textContent = `Connect to your local ${name} session from anywhere`;
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
// Update page title
|
|
527
|
+
document.title = `${name} Remote`;
|
|
528
|
+
}
|
|
529
|
+
|
|
497
530
|
initTerminal() {
|
|
498
531
|
// Create terminal with mobile-friendly settings
|
|
499
532
|
this.terminal = new Terminal({
|
package/public/index.html
CHANGED
|
@@ -36,8 +36,8 @@
|
|
|
36
36
|
<img src="/ic_logo.png" width="64" height="64" alt="Claude Code" style="border-radius:12px;">
|
|
37
37
|
</div>
|
|
38
38
|
|
|
39
|
-
<h1>Claude Code Remote</h1>
|
|
40
|
-
<p class="subtitle">Connect to your local Claude Code session from anywhere</p>
|
|
39
|
+
<h1 id="main-title">Claude Code Remote</h1>
|
|
40
|
+
<p id="main-subtitle" class="subtitle">Connect to your local Claude Code session from anywhere</p>
|
|
41
41
|
|
|
42
42
|
<form id="auth-form" onsubmit="return false;">
|
|
43
43
|
<input
|