@remcp/remcp 0.2.21 → 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.
- package/README.md +2 -2
- package/package.json +2 -2
- package/src/cli.mjs +23 -3
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@ remcp --version
|
|
|
9
9
|
remcp status
|
|
10
10
|
```
|
|
11
11
|
|
|
12
|
-
Pairing commands are generated in the workspace at <https://remcp.
|
|
12
|
+
Pairing commands are generated in the workspace at <https://remcp.site/app/connect>. The
|
|
13
13
|
generated command runs `remcp connect --server … --code … --install`, which stores a per-device
|
|
14
14
|
credential under `~/.config/remcp/`, installs the runtime from npm, and registers a user service
|
|
15
15
|
(systemd on Linux, LaunchAgent on macOS, Scheduled Task on Windows).
|
|
@@ -34,7 +34,7 @@ and the current usage-metrics state, so a support request can be answered with o
|
|
|
34
34
|
## What runs on your computer
|
|
35
35
|
|
|
36
36
|
- the agent (`remcp start`), which holds the device credential and dials
|
|
37
|
-
`wss://remcp.
|
|
37
|
+
`wss://remcp.site/agent`;
|
|
38
38
|
- [`@remcp/runtime`](https://www.npmjs.com/package/@remcp/runtime), spawned by the agent as an MCP
|
|
39
39
|
stdio server. The runtime executes the tools, opens no network connection, and is supervised: if it
|
|
40
40
|
exits, the agent restarts it with backoff and reports the restart instead of failing silently.
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remcp/remcp",
|
|
3
|
-
"version": "0.2.
|
|
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.
|
|
7
|
+
"homepage": "https://remcp.site",
|
|
8
8
|
"bin": {
|
|
9
9
|
"remcp": "bin/remcp.mjs"
|
|
10
10
|
},
|
package/src/cli.mjs
CHANGED
|
@@ -22,7 +22,7 @@ const windowsTaskName = 'ReMCP Agent';
|
|
|
22
22
|
// How npm is invoked is resolved from the running node when possible: a background service has a
|
|
23
23
|
// minimal PATH, which is why auto-update used to find no npm on macOS. See src/npm.mjs.
|
|
24
24
|
const npm = resolveNpm();
|
|
25
|
-
const officialOrigin = 'https://remcp.
|
|
25
|
+
const officialOrigin = 'https://remcp.site';
|
|
26
26
|
|
|
27
27
|
function parse(argv) {
|
|
28
28
|
const [command = 'help', ...rest] = argv;
|
|
@@ -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')
|
|
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
|
-
|
|
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.');
|