cursor-bridge 1.2.0 → 1.4.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 (3) hide show
  1. package/dist/index.js +80 -16
  2. package/package.json +1 -1
  3. package/src/index.ts +129 -23
package/dist/index.js CHANGED
@@ -5,12 +5,59 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  };
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
7
  const ws_1 = __importDefault(require("ws"));
8
+ const child_process_1 = require("child_process");
9
+ const fs_1 = require("fs");
10
+ const path_1 = require("path");
8
11
  const chalk_1 = __importDefault(require("chalk"));
9
12
  const BRIDGE_URL = 'wss://cursor-226b2ae97542.herokuapp.com';
13
+ function getCursorAuthFromDB() {
14
+ const home = process.env.HOME || process.env.USERPROFILE || '';
15
+ const dbPath = (0, path_1.join)(home, 'Library', 'Application Support', 'Cursor', 'User', 'globalStorage', 'state.vscdb');
16
+ if (!(0, fs_1.existsSync)(dbPath)) {
17
+ console.log(chalk_1.default.hex('#EF4444')(' ✗ ') +
18
+ chalk_1.default.gray('Cursor database not found. Is Cursor installed?'));
19
+ return null;
20
+ }
21
+ try {
22
+ // Read auth tokens from Cursor's SQLite database
23
+ const query = (key) => {
24
+ const result = (0, child_process_1.execSync)(`sqlite3 "${dbPath}" "SELECT value FROM ItemTable WHERE key='${key}'" 2>/dev/null`, { encoding: 'utf-8', timeout: 5000 }).trim();
25
+ return result;
26
+ };
27
+ const accessToken = query('cursorAuth/accessToken');
28
+ const refreshToken = query('cursorAuth/refreshToken');
29
+ const machineId = query('storage.serviceMachineId');
30
+ if (!accessToken || !refreshToken) {
31
+ console.log(chalk_1.default.hex('#EF4444')(' ✗ ') +
32
+ chalk_1.default.gray('Not logged into Cursor. Please log in first.'));
33
+ return null;
34
+ }
35
+ // macMachineId is optional
36
+ let macMachineId;
37
+ try {
38
+ macMachineId = query('storage.macMachineId') || undefined;
39
+ }
40
+ catch {
41
+ // not available on all platforms
42
+ }
43
+ return {
44
+ accessToken: accessToken.replace(/"/g, ''),
45
+ refreshToken: refreshToken.replace(/"/g, ''),
46
+ machineId: machineId.replace(/"/g, ''),
47
+ macMachineId: macMachineId?.replace(/"/g, ''),
48
+ };
49
+ }
50
+ catch (err) {
51
+ console.log(chalk_1.default.hex('#EF4444')(' ✗ ') +
52
+ chalk_1.default.gray('Failed to read Cursor auth. Is Cursor installed and logged in?'));
53
+ return null;
54
+ }
55
+ }
10
56
  function generatePairCode() {
11
57
  return Math.floor(100000 + Math.random() * 900000).toString();
12
58
  }
13
59
  const PAIR_CODE = generatePairCode();
60
+ const cursorAuth = getCursorAuthFromDB();
14
61
  let ws = null;
15
62
  let reconnectTimer = null;
16
63
  function banner() {
@@ -28,22 +75,40 @@ function banner() {
28
75
  chalk_1.default.bgHex('#A855F7').white.bold(` ${PAIR_CODE.split('').join(' ')} `));
29
76
  console.log('');
30
77
  console.log(chalk_1.default.gray(' ─────────────────────────────────────────'));
31
- console.log(chalk_1.default.gray(' Bridge: ') + chalk_1.default.white(BRIDGE_URL));
78
+ if (cursorAuth) {
79
+ console.log(chalk_1.default.hex('#22C55E')(' ✓ ') +
80
+ chalk_1.default.white('Cursor auth detected'));
81
+ console.log(chalk_1.default.gray(' Mode: ') +
82
+ chalk_1.default.white('Direct API (works without Cursor open)'));
83
+ }
84
+ else {
85
+ console.log(chalk_1.default.hex('#F59E0B')(' ⚠ ') +
86
+ chalk_1.default.gray('No Cursor auth found — limited functionality'));
87
+ }
32
88
  console.log(chalk_1.default.gray(' ─────────────────────────────────────────'));
33
89
  console.log('');
34
- console.log(chalk_1.default.gray(' Connecting to bridge server...'));
35
- console.log('');
36
90
  }
37
91
  function connect() {
38
92
  ws = new ws_1.default(BRIDGE_URL);
39
93
  ws.on('open', () => {
40
94
  console.log(chalk_1.default.hex('#22C55E')(' ✓ ') +
41
95
  chalk_1.default.white('Connected to bridge server'));
96
+ // Pair as desktop client
42
97
  ws.send(JSON.stringify({
43
98
  type: 'pair',
44
99
  payload: { pairCode: PAIR_CODE, clientType: 'desktop' },
45
100
  timestamp: Date.now(),
46
101
  }));
102
+ // Send Cursor auth to bridge so it can proxy API calls
103
+ if (cursorAuth) {
104
+ ws.send(JSON.stringify({
105
+ type: 'auth',
106
+ payload: cursorAuth,
107
+ timestamp: Date.now(),
108
+ }));
109
+ console.log(chalk_1.default.hex('#22C55E')(' ✓ ') +
110
+ chalk_1.default.white('Cursor auth sent to bridge'));
111
+ }
47
112
  console.log(chalk_1.default.gray(' Waiting for mobile device...'));
48
113
  console.log('');
49
114
  });
@@ -56,30 +121,29 @@ function connect() {
56
121
  if (status === 'connected') {
57
122
  console.log(chalk_1.default.hex('#22C55E')(' ✓ ') +
58
123
  chalk_1.default.white('Mobile device paired successfully!'));
124
+ console.log(chalk_1.default.gray(' Ready to receive prompts from mobile.'));
125
+ console.log('');
59
126
  }
60
127
  else if (status === 'waiting') {
61
- console.log(chalk_1.default.gray(' Waiting for mobile device...'));
128
+ // already shown
62
129
  }
63
130
  else if (status === 'disconnected') {
64
131
  console.log(chalk_1.default.hex('#EF4444')(' ✗ ') +
65
132
  chalk_1.default.gray('Mobile device disconnected'));
66
133
  }
134
+ else if (status === 'auth_stored') {
135
+ console.log(chalk_1.default.hex('#22C55E')(' ✓ ') +
136
+ chalk_1.default.white('Auth credentials stored on bridge'));
137
+ }
67
138
  break;
68
139
  }
69
140
  case 'command': {
70
141
  const prompt = message.payload.prompt;
71
142
  console.log(chalk_1.default.hex('#A855F7')(' → ') +
72
- chalk_1.default.white('Command received: ') +
73
- chalk_1.default.gray(prompt.substring(0, 80) + (prompt.length > 80 ? '...' : '')));
74
- // Send response back
75
- ws.send(JSON.stringify({
76
- type: 'response',
77
- payload: {
78
- status: 'received',
79
- message: `Command received: ${prompt.substring(0, 50)}`,
80
- },
81
- timestamp: Date.now(),
82
- }));
143
+ chalk_1.default.white('Prompt: ') +
144
+ chalk_1.default.gray(prompt.substring(0, 80) +
145
+ (prompt.length > 80 ? '...' : '')));
146
+ // Bridge handles API proxy now — no need to do anything locally
83
147
  break;
84
148
  }
85
149
  case 'error': {
@@ -98,7 +162,7 @@ function connect() {
98
162
  chalk_1.default.gray('Disconnected from bridge server'));
99
163
  scheduleReconnect();
100
164
  });
101
- ws.on('error', (err) => {
165
+ ws.on('error', err => {
102
166
  console.error(chalk_1.default.hex('#EF4444')(' ✗ ') +
103
167
  chalk_1.default.gray(`Connection error: ${err.message}`));
104
168
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cursor-bridge",
3
- "version": "1.2.0",
3
+ "version": "1.4.0",
4
4
  "description": "CLI bridge to connect IDE For Cursor mobile app with desktop Cursor IDE",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
package/src/index.ts CHANGED
@@ -1,16 +1,91 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import WebSocket from 'ws';
4
+ import { execSync } from 'child_process';
5
+ import { existsSync } from 'fs';
6
+ import { join } from 'path';
4
7
  import chalk from 'chalk';
5
- import os from 'os';
6
8
 
7
9
  const BRIDGE_URL = 'wss://cursor-226b2ae97542.herokuapp.com';
8
10
 
11
+ interface CursorAuth {
12
+ accessToken: string;
13
+ refreshToken: string;
14
+ machineId: string;
15
+ macMachineId?: string;
16
+ }
17
+
18
+ function getCursorAuthFromDB(): CursorAuth | null {
19
+ const home = process.env.HOME || process.env.USERPROFILE || '';
20
+ const dbPath = join(
21
+ home,
22
+ 'Library',
23
+ 'Application Support',
24
+ 'Cursor',
25
+ 'User',
26
+ 'globalStorage',
27
+ 'state.vscdb',
28
+ );
29
+
30
+ if (!existsSync(dbPath)) {
31
+ console.log(
32
+ chalk.hex('#EF4444')(' ✗ ') +
33
+ chalk.gray('Cursor database not found. Is Cursor installed?'),
34
+ );
35
+ return null;
36
+ }
37
+
38
+ try {
39
+ // Read auth tokens from Cursor's SQLite database
40
+ const query = (key: string): string => {
41
+ const result = execSync(
42
+ `sqlite3 "${dbPath}" "SELECT value FROM ItemTable WHERE key='${key}'" 2>/dev/null`,
43
+ { encoding: 'utf-8', timeout: 5000 },
44
+ ).trim();
45
+ return result;
46
+ };
47
+
48
+ const accessToken = query('cursorAuth/accessToken');
49
+ const refreshToken = query('cursorAuth/refreshToken');
50
+ const machineId = query('storage.serviceMachineId');
51
+
52
+ if (!accessToken || !refreshToken) {
53
+ console.log(
54
+ chalk.hex('#EF4444')(' ✗ ') +
55
+ chalk.gray('Not logged into Cursor. Please log in first.'),
56
+ );
57
+ return null;
58
+ }
59
+
60
+ // macMachineId is optional
61
+ let macMachineId: string | undefined;
62
+ try {
63
+ macMachineId = query('storage.macMachineId') || undefined;
64
+ } catch {
65
+ // not available on all platforms
66
+ }
67
+
68
+ return {
69
+ accessToken: accessToken.replace(/"/g, ''),
70
+ refreshToken: refreshToken.replace(/"/g, ''),
71
+ machineId: machineId.replace(/"/g, ''),
72
+ macMachineId: macMachineId?.replace(/"/g, ''),
73
+ };
74
+ } catch (err) {
75
+ console.log(
76
+ chalk.hex('#EF4444')(' ✗ ') +
77
+ chalk.gray('Failed to read Cursor auth. Is Cursor installed and logged in?'),
78
+ );
79
+ return null;
80
+ }
81
+ }
82
+
9
83
  function generatePairCode(): string {
10
84
  return Math.floor(100000 + Math.random() * 900000).toString();
11
85
  }
12
86
 
13
87
  const PAIR_CODE = generatePairCode();
88
+ const cursorAuth = getCursorAuthFromDB();
14
89
 
15
90
  let ws: WebSocket | null = null;
16
91
  let reconnectTimer: ReturnType<typeof setTimeout> | null = null;
@@ -42,15 +117,27 @@ function banner() {
42
117
  console.log(
43
118
  chalk.gray(' ─────────────────────────────────────────'),
44
119
  );
45
- console.log(
46
- chalk.gray(' Bridge: ') + chalk.white(BRIDGE_URL),
47
- );
120
+
121
+ if (cursorAuth) {
122
+ console.log(
123
+ chalk.hex('#22C55E')(' ✓ ') +
124
+ chalk.white('Cursor auth detected'),
125
+ );
126
+ console.log(
127
+ chalk.gray(' Mode: ') +
128
+ chalk.white('Direct API (works without Cursor open)'),
129
+ );
130
+ } else {
131
+ console.log(
132
+ chalk.hex('#F59E0B')(' ⚠ ') +
133
+ chalk.gray('No Cursor auth found — limited functionality'),
134
+ );
135
+ }
136
+
48
137
  console.log(
49
138
  chalk.gray(' ─────────────────────────────────────────'),
50
139
  );
51
140
  console.log('');
52
- console.log(chalk.gray(' Connecting to bridge server...'));
53
- console.log('');
54
141
  }
55
142
 
56
143
  function connect() {
@@ -62,6 +149,7 @@ function connect() {
62
149
  chalk.white('Connected to bridge server'),
63
150
  );
64
151
 
152
+ // Pair as desktop client
65
153
  ws!.send(
66
154
  JSON.stringify({
67
155
  type: 'pair',
@@ -70,6 +158,21 @@ function connect() {
70
158
  }),
71
159
  );
72
160
 
161
+ // Send Cursor auth to bridge so it can proxy API calls
162
+ if (cursorAuth) {
163
+ ws!.send(
164
+ JSON.stringify({
165
+ type: 'auth',
166
+ payload: cursorAuth,
167
+ timestamp: Date.now(),
168
+ }),
169
+ );
170
+ console.log(
171
+ chalk.hex('#22C55E')(' ✓ ') +
172
+ chalk.white('Cursor auth sent to bridge'),
173
+ );
174
+ }
175
+
73
176
  console.log(chalk.gray(' Waiting for mobile device...'));
74
177
  console.log('');
75
178
  });
@@ -86,13 +189,22 @@ function connect() {
86
189
  chalk.hex('#22C55E')(' ✓ ') +
87
190
  chalk.white('Mobile device paired successfully!'),
88
191
  );
192
+ console.log(
193
+ chalk.gray(' Ready to receive prompts from mobile.'),
194
+ );
195
+ console.log('');
89
196
  } else if (status === 'waiting') {
90
- console.log(chalk.gray(' Waiting for mobile device...'));
197
+ // already shown
91
198
  } else if (status === 'disconnected') {
92
199
  console.log(
93
200
  chalk.hex('#EF4444')(' ✗ ') +
94
201
  chalk.gray('Mobile device disconnected'),
95
202
  );
203
+ } else if (status === 'auth_stored') {
204
+ console.log(
205
+ chalk.hex('#22C55E')(' ✓ ') +
206
+ chalk.white('Auth credentials stored on bridge'),
207
+ );
96
208
  }
97
209
  break;
98
210
  }
@@ -101,28 +213,22 @@ function connect() {
101
213
  const prompt = message.payload.prompt as string;
102
214
  console.log(
103
215
  chalk.hex('#A855F7')(' → ') +
104
- chalk.white('Command received: ') +
105
- chalk.gray(prompt.substring(0, 80) + (prompt.length > 80 ? '...' : '')),
106
- );
107
-
108
- // Send response back
109
- ws!.send(
110
- JSON.stringify({
111
- type: 'response',
112
- payload: {
113
- status: 'received',
114
- message: `Command received: ${prompt.substring(0, 50)}`,
115
- },
116
- timestamp: Date.now(),
117
- }),
216
+ chalk.white('Prompt: ') +
217
+ chalk.gray(
218
+ prompt.substring(0, 80) +
219
+ (prompt.length > 80 ? '...' : ''),
220
+ ),
118
221
  );
222
+ // Bridge handles API proxy now — no need to do anything locally
119
223
  break;
120
224
  }
121
225
 
122
226
  case 'error': {
123
227
  console.log(
124
228
  chalk.hex('#EF4444')(' ✗ ') +
125
- chalk.gray(message.payload.message || 'Unknown error'),
229
+ chalk.gray(
230
+ (message.payload.message as string) || 'Unknown error',
231
+ ),
126
232
  );
127
233
  break;
128
234
  }
@@ -140,7 +246,7 @@ function connect() {
140
246
  scheduleReconnect();
141
247
  });
142
248
 
143
- ws.on('error', (err) => {
249
+ ws.on('error', err => {
144
250
  console.error(
145
251
  chalk.hex('#EF4444')(' ✗ ') +
146
252
  chalk.gray(`Connection error: ${err.message}`),