remotelink 0.3.0 → 0.3.4

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/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Remote Arc Proprietary Source License
2
+
3
+ Copyright (c) 2026 Remote Arc. All rights reserved.
4
+
5
+ The remotelink package is distributed for use with Remote Arc. You may install
6
+ and execute the officially distributed package for its intended purpose.
7
+
8
+ You may not, except where required by law or expressly authorized in writing,
9
+ modify, redistribute, sublicense, sell, white-label, or create derivative
10
+ products or competing services from this package or substantial portions of it.
11
+
12
+ Third-party dependencies remain governed by their respective licenses.
13
+
14
+ Historical versions previously distributed under the MIT License remain
15
+ subject to the MIT terms that applied to those specific versions.
16
+
17
+ For additional permissions or commercial licensing:
18
+ https://remotearc.app/support
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND.
package/README.md ADDED
@@ -0,0 +1,98 @@
1
+ # remotelink
2
+
3
+ Connect a Windows, macOS, or Linux computer to **Remote Arc** with one command.
4
+
5
+ Remote Arc lets authorized AI clients such as ChatGPT, Claude, and Codex reach
6
+ the computers you explicitly pair through a secure outbound connection.
7
+
8
+ ## Quick start
9
+
10
+ ```bash
11
+ npx remotelink
12
+ ```
13
+
14
+ On first run, `remotelink`:
15
+
16
+ 1. creates a short-lived pairing request;
17
+ 2. opens the Remote Arc pairing page in your browser;
18
+ 3. asks you to sign in and approve the device;
19
+ 4. stores a device credential locally in `~/.remotearc/config.json`;
20
+ 5. connects the computer to Remote Arc over an outbound WebSocket.
21
+
22
+ No public IP, VPN, router port forwarding, repository clone, or manual token
23
+ copy is required.
24
+
25
+ ## Connect your AI client
26
+
27
+ Remote MCP endpoint:
28
+
29
+ ```text
30
+ https://remotearc.app/mcp
31
+ ```
32
+
33
+ Website and device dashboard:
34
+
35
+ ```text
36
+ https://remotearc.app
37
+ ```
38
+
39
+ ## Commands
40
+
41
+ ```text
42
+ npx remotelink Connect using developer mode
43
+ npx remotelink --safe Read-only capability mode
44
+ npx remotelink --developer Read/write/shell capability mode
45
+ npx remotelink --reset Remove local pairing credentials
46
+ npx remotelink --version Show the CLI version
47
+ npx remotelink --help Show help
48
+ ```
49
+
50
+ The package also exposes the aliases `remote-link` and `remote-arc`.
51
+
52
+ ## Local capability model
53
+
54
+ Safe mode exposes read-oriented capabilities such as directory listing,
55
+ file reading, file metadata, and process listing.
56
+
57
+ Developer mode additionally allows process execution and selected file
58
+ modification capabilities.
59
+
60
+ The connected device advertises its actual tool set to Remote Arc. The relay
61
+ will not forward a tool the device did not advertise.
62
+
63
+ ## Security
64
+
65
+ - Each computer receives its own revocable credential.
66
+ - Raw device credentials are not stored in the hosted database.
67
+ - Connections are initiated outbound from your computer.
68
+ - MCP access uses OAuth 2.1 + PKCE.
69
+ - Device access is scoped to the authenticated Remote Arc account.
70
+ - You can revoke paired devices from the Remote Arc dashboard.
71
+
72
+ Remote computer control can modify files and execute commands. Review the
73
+ permissions you grant and use developer mode only on computers you control.
74
+
75
+ ## Requirements
76
+
77
+ - Node.js 20 or later
78
+ - Windows, macOS, or Linux
79
+
80
+ ## Product vs package name
81
+
82
+ **Remote Arc** is the product name.
83
+
84
+ `remotelink` is the npm package and CLI command.
85
+
86
+ ## Support
87
+
88
+ - Website: https://remotearc.app
89
+ - Support: https://remotearc.app/support
90
+ - GitHub: https://github.com/yaohuangguan/remote-arc
91
+
92
+ ## License
93
+
94
+ The Remote Arc implementation is source-available under the **Remote Arc
95
+ Proprietary Source License**. It is not MIT-licensed for new releases.
96
+
97
+ Historical revisions that were previously released under MIT remain governed
98
+ by the MIT terms that applied to those revisions.
package/dist/index.js CHANGED
@@ -9,8 +9,8 @@ import process from "process";
9
9
  import { Client } from "@modelcontextprotocol/client";
10
10
  import { StdioClientTransport } from "@modelcontextprotocol/client/stdio";
11
11
  import WebSocket from "ws";
12
- var VERSION = "0.3.0";
13
- var DEFAULT_ORIGIN = "https://remote.samyao.me";
12
+ var VERSION = "0.3.4";
13
+ var DEFAULT_ORIGIN = "https://mcp.remotearc.app";
14
14
  var CONFIG_DIR = path.join(os.homedir(), ".remotearc");
15
15
  var CONFIG_PATH = path.join(CONFIG_DIR, "config.json");
16
16
  var LEGACY_CONFIG_PATH = path.join(os.homedir(), ".remote-link", "config.json");
@@ -27,6 +27,32 @@ var DEVELOPER_TOOLS = /* @__PURE__ */ new Set([
27
27
  "edit_block"
28
28
  ]);
29
29
  var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
30
+ var supportsColor = process.stdout.isTTY && !process.env.NO_COLOR;
31
+ var paint = (code, value) => supportsColor ? `\x1B[${code}m${value}\x1B[0m` : value;
32
+ var dim = (value) => paint("2", value);
33
+ var cyan = (value) => paint("36", value);
34
+ var green = (value) => paint("32", value);
35
+ var yellow = (value) => paint("33", value);
36
+ var red = (value) => paint("31", value);
37
+ var bold = (value) => paint("1", value);
38
+ function nowTime() {
39
+ return (/* @__PURE__ */ new Date()).toLocaleTimeString([], {
40
+ hour: "2-digit",
41
+ minute: "2-digit",
42
+ second: "2-digit",
43
+ hour12: false
44
+ });
45
+ }
46
+ function logLine(level, message) {
47
+ const icon = level === "success" ? green("\u2713") : level === "warn" ? yellow("!") : level === "error" ? red("\xD7") : level === "event" ? cyan("\u2192") : cyan("\u2022");
48
+ process.stdout.write(`${dim(nowTime())} ${icon} ${message}
49
+ `);
50
+ }
51
+ function banner() {
52
+ process.stdout.write("\n");
53
+ process.stdout.write(bold("Remote Arc") + " " + dim(`v${VERSION}`) + "\n");
54
+ process.stdout.write(dim("Secure remote MCP bridge") + "\n\n");
55
+ }
30
56
  function argFlag(name) {
31
57
  return process.argv.includes(name);
32
58
  }
@@ -43,9 +69,7 @@ async function readConfig() {
43
69
  await fs.readFile(LEGACY_CONFIG_PATH, "utf8")
44
70
  );
45
71
  await writeConfig(legacy);
46
- process.stdout.write(
47
- "Migrated existing Remote Link pairing to Remote Arc.\n"
48
- );
72
+ logLine("success", "Migrated existing Remote Link pairing to Remote Arc.");
49
73
  return legacy;
50
74
  } catch {
51
75
  return null;
@@ -63,7 +87,7 @@ async function resetConfig() {
63
87
  fs.rm(CONFIG_PATH, { force: true }),
64
88
  fs.rm(LEGACY_CONFIG_PATH, { force: true })
65
89
  ]);
66
- process.stdout.write("Remote Arc device credentials removed.\n");
90
+ logLine("success", "Removed saved device credentials.");
67
91
  }
68
92
  function openBrowser(url) {
69
93
  const command = process.platform === "win32" ? "cmd" : process.platform === "darwin" ? "open" : "xdg-open";
@@ -90,12 +114,13 @@ async function pair(origin, mode) {
90
114
  throw new Error("Could not start device pairing: " + response.status);
91
115
  }
92
116
  const pairing = await response.json();
93
- process.stdout.write("\nRemote Arc\n\n");
94
- process.stdout.write("Pair this computer in your browser.\n\n");
95
- process.stdout.write(" " + pairing.user_code + "\n\n");
96
- process.stdout.write(pairing.verification_uri_complete + "\n\n");
97
- process.stdout.write("Opening browser...\n");
117
+ banner();
118
+ logLine("info", `Device: ${bold(deviceName)} \xB7 ${process.platform}/${process.arch} \xB7 ${mode} mode`);
119
+ logLine("event", "Pairing required \u2014 opening secure browser approval.");
120
+ process.stdout.write("\n Pairing code " + bold(cyan(pairing.user_code)) + "\n");
121
+ process.stdout.write(" " + dim(pairing.verification_uri_complete) + "\n\n");
98
122
  openBrowser(pairing.verification_uri_complete);
123
+ logLine("info", "Waiting for authorization\u2026");
99
124
  const startedAt = Date.now();
100
125
  while (Date.now() - startedAt < pairing.expires_in * 1e3) {
101
126
  await sleep(Math.max(pairing.interval, 2) * 1e3);
@@ -108,7 +133,7 @@ async function pair(origin, mode) {
108
133
  })
109
134
  });
110
135
  if (tokenResponse.status === 428) {
111
- process.stdout.write(".");
136
+ if (process.stdout.isTTY) process.stdout.write(dim("\xB7"));
112
137
  continue;
113
138
  }
114
139
  if (!tokenResponse.ok) {
@@ -116,7 +141,8 @@ async function pair(origin, mode) {
116
141
  throw new Error("Pairing failed: " + body);
117
142
  }
118
143
  const result = await tokenResponse.json();
119
- process.stdout.write("\n\n\u2713 Device authorized\n");
144
+ process.stdout.write("\n");
145
+ logLine("success", "Device authorized.");
120
146
  const config = {
121
147
  deviceId: result.device_id,
122
148
  deviceToken: result.device_token,
@@ -147,8 +173,10 @@ var ExecutionCore = class {
147
173
  args: ["-y", "@wonderwhy-er/desktop-commander@latest"],
148
174
  stderr: "inherit"
149
175
  });
176
+ logLine("info", "Starting local execution core\u2026");
150
177
  await client.connect(transport);
151
178
  this.client = client;
179
+ logLine("success", "Local execution core ready.");
152
180
  return client;
153
181
  }
154
182
  async tools() {
@@ -174,7 +202,12 @@ var ExecutionCore = class {
174
202
  };
175
203
  async function connectAgent(config) {
176
204
  const core = new ExecutionCore(config.mode);
205
+ banner();
206
+ logLine("info", `Device: ${bold(config.deviceName)} \xB7 ${process.platform}/${process.arch}`);
207
+ logLine("info", `Permission profile: ${config.mode === "developer" ? yellow("developer") : green("safe")}`);
177
208
  const tools = await core.tools();
209
+ logLine("success", `Local tools ready: ${tools.length} exposed`);
210
+ process.stdout.write(" " + dim(tools.map((tool) => tool.name).join(" \xB7 ")) + "\n");
178
211
  const wsUrl = new URL("/agent", config.origin.replace(/^http/, "ws"));
179
212
  let stopped = false;
180
213
  let backoff = 1e3;
@@ -186,6 +219,7 @@ async function connectAgent(config) {
186
219
  process.on("SIGINT", shutdown);
187
220
  process.on("SIGTERM", shutdown);
188
221
  while (!stopped) {
222
+ logLine("event", `Connecting relay ${dim(wsUrl.host)}\u2026`);
189
223
  const ws = new WebSocket(wsUrl, {
190
224
  headers: {
191
225
  Authorization: "Bearer " + config.deviceToken
@@ -211,11 +245,21 @@ async function connectAgent(config) {
211
245
  tools: tools.map((tool) => tool.name)
212
246
  })
213
247
  );
214
- process.stdout.write(
215
- "\u2713 Connected as " + config.deviceName + " (" + config.mode + " mode)\n"
216
- );
217
- process.stdout.write(" " + config.origin + "\n");
218
- process.stdout.write("Press Ctrl+C to disconnect.\n");
248
+ logLine("success", `Relay connected \xB7 ${bold(config.deviceName)} \xB7 ${config.mode} mode`);
249
+ logLine("success", "Device presence published.");
250
+ process.stdout.write(" " + dim(config.origin) + "\n");
251
+ process.stdout.write(" " + dim("Ctrl+C to disconnect") + "\n\n");
252
+ const sendHeartbeat = async () => {
253
+ try {
254
+ await fetch(new URL("/api/device/heartbeat", config.origin), {
255
+ method: "POST",
256
+ headers: { Authorization: "Bearer " + config.deviceToken }
257
+ });
258
+ } catch {
259
+ }
260
+ };
261
+ void sendHeartbeat();
262
+ const heartbeatTimer = setInterval(() => void sendHeartbeat(), 6e4);
219
263
  await new Promise((resolve) => {
220
264
  ws.on("message", async (raw) => {
221
265
  let message;
@@ -227,11 +271,14 @@ async function connectAgent(config) {
227
271
  if (message.type !== "call" || !message.id || !message.tool) {
228
272
  return;
229
273
  }
274
+ const callStarted = Date.now();
275
+ logLine("event", `tool.call ${bold(message.tool)} \xB7 ${dim(message.id.slice(0, 8))}`);
230
276
  try {
231
277
  const result = await core.call(
232
278
  message.tool,
233
279
  message.arguments || {}
234
280
  );
281
+ logLine("success", `tool.done ${message.tool} \xB7 ${Date.now() - callStarted}ms`);
235
282
  ws.send(
236
283
  JSON.stringify({
237
284
  type: "result",
@@ -240,6 +287,7 @@ async function connectAgent(config) {
240
287
  })
241
288
  );
242
289
  } catch (error) {
290
+ logLine("error", `tool.fail ${message.tool} \xB7 ${error instanceof Error ? error.message : String(error)}`);
243
291
  ws.send(
244
292
  JSON.stringify({
245
293
  type: "result",
@@ -252,17 +300,20 @@ async function connectAgent(config) {
252
300
  ws.once("close", resolve);
253
301
  ws.once("error", resolve);
254
302
  });
303
+ clearInterval(heartbeatTimer);
255
304
  } catch (error) {
256
- process.stderr.write(
257
- "Remote Arc connection failed: " + (error instanceof Error ? error.message : String(error)) + "\n"
305
+ logLine(
306
+ "error",
307
+ "Relay connection failed: " + (error instanceof Error ? error.message : String(error))
258
308
  );
259
309
  } finally {
260
310
  ws.removeAllListeners();
261
311
  ws.close();
262
312
  }
263
313
  if (!stopped) {
264
- process.stdout.write(
265
- "Disconnected. Reconnecting in " + Math.round(backoff / 1e3) + "s...\n"
314
+ logLine(
315
+ "warn",
316
+ "Relay disconnected \xB7 retrying in " + Math.round(backoff / 1e3) + "s"
266
317
  );
267
318
  await sleep(backoff);
268
319
  backoff = Math.min(backoff * 2, 3e4);
@@ -302,17 +353,26 @@ async function main() {
302
353
  }
303
354
  const origin = process.env.REMOTEARC_ORIGIN || process.env.REMOTE_LINK_ORIGIN || process.argv.find((value) => value.startsWith("--origin="))?.slice(9) || DEFAULT_ORIGIN;
304
355
  let config = await readConfig();
356
+ if (config && ["https://remote.samyao.me", "https://remotearc.app"].includes(config.origin)) {
357
+ config.origin = DEFAULT_ORIGIN;
358
+ await writeConfig(config);
359
+ logLine("info", "Migrated relay origin to " + DEFAULT_ORIGIN);
360
+ }
305
361
  if (!config) {
306
362
  config = await pair(origin, selectedMode());
307
363
  } else if (argFlag("--safe") || argFlag("--developer")) {
308
364
  config.mode = selectedMode();
309
365
  await writeConfig(config);
310
366
  }
367
+ if (config) {
368
+ logLine("info", `Using paired device identity ${dim(config.deviceId.slice(0, 8))}\u2026`);
369
+ }
311
370
  await connectAgent(config);
312
371
  }
313
372
  main().catch((error) => {
314
- process.stderr.write(
315
- "\nRemote Arc error: " + (error instanceof Error ? error.message : String(error)) + "\n"
373
+ logLine(
374
+ "error",
375
+ "Fatal: " + (error instanceof Error ? error.message : String(error))
316
376
  );
317
377
  process.exit(1);
318
378
  });
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["#!/usr/bin/env node\r\nimport os from \"node:os\";\r\nimport path from \"node:path\";\r\nimport fs from \"node:fs/promises\";\r\nimport { spawn } from \"node:child_process\";\r\nimport process from \"node:process\";\r\nimport { Client } from \"@modelcontextprotocol/client\";\r\nimport { StdioClientTransport } from \"@modelcontextprotocol/client/stdio\";\r\nimport WebSocket from \"ws\";\r\n\r\nconst VERSION = \"0.3.0\";\r\nconst DEFAULT_ORIGIN = \"https://remote.samyao.me\";\r\nconst CONFIG_DIR = path.join(os.homedir(), \".remotearc\");\r\nconst CONFIG_PATH = path.join(CONFIG_DIR, \"config.json\");\r\nconst LEGACY_CONFIG_PATH = path.join(os.homedir(), \".remote-link\", \"config.json\");\r\n\r\ntype Mode = \"safe\" | \"developer\";\r\n\r\ntype SavedConfig = {\r\n deviceId: string;\r\n deviceToken: string;\r\n deviceName: string;\r\n origin: string;\r\n mode: Mode;\r\n};\r\n\r\ntype PairingStart = {\r\n device_code: string;\r\n device_secret: string;\r\n user_code: string;\r\n verification_uri: string;\r\n verification_uri_complete: string;\r\n expires_in: number;\r\n interval: number;\r\n};\r\n\r\ntype PairingToken = {\r\n device_id: string;\r\n device_token: string;\r\n relay_url: string;\r\n};\r\n\r\nconst SAFE_TOOLS = new Set([\r\n \"list_directory\",\r\n \"read_file\",\r\n \"get_file_info\",\r\n \"list_processes\",\r\n]);\r\n\r\nconst DEVELOPER_TOOLS = new Set([\r\n ...SAFE_TOOLS,\r\n \"start_process\",\r\n \"write_file\",\r\n \"edit_block\",\r\n]);\r\n\r\nconst sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));\r\n\r\nfunction argFlag(name: string) {\r\n return process.argv.includes(name);\r\n}\r\n\r\nfunction selectedMode(): Mode {\r\n if (argFlag(\"--safe\")) return \"safe\";\r\n return \"developer\";\r\n}\r\n\r\nasync function readConfig(): Promise<SavedConfig | null> {\r\n try {\r\n return JSON.parse(await fs.readFile(CONFIG_PATH, \"utf8\")) as SavedConfig;\r\n } catch {\r\n try {\r\n const legacy = JSON.parse(\r\n await fs.readFile(LEGACY_CONFIG_PATH, \"utf8\"),\r\n ) as SavedConfig;\r\n await writeConfig(legacy);\r\n process.stdout.write(\r\n \"Migrated existing Remote Link pairing to Remote Arc.\\n\",\r\n );\r\n return legacy;\r\n } catch {\r\n return null;\r\n }\r\n }\r\n}\r\n\r\nasync function writeConfig(config: SavedConfig) {\r\n await fs.mkdir(CONFIG_DIR, { recursive: true });\r\n await fs.writeFile(CONFIG_PATH, JSON.stringify(config, null, 2) + \"\\n\", {\r\n mode: 0o600,\r\n });\r\n}\r\n\r\nasync function resetConfig() {\r\n await Promise.all([\r\n fs.rm(CONFIG_PATH, { force: true }),\r\n fs.rm(LEGACY_CONFIG_PATH, { force: true }),\r\n ]);\r\n process.stdout.write(\"Remote Arc device credentials removed.\\n\");\r\n}\r\n\r\nfunction openBrowser(url: string) {\r\n const command =\r\n process.platform === \"win32\"\r\n ? \"cmd\"\r\n : process.platform === \"darwin\"\r\n ? \"open\"\r\n : \"xdg-open\";\r\n const args =\r\n process.platform === \"win32\"\r\n ? [\"/c\", \"start\", \"\", url]\r\n : [url];\r\n\r\n const child = spawn(command, args, {\r\n detached: true,\r\n stdio: \"ignore\",\r\n });\r\n child.unref();\r\n}\r\n\r\nasync function pair(origin: string, mode: Mode): Promise<SavedConfig> {\r\n const deviceName = os.hostname();\r\n const response = await fetch(origin + \"/api/device/start\", {\r\n method: \"POST\",\r\n headers: { \"content-type\": \"application/json\" },\r\n body: JSON.stringify({\r\n device_name: deviceName,\r\n platform: process.platform,\r\n arch: process.arch,\r\n hostname: os.hostname(),\r\n }),\r\n });\r\n\r\n if (!response.ok) {\r\n throw new Error(\"Could not start device pairing: \" + response.status);\r\n }\r\n\r\n const pairing = (await response.json()) as PairingStart;\r\n\r\n process.stdout.write(\"\\nRemote Arc\\n\\n\");\r\n process.stdout.write(\"Pair this computer in your browser.\\n\\n\");\r\n process.stdout.write(\" \" + pairing.user_code + \"\\n\\n\");\r\n process.stdout.write(pairing.verification_uri_complete + \"\\n\\n\");\r\n process.stdout.write(\"Opening browser...\\n\");\r\n openBrowser(pairing.verification_uri_complete);\r\n\r\n const startedAt = Date.now();\r\n while (Date.now() - startedAt < pairing.expires_in * 1000) {\r\n await sleep(Math.max(pairing.interval, 2) * 1000);\r\n\r\n const tokenResponse = await fetch(origin + \"/api/device/token\", {\r\n method: \"POST\",\r\n headers: { \"content-type\": \"application/json\" },\r\n body: JSON.stringify({\r\n device_code: pairing.device_code,\r\n device_secret: pairing.device_secret,\r\n }),\r\n });\r\n\r\n if (tokenResponse.status === 428) {\r\n process.stdout.write(\".\");\r\n continue;\r\n }\r\n\r\n if (!tokenResponse.ok) {\r\n const body = await tokenResponse.text();\r\n throw new Error(\"Pairing failed: \" + body);\r\n }\r\n\r\n const result = (await tokenResponse.json()) as PairingToken;\r\n process.stdout.write(\"\\n\\n✓ Device authorized\\n\");\r\n\r\n const config: SavedConfig = {\r\n deviceId: result.device_id,\r\n deviceToken: result.device_token,\r\n deviceName,\r\n origin,\r\n mode,\r\n };\r\n await writeConfig(config);\r\n return config;\r\n }\r\n\r\n throw new Error(\"Pairing expired. Run Remote Arc again to retry.\");\r\n}\r\n\r\nclass ExecutionCore {\r\n private client: Client | null = null;\r\n\r\n constructor(private readonly mode: Mode) {}\r\n\r\n async connect() {\r\n if (this.client) return this.client;\r\n\r\n const client = new Client({\r\n name: \"remotearc-cli-core\",\r\n version: VERSION,\r\n });\r\n\r\n const command = process.platform === \"win32\" ? \"npx.cmd\" : \"npx\";\r\n const transport = new StdioClientTransport({\r\n command,\r\n args: [\"-y\", \"@wonderwhy-er/desktop-commander@latest\"],\r\n stderr: \"inherit\",\r\n });\r\n\r\n await client.connect(transport);\r\n this.client = client;\r\n return client;\r\n }\r\n\r\n async tools() {\r\n const list = await (await this.connect()).listTools();\r\n const allowed = this.mode === \"developer\" ? DEVELOPER_TOOLS : SAFE_TOOLS;\r\n return list.tools.filter((tool) => allowed.has(tool.name));\r\n }\r\n\r\n async call(name: string, args: Record<string, unknown>) {\r\n const allowed = this.mode === \"developer\" ? DEVELOPER_TOOLS : SAFE_TOOLS;\r\n if (!allowed.has(name)) {\r\n throw new Error(\"Tool blocked by local permission mode: \" + name);\r\n }\r\n\r\n return (await this.connect()).callTool({\r\n name,\r\n arguments: args,\r\n });\r\n }\r\n\r\n async close() {\r\n if (!this.client) return;\r\n await this.client.close();\r\n this.client = null;\r\n }\r\n}\r\n\r\nasync function connectAgent(config: SavedConfig) {\r\n const core = new ExecutionCore(config.mode);\r\n const tools = await core.tools();\r\n const wsUrl = new URL(\"/agent\", config.origin.replace(/^http/, \"ws\"));\r\n\r\n let stopped = false;\r\n let backoff = 1000;\r\n\r\n const shutdown = async () => {\r\n stopped = true;\r\n await core.close().catch(() => undefined);\r\n process.exit(0);\r\n };\r\n process.on(\"SIGINT\", shutdown);\r\n process.on(\"SIGTERM\", shutdown);\r\n\r\n while (!stopped) {\r\n const ws = new WebSocket(wsUrl, {\r\n headers: {\r\n Authorization: \"Bearer \" + config.deviceToken,\r\n },\r\n });\r\n\r\n try {\r\n await new Promise<void>((resolve, reject) => {\r\n ws.once(\"open\", resolve);\r\n ws.once(\"error\", reject);\r\n });\r\n\r\n backoff = 1000;\r\n ws.send(\r\n JSON.stringify({\r\n type: \"hello\",\r\n device: {\r\n id: config.deviceId,\r\n name: config.deviceName,\r\n platform: process.platform,\r\n arch: process.arch,\r\n hostname: os.hostname(),\r\n agentVersion: VERSION,\r\n },\r\n tools: tools.map((tool) => tool.name),\r\n }),\r\n );\r\n\r\n process.stdout.write(\r\n \"✓ Connected as \" +\r\n config.deviceName +\r\n \" (\" +\r\n config.mode +\r\n \" mode)\\n\",\r\n );\r\n process.stdout.write(\" \" + config.origin + \"\\n\");\r\n process.stdout.write(\"Press Ctrl+C to disconnect.\\n\");\r\n\r\n await new Promise<void>((resolve) => {\r\n ws.on(\"message\", async (raw) => {\r\n let message: {\r\n type?: string;\r\n id?: string;\r\n tool?: string;\r\n arguments?: Record<string, unknown>;\r\n };\r\n\r\n try {\r\n message = JSON.parse(raw.toString());\r\n } catch {\r\n return;\r\n }\r\n\r\n if (\r\n message.type !== \"call\" ||\r\n !message.id ||\r\n !message.tool\r\n ) {\r\n return;\r\n }\r\n\r\n try {\r\n const result = await core.call(\r\n message.tool,\r\n message.arguments || {},\r\n );\r\n ws.send(\r\n JSON.stringify({\r\n type: \"result\",\r\n id: message.id,\r\n result,\r\n }),\r\n );\r\n } catch (error) {\r\n ws.send(\r\n JSON.stringify({\r\n type: \"result\",\r\n id: message.id,\r\n error: error instanceof Error ? error.message : String(error),\r\n }),\r\n );\r\n }\r\n });\r\n\r\n ws.once(\"close\", resolve);\r\n ws.once(\"error\", resolve);\r\n });\r\n } catch (error) {\r\n process.stderr.write(\r\n \"Remote Arc connection failed: \" +\r\n (error instanceof Error ? error.message : String(error)) +\r\n \"\\n\",\r\n );\r\n } finally {\r\n ws.removeAllListeners();\r\n ws.close();\r\n }\r\n\r\n if (!stopped) {\r\n process.stdout.write(\r\n \"Disconnected. Reconnecting in \" + Math.round(backoff / 1000) + \"s...\\n\",\r\n );\r\n await sleep(backoff);\r\n backoff = Math.min(backoff * 2, 30_000);\r\n }\r\n }\r\n}\r\n\r\nasync function main() {\r\n if (argFlag(\"--help\") || argFlag(\"-h\")) {\r\n process.stdout.write(\r\n [\r\n \"Remote Arc\",\r\n \"\",\r\n \"Usage:\",\r\n \" npx remotelink\",\r\n \"\",\r\n \"After the npm release:\",\r\n \" npx remotelink\",\r\n \"\",\r\n \"Options:\",\r\n \" --safe Read-only local capability mode\",\r\n \" --developer Read/write/shell mode (default)\",\r\n \" --reset Remove this computer's saved pairing\",\r\n \" --version Print CLI version\",\r\n \" --help Show this help\",\r\n \"\",\r\n ].join(\"\\n\"),\r\n );\r\n return;\r\n }\r\n\r\n if (argFlag(\"--version\") || argFlag(\"-v\")) {\r\n process.stdout.write(VERSION + \"\\n\");\r\n return;\r\n }\r\n\r\n if (argFlag(\"--reset\")) {\r\n await resetConfig();\r\n return;\r\n }\r\n\r\n const origin =\r\n process.env.REMOTEARC_ORIGIN || process.env.REMOTE_LINK_ORIGIN ||\r\n process.argv.find((value) => value.startsWith(\"--origin=\"))?.slice(9) ||\r\n DEFAULT_ORIGIN;\r\n\r\n let config = await readConfig();\r\n if (!config) {\r\n config = await pair(origin, selectedMode());\r\n } else if (argFlag(\"--safe\") || argFlag(\"--developer\")) {\r\n config.mode = selectedMode();\r\n await writeConfig(config);\r\n }\r\n\r\n await connectAgent(config);\r\n}\r\n\r\nmain().catch((error) => {\r\n process.stderr.write(\r\n \"\\nRemote Arc error: \" +\r\n (error instanceof Error ? error.message : String(error)) +\r\n \"\\n\",\r\n );\r\n process.exit(1);\r\n});\r\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["#!/usr/bin/env node\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport fs from \"node:fs/promises\";\nimport { spawn } from \"node:child_process\";\nimport process from \"node:process\";\nimport { Client } from \"@modelcontextprotocol/client\";\nimport { StdioClientTransport } from \"@modelcontextprotocol/client/stdio\";\nimport WebSocket from \"ws\";\n\nconst VERSION = \"0.3.4\";\nconst DEFAULT_ORIGIN = \"https://mcp.remotearc.app\";\nconst CONFIG_DIR = path.join(os.homedir(), \".remotearc\");\nconst CONFIG_PATH = path.join(CONFIG_DIR, \"config.json\");\nconst LEGACY_CONFIG_PATH = path.join(os.homedir(), \".remote-link\", \"config.json\");\n\ntype Mode = \"safe\" | \"developer\";\n\ntype SavedConfig = {\n deviceId: string;\n deviceToken: string;\n deviceName: string;\n origin: string;\n mode: Mode;\n};\n\ntype PairingStart = {\n device_code: string;\n device_secret: string;\n user_code: string;\n verification_uri: string;\n verification_uri_complete: string;\n expires_in: number;\n interval: number;\n};\n\ntype PairingToken = {\n device_id: string;\n device_token: string;\n relay_url: string;\n};\n\nconst SAFE_TOOLS = new Set([\n \"list_directory\",\n \"read_file\",\n \"get_file_info\",\n \"list_processes\",\n]);\n\nconst DEVELOPER_TOOLS = new Set([\n ...SAFE_TOOLS,\n \"start_process\",\n \"write_file\",\n \"edit_block\",\n]);\n\nconst sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));\n\nconst supportsColor = process.stdout.isTTY && !process.env.NO_COLOR;\nconst paint = (code: string, value: string) =>\n supportsColor ? `\\x1b[${code}m${value}\\x1b[0m` : value;\nconst dim = (value: string) => paint(\"2\", value);\nconst cyan = (value: string) => paint(\"36\", value);\nconst green = (value: string) => paint(\"32\", value);\nconst yellow = (value: string) => paint(\"33\", value);\nconst red = (value: string) => paint(\"31\", value);\nconst bold = (value: string) => paint(\"1\", value);\n\nfunction nowTime() {\n return new Date().toLocaleTimeString([], {\n hour: \"2-digit\",\n minute: \"2-digit\",\n second: \"2-digit\",\n hour12: false,\n });\n}\n\nfunction logLine(\n level: \"info\" | \"success\" | \"warn\" | \"error\" | \"event\",\n message: string,\n) {\n const icon =\n level === \"success\" ? green(\"✓\") :\n level === \"warn\" ? yellow(\"!\") :\n level === \"error\" ? red(\"×\") :\n level === \"event\" ? cyan(\"→\") :\n cyan(\"•\");\n process.stdout.write(`${dim(nowTime())} ${icon} ${message}\\n`);\n}\n\nfunction banner() {\n process.stdout.write(\"\\n\");\n process.stdout.write(bold(\"Remote Arc\") + \" \" + dim(`v${VERSION}`) + \"\\n\");\n process.stdout.write(dim(\"Secure remote MCP bridge\") + \"\\n\\n\");\n}\n\nfunction argFlag(name: string) {\n return process.argv.includes(name);\n}\n\nfunction selectedMode(): Mode {\n if (argFlag(\"--safe\")) return \"safe\";\n return \"developer\";\n}\n\nasync function readConfig(): Promise<SavedConfig | null> {\n try {\n return JSON.parse(await fs.readFile(CONFIG_PATH, \"utf8\")) as SavedConfig;\n } catch {\n try {\n const legacy = JSON.parse(\n await fs.readFile(LEGACY_CONFIG_PATH, \"utf8\"),\n ) as SavedConfig;\n await writeConfig(legacy);\n logLine(\"success\", \"Migrated existing Remote Link pairing to Remote Arc.\");\n return legacy;\n } catch {\n return null;\n }\n }\n}\n\nasync function writeConfig(config: SavedConfig) {\n await fs.mkdir(CONFIG_DIR, { recursive: true });\n await fs.writeFile(CONFIG_PATH, JSON.stringify(config, null, 2) + \"\\n\", {\n mode: 0o600,\n });\n}\n\nasync function resetConfig() {\n await Promise.all([\n fs.rm(CONFIG_PATH, { force: true }),\n fs.rm(LEGACY_CONFIG_PATH, { force: true }),\n ]);\n logLine(\"success\", \"Removed saved device credentials.\");\n}\n\nfunction openBrowser(url: string) {\n const command =\n process.platform === \"win32\"\n ? \"cmd\"\n : process.platform === \"darwin\"\n ? \"open\"\n : \"xdg-open\";\n const args =\n process.platform === \"win32\"\n ? [\"/c\", \"start\", \"\", url]\n : [url];\n\n const child = spawn(command, args, {\n detached: true,\n stdio: \"ignore\",\n });\n child.unref();\n}\n\nasync function pair(origin: string, mode: Mode): Promise<SavedConfig> {\n const deviceName = os.hostname();\n const response = await fetch(origin + \"/api/device/start\", {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({\n device_name: deviceName,\n platform: process.platform,\n arch: process.arch,\n hostname: os.hostname(),\n }),\n });\n\n if (!response.ok) {\n throw new Error(\"Could not start device pairing: \" + response.status);\n }\n\n const pairing = (await response.json()) as PairingStart;\n\n banner();\n logLine(\"info\", `Device: ${bold(deviceName)} · ${process.platform}/${process.arch} · ${mode} mode`);\n logLine(\"event\", \"Pairing required — opening secure browser approval.\");\n process.stdout.write(\"\\n Pairing code \" + bold(cyan(pairing.user_code)) + \"\\n\");\n process.stdout.write(\" \" + dim(pairing.verification_uri_complete) + \"\\n\\n\");\n openBrowser(pairing.verification_uri_complete);\n logLine(\"info\", \"Waiting for authorization…\");\n\n const startedAt = Date.now();\n while (Date.now() - startedAt < pairing.expires_in * 1000) {\n await sleep(Math.max(pairing.interval, 2) * 1000);\n\n const tokenResponse = await fetch(origin + \"/api/device/token\", {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({\n device_code: pairing.device_code,\n device_secret: pairing.device_secret,\n }),\n });\n\n if (tokenResponse.status === 428) {\n if (process.stdout.isTTY) process.stdout.write(dim(\"·\"));\n continue;\n }\n\n if (!tokenResponse.ok) {\n const body = await tokenResponse.text();\n throw new Error(\"Pairing failed: \" + body);\n }\n\n const result = (await tokenResponse.json()) as PairingToken;\n process.stdout.write(\"\\n\");\n logLine(\"success\", \"Device authorized.\");\n\n const config: SavedConfig = {\n deviceId: result.device_id,\n deviceToken: result.device_token,\n deviceName,\n origin,\n mode,\n };\n await writeConfig(config);\n return config;\n }\n\n throw new Error(\"Pairing expired. Run Remote Arc again to retry.\");\n}\n\nclass ExecutionCore {\n private client: Client | null = null;\n\n constructor(private readonly mode: Mode) {}\n\n async connect() {\n if (this.client) return this.client;\n\n const client = new Client({\n name: \"remotearc-cli-core\",\n version: VERSION,\n });\n\n const command = process.platform === \"win32\" ? \"npx.cmd\" : \"npx\";\n const transport = new StdioClientTransport({\n command,\n args: [\"-y\", \"@wonderwhy-er/desktop-commander@latest\"],\n stderr: \"inherit\",\n });\n\n logLine(\"info\", \"Starting local execution core…\");\n await client.connect(transport);\n this.client = client;\n logLine(\"success\", \"Local execution core ready.\");\n return client;\n }\n\n async tools() {\n const list = await (await this.connect()).listTools();\n const allowed = this.mode === \"developer\" ? DEVELOPER_TOOLS : SAFE_TOOLS;\n return list.tools.filter((tool) => allowed.has(tool.name));\n }\n\n async call(name: string, args: Record<string, unknown>) {\n const allowed = this.mode === \"developer\" ? DEVELOPER_TOOLS : SAFE_TOOLS;\n if (!allowed.has(name)) {\n throw new Error(\"Tool blocked by local permission mode: \" + name);\n }\n\n return (await this.connect()).callTool({\n name,\n arguments: args,\n });\n }\n\n async close() {\n if (!this.client) return;\n await this.client.close();\n this.client = null;\n }\n}\n\nasync function connectAgent(config: SavedConfig) {\n const core = new ExecutionCore(config.mode);\n banner();\n logLine(\"info\", `Device: ${bold(config.deviceName)} · ${process.platform}/${process.arch}`);\n logLine(\"info\", `Permission profile: ${config.mode === \"developer\" ? yellow(\"developer\") : green(\"safe\")}`);\n\n const tools = await core.tools();\n logLine(\"success\", `Local tools ready: ${tools.length} exposed`);\n process.stdout.write(\" \" + dim(tools.map((tool) => tool.name).join(\" · \")) + \"\\n\");\n const wsUrl = new URL(\"/agent\", config.origin.replace(/^http/, \"ws\"));\n\n let stopped = false;\n let backoff = 1000;\n\n const shutdown = async () => {\n stopped = true;\n await core.close().catch(() => undefined);\n process.exit(0);\n };\n process.on(\"SIGINT\", shutdown);\n process.on(\"SIGTERM\", shutdown);\n\n while (!stopped) {\n logLine(\"event\", `Connecting relay ${dim(wsUrl.host)}…`);\n const ws = new WebSocket(wsUrl, {\n headers: {\n Authorization: \"Bearer \" + config.deviceToken,\n },\n });\n\n try {\n await new Promise<void>((resolve, reject) => {\n ws.once(\"open\", resolve);\n ws.once(\"error\", reject);\n });\n\n backoff = 1000;\n ws.send(\n JSON.stringify({\n type: \"hello\",\n device: {\n id: config.deviceId,\n name: config.deviceName,\n platform: process.platform,\n arch: process.arch,\n hostname: os.hostname(),\n agentVersion: VERSION,\n },\n tools: tools.map((tool) => tool.name),\n }),\n );\n\n logLine(\"success\", `Relay connected · ${bold(config.deviceName)} · ${config.mode} mode`);\n logLine(\"success\", \"Device presence published.\");\n process.stdout.write(\" \" + dim(config.origin) + \"\\n\");\n process.stdout.write(\" \" + dim(\"Ctrl+C to disconnect\") + \"\\n\\n\");\n\n const sendHeartbeat = async () => {\n try {\n await fetch(new URL(\"/api/device/heartbeat\", config.origin), {\n method: \"POST\",\n headers: { Authorization: \"Bearer \" + config.deviceToken },\n });\n } catch {\n // WebSocket reconnect logic remains the source of truth for connectivity.\n }\n };\n void sendHeartbeat();\n const heartbeatTimer = setInterval(() => void sendHeartbeat(), 60_000);\n\n await new Promise<void>((resolve) => {\n ws.on(\"message\", async (raw) => {\n let message: {\n type?: string;\n id?: string;\n tool?: string;\n arguments?: Record<string, unknown>;\n };\n\n try {\n message = JSON.parse(raw.toString());\n } catch {\n return;\n }\n\n if (\n message.type !== \"call\" ||\n !message.id ||\n !message.tool\n ) {\n return;\n }\n\n const callStarted = Date.now();\n logLine(\"event\", `tool.call ${bold(message.tool)} · ${dim(message.id.slice(0, 8))}`);\n try {\n const result = await core.call(\n message.tool,\n message.arguments || {},\n );\n logLine(\"success\", `tool.done ${message.tool} · ${Date.now() - callStarted}ms`);\n ws.send(\n JSON.stringify({\n type: \"result\",\n id: message.id,\n result,\n }),\n );\n } catch (error) {\n logLine(\"error\", `tool.fail ${message.tool} · ${error instanceof Error ? error.message : String(error)}`);\n ws.send(\n JSON.stringify({\n type: \"result\",\n id: message.id,\n error: error instanceof Error ? error.message : String(error),\n }),\n );\n }\n });\n\n ws.once(\"close\", resolve);\n ws.once(\"error\", resolve);\n });\n clearInterval(heartbeatTimer);\n } catch (error) {\n logLine(\n \"error\",\n \"Relay connection failed: \" +\n (error instanceof Error ? error.message : String(error)),\n );\n } finally {\n ws.removeAllListeners();\n ws.close();\n }\n\n if (!stopped) {\n logLine(\n \"warn\",\n \"Relay disconnected · retrying in \" + Math.round(backoff / 1000) + \"s\",\n );\n await sleep(backoff);\n backoff = Math.min(backoff * 2, 30_000);\n }\n }\n}\n\nasync function main() {\n if (argFlag(\"--help\") || argFlag(\"-h\")) {\n process.stdout.write(\n [\n \"Remote Arc\",\n \"\",\n \"Usage:\",\n \" npx remotelink\",\n \"\",\n \"After the npm release:\",\n \" npx remotelink\",\n \"\",\n \"Options:\",\n \" --safe Read-only local capability mode\",\n \" --developer Read/write/shell mode (default)\",\n \" --reset Remove this computer's saved pairing\",\n \" --version Print CLI version\",\n \" --help Show this help\",\n \"\",\n ].join(\"\\n\"),\n );\n return;\n }\n\n if (argFlag(\"--version\") || argFlag(\"-v\")) {\n process.stdout.write(VERSION + \"\\n\");\n return;\n }\n\n if (argFlag(\"--reset\")) {\n await resetConfig();\n return;\n }\n\n const origin =\n process.env.REMOTEARC_ORIGIN || process.env.REMOTE_LINK_ORIGIN ||\n process.argv.find((value) => value.startsWith(\"--origin=\"))?.slice(9) ||\n DEFAULT_ORIGIN;\n\n let config = await readConfig();\n if (config && [\"https://remote.samyao.me\", \"https://remotearc.app\"].includes(config.origin)) {\n config.origin = DEFAULT_ORIGIN;\n await writeConfig(config);\n logLine(\"info\", \"Migrated relay origin to \" + DEFAULT_ORIGIN);\n }\n if (!config) {\n config = await pair(origin, selectedMode());\n } else if (argFlag(\"--safe\") || argFlag(\"--developer\")) {\n config.mode = selectedMode();\n await writeConfig(config);\n }\n\n if (config) {\n logLine(\"info\", `Using paired device identity ${dim(config.deviceId.slice(0, 8))}…`);\n }\n await connectAgent(config);\n}\n\nmain().catch((error) => {\n logLine(\n \"error\",\n \"Fatal: \" + (error instanceof Error ? error.message : String(error)),\n );\n process.exit(1);\n});\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "remotelink",
3
- "version": "0.3.0",
3
+ "version": "0.3.4",
4
4
  "description": "Connect a computer to Remote Arc with one command.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -9,7 +9,9 @@
9
9
  "remote-arc": "dist/index.js"
10
10
  },
11
11
  "files": [
12
- "dist"
12
+ "dist",
13
+ "README.md",
14
+ "LICENSE"
13
15
  ],
14
16
  "engines": {
15
17
  "node": ">=20"
@@ -28,5 +30,24 @@
28
30
  "@types/ws": "^8.18.1",
29
31
  "tsup": "^8.5.0",
30
32
  "typescript": "^6.0.3"
31
- }
33
+ },
34
+ "license": "UNLICENSED",
35
+ "homepage": "https://remotearc.app",
36
+ "repository": {
37
+ "type": "git",
38
+ "url": "git+https://github.com/yaohuangguan/remote-arc.git",
39
+ "directory": "packages/cli"
40
+ },
41
+ "bugs": {
42
+ "url": "https://github.com/yaohuangguan/remote-arc/issues"
43
+ },
44
+ "keywords": [
45
+ "remote",
46
+ "mcp",
47
+ "chatgpt",
48
+ "claude",
49
+ "codex",
50
+ "remote-computer",
51
+ "developer-tools"
52
+ ]
32
53
  }