@remcp/remcp 0.2.22 → 0.2.23

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 (2) hide show
  1. package/package.json +2 -2
  2. package/src/cli.mjs +22 -2
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@remcp/remcp",
3
- "version": "0.2.22",
3
+ "version": "0.2.23",
4
4
  "description": "ReMCP device client: pair a computer with ReMCP and run the outbound-only agent that hosts the local MCP runtime.",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
- "homepage": "https://remcp.delio24.com",
7
+ "homepage": "https://remcp.site",
8
8
  "bin": {
9
9
  "remcp": "bin/remcp.mjs"
10
10
  },
package/src/cli.mjs CHANGED
@@ -252,7 +252,9 @@ async function pairWithDeviceCode(server, flags) {
252
252
  console.log(`Approve this computer in your browser: ${approvalUrl}`);
253
253
  console.log(`Pairing code: ${grant.user_code} (expires in ${Math.max(1, Math.round(Number(grant.expires_in || 600) / 60))} minutes)`);
254
254
  openInBrowser(approvalUrl);
255
+ console.log('Waiting for approval… (Ctrl+C to cancel)');
255
256
  const deadline = Date.now() + (Number(grant.expires_in) || 600) * 1000;
257
+ let lastReminder = Date.now();
256
258
  const intervalMs = Math.max(1, Number(grant.interval) || 5) * 1000;
257
259
  while (Date.now() < deadline) {
258
260
  await sleep(intervalMs);
@@ -262,11 +264,19 @@ async function pairWithDeviceCode(server, flags) {
262
264
  body: new URLSearchParams({
263
265
  grant_type: 'urn:ietf:params:oauth:grant-type:device_code',
264
266
  device_code: String(grant.device_code || ''),
267
+ machineId: ensureMachineId(),
265
268
  }).toString(),
266
269
  });
267
270
  const data = await response.json().catch(() => ({}));
268
271
  if (response.ok && data.device_token) return data;
269
- if (data.error === 'authorization_pending' || data.error === 'slow_down') continue;
272
+ if (data.error === 'authorization_pending' || data.error === 'slow_down') {
273
+ if (Date.now() - lastReminder > 60_000) {
274
+ lastReminder = Date.now();
275
+ const left = Math.max(0, Math.round((deadline - Date.now()) / 60_000));
276
+ console.log(`Still waiting — approve at ${approvalUrl} (about ${left} min left)`);
277
+ }
278
+ continue;
279
+ }
270
280
  if (data.error === 'access_denied') throw new Error('That pairing request was denied in the browser. Run the command again if it was not you.');
271
281
  if (data.error === 'expired_token') break;
272
282
  throw new Error(`Pairing failed (${response.status}): ${JSON.stringify(data)}`);
@@ -434,7 +444,8 @@ export async function main(argv = process.argv.slice(2)) {
434
444
  trustRuntime: Boolean(flags['trust-runtime']) || new URL(server).origin === officialOrigin,
435
445
  };
436
446
  saveConfig(config);
437
- console.log(`Paired ${os.hostname()} with ${server}`);
447
+ const accountEmail = String(paired.account?.email || '');
448
+ console.log(`Paired ${os.hostname()} with ${server}${accountEmail ? ` as ${accountEmail}` : ''}`);
438
449
  if (flags.install) {
439
450
  installPersistentAgent(config);
440
451
  return;
@@ -443,6 +454,15 @@ export async function main(argv = process.argv.slice(2)) {
443
454
  // a fresh machine expects the connection to be live when the command finishes. A workspace code
444
455
  // keeps its old meaning (pair, then `remcp start` or `--install`).
445
456
  if (!deviceInitiated) return;
457
+ // One question, and the machine survives a reboot afterwards. Nothing about the credential
458
+ // changes: the same revocable token is used either way.
459
+ if (!flags.install && process.stdin.isTTY) {
460
+ const answer = await new Promise(resolve => {
461
+ process.stdout.write('Install ReMCP as a background service so it stays connected after a reboot? [Y/n] ');
462
+ process.stdin.once('data', chunk => resolve(String(chunk).trim().toLowerCase()));
463
+ });
464
+ if (answer === '' || answer === 'y' || answer === 'yes') { installPersistentAgent(config); return; }
465
+ }
446
466
  // Nobody supervises this machine yet, so the agent runs in this window: Ctrl+C disconnects it,
447
467
  // which is the behaviour people expect from a command they just ran themselves.
448
468
  console.log('ReMCP is connected. Keep this window open, or run `remcp install` for a background service. Press Ctrl+C to stop.');