cursor-bridge 1.0.0 → 1.1.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 +39 -17
  2. package/package.json +1 -1
  3. package/src/index.ts +55 -20
package/dist/index.js CHANGED
@@ -7,10 +7,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
7
7
  const ws_1 = require("ws");
8
8
  const uuid_1 = require("uuid");
9
9
  const chalk_1 = __importDefault(require("chalk"));
10
- const qrcode_terminal_1 = __importDefault(require("qrcode-terminal"));
11
10
  const os_1 = __importDefault(require("os"));
12
11
  const PORT = Number(process.argv[2]) || 9090;
13
12
  const TOKEN = (0, uuid_1.v4)();
13
+ // 6 haneli pair code üret
14
+ function generatePairCode() {
15
+ return Math.floor(100000 + Math.random() * 900000).toString();
16
+ }
17
+ const PAIR_CODE = generatePairCode();
14
18
  const clients = new Map();
15
19
  function getLocalIP() {
16
20
  const interfaces = os_1.default.networkInterfaces();
@@ -38,7 +42,6 @@ function findPeer(clientId) {
38
42
  }
39
43
  function banner() {
40
44
  const ip = getLocalIP();
41
- const pairUrl = `cursor-bridge://${ip}:${PORT}/${TOKEN}`;
42
45
  console.clear();
43
46
  console.log('');
44
47
  console.log(chalk_1.default.hex('#A855F7').bold(' ╔══════════════════════════════════════╗'));
@@ -47,35 +50,51 @@ function banner() {
47
50
  chalk_1.default.hex('#A855F7').bold('║'));
48
51
  console.log(chalk_1.default.hex('#A855F7').bold(' ╚══════════════════════════════════════╝'));
49
52
  console.log('');
50
- console.log(chalk_1.default.gray(' Scan this QR code with the mobile app:'));
53
+ console.log(chalk_1.default.gray(' Enter this code in the mobile app to pair:'));
51
54
  console.log('');
52
- qrcode_terminal_1.default.generate(pairUrl, { small: true }, (qr) => {
53
- const lines = qr.split('\n');
54
- lines.forEach(line => console.log(' ' + line));
55
- });
55
+ console.log(' ' +
56
+ chalk_1.default.bgHex('#A855F7').white.bold(` ${PAIR_CODE.split('').join(' ')} `));
56
57
  console.log('');
57
- console.log(chalk_1.default.gray(' Or connect manually:'));
58
- console.log(chalk_1.default.white(' Host: ') + chalk_1.default.hex('#A855F7')(ip));
59
- console.log(chalk_1.default.white(' Port: ') + chalk_1.default.hex('#A855F7')(String(PORT)));
60
- console.log(chalk_1.default.white(' Token: ') + chalk_1.default.hex('#A855F7')(TOKEN));
58
+ console.log(chalk_1.default.gray(' ─────────────────────────────────────────'));
59
+ console.log(chalk_1.default.gray(' Host: ') + chalk_1.default.white(ip));
60
+ console.log(chalk_1.default.gray(' Port: ') + chalk_1.default.white(String(PORT)));
61
+ console.log(chalk_1.default.gray(' ─────────────────────────────────────────'));
61
62
  console.log('');
62
63
  console.log(chalk_1.default.gray(' Waiting for mobile connection...'));
63
64
  console.log('');
64
65
  }
65
66
  const wss = new ws_1.WebSocketServer({ port: PORT });
67
+ wss.on('error', error => {
68
+ console.error(chalk_1.default.red(' WebSocket error:'), error.message);
69
+ });
66
70
  wss.on('connection', (ws) => {
67
71
  const clientId = (0, uuid_1.v4)();
72
+ ws.on('error', error => {
73
+ console.error(chalk_1.default.red(` Client error:`), error.message);
74
+ clients.delete(clientId);
75
+ });
68
76
  ws.on('message', (raw) => {
69
77
  try {
70
78
  const message = JSON.parse(raw.toString());
71
79
  switch (message.type) {
72
80
  case 'pair': {
73
- const { token, clientType } = message.payload;
81
+ const { pairCode, clientType } = message.payload;
82
+ // Pair code doğrula
83
+ if (pairCode !== PAIR_CODE) {
84
+ ws.send(JSON.stringify({
85
+ type: 'error',
86
+ payload: { message: 'Invalid pair code' },
87
+ timestamp: Date.now(),
88
+ }));
89
+ console.log(chalk_1.default.hex('#EF4444')(' ✗ ') +
90
+ chalk_1.default.gray(`Invalid pair code attempt: ${pairCode}`));
91
+ return;
92
+ }
74
93
  clients.set(clientId, {
75
94
  id: clientId,
76
95
  ws,
77
96
  type: clientType,
78
- token,
97
+ token: TOKEN,
79
98
  });
80
99
  const peer = findPeer(clientId);
81
100
  ws.send(JSON.stringify({
@@ -83,6 +102,8 @@ wss.on('connection', (ws) => {
83
102
  payload: {
84
103
  status: peer ? 'connected' : 'waiting',
85
104
  clientId,
105
+ host: getLocalIP(),
106
+ port: PORT,
86
107
  },
87
108
  timestamp: Date.now(),
88
109
  }));
@@ -93,11 +114,11 @@ wss.on('connection', (ws) => {
93
114
  timestamp: Date.now(),
94
115
  }));
95
116
  console.log(chalk_1.default.hex('#22C55E')(' ✓ ') +
96
- chalk_1.default.white(`${clientType} device connected and paired!`));
117
+ chalk_1.default.white(`${clientType} paired successfully!`));
97
118
  }
98
119
  else {
99
- console.log(chalk_1.default.hex('#F59E0B')(' ') +
100
- chalk_1.default.white(`${clientType} device connected, waiting for peer...`));
120
+ console.log(chalk_1.default.hex('#22C55E')(' ') +
121
+ chalk_1.default.white(`${clientType} connected with pair code`));
101
122
  }
102
123
  break;
103
124
  }
@@ -162,7 +183,7 @@ wss.on('connection', (ws) => {
162
183
  });
163
184
  });
164
185
  // Heartbeat
165
- setInterval(() => {
186
+ const heartbeat = setInterval(() => {
166
187
  clients.forEach(client => {
167
188
  if (client.ws.readyState === ws_1.WebSocket.OPEN) {
168
189
  client.ws.ping();
@@ -173,6 +194,7 @@ banner();
173
194
  process.on('SIGINT', () => {
174
195
  console.log('');
175
196
  console.log(chalk_1.default.gray(' Bridge stopped.'));
197
+ clearInterval(heartbeat);
176
198
  wss.close();
177
199
  process.exit(0);
178
200
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cursor-bridge",
3
- "version": "1.0.0",
3
+ "version": "1.1.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
@@ -3,12 +3,18 @@
3
3
  import { WebSocketServer, WebSocket } from 'ws';
4
4
  import { v4 as uuidv4 } from 'uuid';
5
5
  import chalk from 'chalk';
6
- import qrcode from 'qrcode-terminal';
7
6
  import os from 'os';
8
7
 
9
8
  const PORT = Number(process.argv[2]) || 9090;
10
9
  const TOKEN = uuidv4();
11
10
 
11
+ // 6 haneli pair code üret
12
+ function generatePairCode(): string {
13
+ return Math.floor(100000 + Math.random() * 900000).toString();
14
+ }
15
+
16
+ const PAIR_CODE = generatePairCode();
17
+
12
18
  interface BridgeMessage {
13
19
  type: string;
14
20
  payload: Record<string, unknown>;
@@ -55,7 +61,6 @@ function findPeer(clientId: string): ConnectedClient | undefined {
55
61
 
56
62
  function banner() {
57
63
  const ip = getLocalIP();
58
- const pairUrl = `cursor-bridge://${ip}:${PORT}/${TOKEN}`;
59
64
 
60
65
  console.clear();
61
66
  console.log('');
@@ -71,24 +76,26 @@ function banner() {
71
76
  chalk.hex('#A855F7').bold(' ╚══════════════════════════════════════╝'),
72
77
  );
73
78
  console.log('');
74
- console.log(chalk.gray(' Scan this QR code with the mobile app:'));
79
+ console.log(
80
+ chalk.gray(' Enter this code in the mobile app to pair:'),
81
+ );
75
82
  console.log('');
76
-
77
- qrcode.generate(pairUrl, { small: true }, (qr: string) => {
78
- const lines = qr.split('\n');
79
- lines.forEach(line => console.log(' ' + line));
80
- });
81
-
83
+ console.log(
84
+ ' ' +
85
+ chalk.bgHex('#A855F7').white.bold(` ${PAIR_CODE.split('').join(' ')} `),
86
+ );
82
87
  console.log('');
83
- console.log(chalk.gray(' Or connect manually:'));
84
88
  console.log(
85
- chalk.white(' Host: ') + chalk.hex('#A855F7')(ip),
89
+ chalk.gray(' ─────────────────────────────────────────'),
86
90
  );
87
91
  console.log(
88
- chalk.white(' Port: ') + chalk.hex('#A855F7')(String(PORT)),
92
+ chalk.gray(' Host: ') + chalk.white(ip),
89
93
  );
90
94
  console.log(
91
- chalk.white(' Token: ') + chalk.hex('#A855F7')(TOKEN),
95
+ chalk.gray(' Port: ') + chalk.white(String(PORT)),
96
+ );
97
+ console.log(
98
+ chalk.gray(' ─────────────────────────────────────────'),
92
99
  );
93
100
  console.log('');
94
101
  console.log(chalk.gray(' Waiting for mobile connection...'));
@@ -97,25 +104,50 @@ function banner() {
97
104
 
98
105
  const wss = new WebSocketServer({ port: PORT });
99
106
 
107
+ wss.on('error', error => {
108
+ console.error(chalk.red(' WebSocket error:'), error.message);
109
+ });
110
+
100
111
  wss.on('connection', (ws: WebSocket) => {
101
112
  const clientId = uuidv4();
102
113
 
114
+ ws.on('error', error => {
115
+ console.error(chalk.red(` Client error:`), error.message);
116
+ clients.delete(clientId);
117
+ });
118
+
103
119
  ws.on('message', (raw: Buffer) => {
104
120
  try {
105
121
  const message: BridgeMessage = JSON.parse(raw.toString());
106
122
 
107
123
  switch (message.type) {
108
124
  case 'pair': {
109
- const { token, clientType } = message.payload as {
110
- token: string;
125
+ const { pairCode, clientType } = message.payload as {
126
+ pairCode: string;
111
127
  clientType: 'mobile' | 'desktop';
112
128
  };
113
129
 
130
+ // Pair code doğrula
131
+ if (pairCode !== PAIR_CODE) {
132
+ ws.send(
133
+ JSON.stringify({
134
+ type: 'error',
135
+ payload: { message: 'Invalid pair code' },
136
+ timestamp: Date.now(),
137
+ }),
138
+ );
139
+ console.log(
140
+ chalk.hex('#EF4444')(' ✗ ') +
141
+ chalk.gray(`Invalid pair code attempt: ${pairCode}`),
142
+ );
143
+ return;
144
+ }
145
+
114
146
  clients.set(clientId, {
115
147
  id: clientId,
116
148
  ws,
117
149
  type: clientType,
118
- token,
150
+ token: TOKEN,
119
151
  });
120
152
 
121
153
  const peer = findPeer(clientId);
@@ -126,6 +158,8 @@ wss.on('connection', (ws: WebSocket) => {
126
158
  payload: {
127
159
  status: peer ? 'connected' : 'waiting',
128
160
  clientId,
161
+ host: getLocalIP(),
162
+ port: PORT,
129
163
  },
130
164
  timestamp: Date.now(),
131
165
  }),
@@ -141,12 +175,12 @@ wss.on('connection', (ws: WebSocket) => {
141
175
  );
142
176
  console.log(
143
177
  chalk.hex('#22C55E')(' ✓ ') +
144
- chalk.white(`${clientType} device connected and paired!`),
178
+ chalk.white(`${clientType} paired successfully!`),
145
179
  );
146
180
  } else {
147
181
  console.log(
148
- chalk.hex('#F59E0B')(' ') +
149
- chalk.white(`${clientType} device connected, waiting for peer...`),
182
+ chalk.hex('#22C55E')(' ') +
183
+ chalk.white(`${clientType} connected with pair code`),
150
184
  );
151
185
  }
152
186
  break;
@@ -232,7 +266,7 @@ wss.on('connection', (ws: WebSocket) => {
232
266
  });
233
267
 
234
268
  // Heartbeat
235
- setInterval(() => {
269
+ const heartbeat = setInterval(() => {
236
270
  clients.forEach(client => {
237
271
  if (client.ws.readyState === WebSocket.OPEN) {
238
272
  client.ws.ping();
@@ -245,6 +279,7 @@ banner();
245
279
  process.on('SIGINT', () => {
246
280
  console.log('');
247
281
  console.log(chalk.gray(' Bridge stopped.'));
282
+ clearInterval(heartbeat);
248
283
  wss.close();
249
284
  process.exit(0);
250
285
  });