@hmduc16031996/claude-mb-bridge 2.4.0 → 2.4.2

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 CHANGED
@@ -6,7 +6,7 @@ const program = new Command();
6
6
  program
7
7
  .name('claude-mobile-bridge')
8
8
  .description('Bridge Claude Code CLI to mobile via WebView')
9
- .version('2.4.0')
9
+ .version('2.4.1')
10
10
  .option('--token <token>', 'Pairing token from mobile app')
11
11
  .option('--server <url>', 'Backend server URL', 'http://127.0.0.1:3110')
12
12
  .option('--path <path>', 'Working directory', process.cwd())
@@ -33,7 +33,7 @@ program
33
33
  // 1. Start local terminal server
34
34
  console.log('📦 Starting terminal server...');
35
35
  const localPort = parseInt(port, 10);
36
- const { server: terminalServer, actualPort } = await startTerminalServer(localPort, path, cleanup);
36
+ const { server: terminalServer, actualPort } = await startTerminalServer(localPort, path, token, cleanup);
37
37
  console.log(`✅ Terminal server started on port ${actualPort}`);
38
38
  // 2. Start Cloudflare Tunnel
39
39
  console.log('🌐 Establishing secure tunnel...');
package/dist/server.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export declare function startTerminalServer(port: number, workingDir: string, onDisconnect?: () => void): Promise<{
1
+ export declare function startTerminalServer(port: number, workingDir: string, terminalToken: string, onDisconnect?: () => void): Promise<{
2
2
  server: any;
3
3
  actualPort: number;
4
4
  }>;
package/dist/server.js CHANGED
@@ -78,7 +78,7 @@ class SessionManager {
78
78
  return Array.from(this.sessions.values()).map(s => s.getInfo());
79
79
  }
80
80
  }
81
- export function startTerminalServer(port, workingDir, onDisconnect) {
81
+ export function startTerminalServer(port, workingDir, terminalToken, onDisconnect) {
82
82
  const app = express();
83
83
  const server = createServer(app);
84
84
  const wss = new WebSocketServer({ server });
@@ -88,6 +88,10 @@ export function startTerminalServer(port, workingDir, onDisconnect) {
88
88
  app.get('/health', (req, res) => {
89
89
  res.json({ status: 'ok' });
90
90
  });
91
+ // Ports endpoint - returns empty list (no port detection in bridge mode)
92
+ app.get('/api/ports', (req, res) => {
93
+ res.json([]);
94
+ });
91
95
  // Directory listing for autocomplete
92
96
  app.get('/api/dirs', (req, res) => {
93
97
  try {
@@ -131,6 +135,7 @@ export function startTerminalServer(port, workingDir, onDisconnect) {
131
135
  });
132
136
  wss.on('connection', (ws, req) => {
133
137
  console.log(`📡 New connection from ${req.socket.remoteAddress}`);
138
+ let authenticated = false;
134
139
  let activeSessionId = null;
135
140
  let outputHandler = null;
136
141
  const sendControl = (message) => {
@@ -148,7 +153,7 @@ export function startTerminalServer(port, workingDir, onDisconnect) {
148
153
  if (activeSessionId && outputHandler) {
149
154
  const oldSession = sessionManager.getSession(activeSessionId);
150
155
  if (oldSession) {
151
- oldSession.term.off('data', outputHandler);
156
+ oldSession.term.removeListener('data', outputHandler);
152
157
  }
153
158
  }
154
159
  activeSessionId = sessionId;
@@ -160,9 +165,6 @@ export function startTerminalServer(port, workingDir, onDisconnect) {
160
165
  session.term.on('data', outputHandler);
161
166
  sendControl({ type: 'session:attached', session: session.getInfo() });
162
167
  };
163
- // Auto-create initial session if none exist or just use workingDir
164
- const initialSession = sessionManager.createSession(workingDir);
165
- attachToSession(initialSession.id);
166
168
  ws.on('message', (msg, isBinary) => {
167
169
  if (isBinary) {
168
170
  let message;
@@ -173,6 +175,26 @@ export function startTerminalServer(port, workingDir, onDisconnect) {
173
175
  sendControl({ type: 'error', error: 'Invalid control message' });
174
176
  return;
175
177
  }
178
+ // Auth must happen first
179
+ if (message.type === 'auth') {
180
+ if (message.token === terminalToken) {
181
+ authenticated = true;
182
+ sendControl({ type: 'auth:success' });
183
+ // Auto-create initial session and attach
184
+ const initialSession = sessionManager.createSession(workingDir);
185
+ attachToSession(initialSession.id);
186
+ console.log('✅ Client authenticated');
187
+ }
188
+ else {
189
+ sendControl({ type: 'auth:failed', error: 'Invalid token' });
190
+ ws.close();
191
+ }
192
+ return;
193
+ }
194
+ if (!authenticated) {
195
+ sendControl({ type: 'auth:failed', error: 'Not authenticated' });
196
+ return;
197
+ }
176
198
  switch (message.type) {
177
199
  case 'session:create': {
178
200
  let cwd = message.cwd || workingDir;
@@ -198,6 +220,11 @@ export function startTerminalServer(port, workingDir, onDisconnect) {
198
220
  sendControl({ type: 'session:list', sessions: sessionManager.listSessions() });
199
221
  break;
200
222
  }
223
+ case 'session:discover': {
224
+ // No external session discovery in bridge mode
225
+ sendControl({ type: 'session:discovered', sessions: [] });
226
+ break;
227
+ }
201
228
  case 'resize': {
202
229
  const session = activeSessionId ? sessionManager.getSession(activeSessionId) : null;
203
230
  if (session && message.cols && message.rows) {
@@ -228,9 +255,33 @@ export function startTerminalServer(port, workingDir, onDisconnect) {
228
255
  }
229
256
  break;
230
257
  }
258
+ // Schedule stubs - not supported in bridge mode
259
+ case 'schedule:list': {
260
+ sendControl({ type: 'schedule:list', schedules: [] });
261
+ break;
262
+ }
263
+ case 'schedule:create': {
264
+ sendControl({ type: 'schedule:create_error', error: 'Schedules are not supported in bridge mode' });
265
+ break;
266
+ }
267
+ case 'schedule:update':
268
+ case 'schedule:delete':
269
+ case 'schedule:trigger':
270
+ case 'schedule:runs':
271
+ case 'schedule:log': {
272
+ // No-op stubs
273
+ break;
274
+ }
275
+ // Preferences - store in memory only (no persistence needed)
276
+ case 'preferences:set': {
277
+ // No-op: preferences are managed client-side via localStorage
278
+ break;
279
+ }
231
280
  }
232
281
  }
233
282
  else {
283
+ if (!authenticated)
284
+ return;
234
285
  // Raw text -> forward to active pty
235
286
  const session = activeSessionId ? sessionManager.getSession(activeSessionId) : null;
236
287
  if (session) {
@@ -242,7 +293,7 @@ export function startTerminalServer(port, workingDir, onDisconnect) {
242
293
  if (activeSessionId && outputHandler) {
243
294
  const session = sessionManager.getSession(activeSessionId);
244
295
  if (session) {
245
- session.term.off('data', outputHandler);
296
+ session.term.removeListener('data', outputHandler);
246
297
  }
247
298
  }
248
299
  if (onDisconnect)
@@ -253,7 +304,7 @@ export function startTerminalServer(port, workingDir, onDisconnect) {
253
304
  server.on('error', (err) => {
254
305
  if (err.code === 'EADDRINUSE' && port !== 0) {
255
306
  console.warn(`⚠️ Port ${port} is busy, trying a random port...`);
256
- resolve(startTerminalServer(0, workingDir, onDisconnect));
307
+ resolve(startTerminalServer(0, workingDir, terminalToken, onDisconnect));
257
308
  }
258
309
  else {
259
310
  reject(err);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hmduc16031996/claude-mb-bridge",
3
- "version": "2.4.0",
3
+ "version": "2.4.2",
4
4
  "description": "Bridge between Claude Code CLI and your mobile app via WebView",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",