remotelink 0.2.0 → 0.3.2

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,10 +9,11 @@ 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.2.0";
13
- var DEFAULT_ORIGIN = "https://remote.samyao.me";
14
- var CONFIG_DIR = path.join(os.homedir(), ".remote-link");
12
+ var VERSION = "0.3.2";
13
+ var DEFAULT_ORIGIN = "https://remotearc.app";
14
+ var CONFIG_DIR = path.join(os.homedir(), ".remotearc");
15
15
  var CONFIG_PATH = path.join(CONFIG_DIR, "config.json");
16
+ var LEGACY_CONFIG_PATH = path.join(os.homedir(), ".remote-link", "config.json");
16
17
  var SAFE_TOOLS = /* @__PURE__ */ new Set([
17
18
  "list_directory",
18
19
  "read_file",
@@ -26,6 +27,32 @@ var DEVELOPER_TOOLS = /* @__PURE__ */ new Set([
26
27
  "edit_block"
27
28
  ]);
28
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
+ }
29
56
  function argFlag(name) {
30
57
  return process.argv.includes(name);
31
58
  }
@@ -37,7 +64,16 @@ async function readConfig() {
37
64
  try {
38
65
  return JSON.parse(await fs.readFile(CONFIG_PATH, "utf8"));
39
66
  } catch {
40
- return null;
67
+ try {
68
+ const legacy = JSON.parse(
69
+ await fs.readFile(LEGACY_CONFIG_PATH, "utf8")
70
+ );
71
+ await writeConfig(legacy);
72
+ logLine("success", "Migrated existing Remote Link pairing to Remote Arc.");
73
+ return legacy;
74
+ } catch {
75
+ return null;
76
+ }
41
77
  }
42
78
  }
43
79
  async function writeConfig(config) {
@@ -47,8 +83,11 @@ async function writeConfig(config) {
47
83
  });
48
84
  }
49
85
  async function resetConfig() {
50
- await fs.rm(CONFIG_PATH, { force: true });
51
- process.stdout.write("Remote Link device credentials removed.\n");
86
+ await Promise.all([
87
+ fs.rm(CONFIG_PATH, { force: true }),
88
+ fs.rm(LEGACY_CONFIG_PATH, { force: true })
89
+ ]);
90
+ logLine("success", "Removed saved device credentials.");
52
91
  }
53
92
  function openBrowser(url) {
54
93
  const command = process.platform === "win32" ? "cmd" : process.platform === "darwin" ? "open" : "xdg-open";
@@ -75,12 +114,13 @@ async function pair(origin, mode) {
75
114
  throw new Error("Could not start device pairing: " + response.status);
76
115
  }
77
116
  const pairing = await response.json();
78
- process.stdout.write("\nRemote Link\n\n");
79
- process.stdout.write("Pair this computer in your browser.\n\n");
80
- process.stdout.write(" " + pairing.user_code + "\n\n");
81
- process.stdout.write(pairing.verification_uri_complete + "\n\n");
82
- 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");
83
122
  openBrowser(pairing.verification_uri_complete);
123
+ logLine("info", "Waiting for authorization\u2026");
84
124
  const startedAt = Date.now();
85
125
  while (Date.now() - startedAt < pairing.expires_in * 1e3) {
86
126
  await sleep(Math.max(pairing.interval, 2) * 1e3);
@@ -93,7 +133,7 @@ async function pair(origin, mode) {
93
133
  })
94
134
  });
95
135
  if (tokenResponse.status === 428) {
96
- process.stdout.write(".");
136
+ if (process.stdout.isTTY) process.stdout.write(dim("\xB7"));
97
137
  continue;
98
138
  }
99
139
  if (!tokenResponse.ok) {
@@ -101,7 +141,8 @@ async function pair(origin, mode) {
101
141
  throw new Error("Pairing failed: " + body);
102
142
  }
103
143
  const result = await tokenResponse.json();
104
- process.stdout.write("\n\n\u2713 Device authorized\n");
144
+ process.stdout.write("\n");
145
+ logLine("success", "Device authorized.");
105
146
  const config = {
106
147
  deviceId: result.device_id,
107
148
  deviceToken: result.device_token,
@@ -112,7 +153,7 @@ async function pair(origin, mode) {
112
153
  await writeConfig(config);
113
154
  return config;
114
155
  }
115
- throw new Error("Pairing expired. Run Remote Link again to retry.");
156
+ throw new Error("Pairing expired. Run Remote Arc again to retry.");
116
157
  }
117
158
  var ExecutionCore = class {
118
159
  constructor(mode) {
@@ -123,7 +164,7 @@ var ExecutionCore = class {
123
164
  async connect() {
124
165
  if (this.client) return this.client;
125
166
  const client = new Client({
126
- name: "remote-link-cli-core",
167
+ name: "remotearc-cli-core",
127
168
  version: VERSION
128
169
  });
129
170
  const command = process.platform === "win32" ? "npx.cmd" : "npx";
@@ -132,8 +173,10 @@ var ExecutionCore = class {
132
173
  args: ["-y", "@wonderwhy-er/desktop-commander@latest"],
133
174
  stderr: "inherit"
134
175
  });
176
+ logLine("info", "Starting local execution core\u2026");
135
177
  await client.connect(transport);
136
178
  this.client = client;
179
+ logLine("success", "Local execution core ready.");
137
180
  return client;
138
181
  }
139
182
  async tools() {
@@ -159,7 +202,12 @@ var ExecutionCore = class {
159
202
  };
160
203
  async function connectAgent(config) {
161
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")}`);
162
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");
163
211
  const wsUrl = new URL("/agent", config.origin.replace(/^http/, "ws"));
164
212
  let stopped = false;
165
213
  let backoff = 1e3;
@@ -171,6 +219,7 @@ async function connectAgent(config) {
171
219
  process.on("SIGINT", shutdown);
172
220
  process.on("SIGTERM", shutdown);
173
221
  while (!stopped) {
222
+ logLine("event", `Connecting relay ${dim(wsUrl.host)}\u2026`);
174
223
  const ws = new WebSocket(wsUrl, {
175
224
  headers: {
176
225
  Authorization: "Bearer " + config.deviceToken
@@ -196,11 +245,10 @@ async function connectAgent(config) {
196
245
  tools: tools.map((tool) => tool.name)
197
246
  })
198
247
  );
199
- process.stdout.write(
200
- "\u2713 Connected as " + config.deviceName + " (" + config.mode + " mode)\n"
201
- );
202
- process.stdout.write(" " + config.origin + "\n");
203
- 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");
204
252
  await new Promise((resolve) => {
205
253
  ws.on("message", async (raw) => {
206
254
  let message;
@@ -212,11 +260,14 @@ async function connectAgent(config) {
212
260
  if (message.type !== "call" || !message.id || !message.tool) {
213
261
  return;
214
262
  }
263
+ const callStarted = Date.now();
264
+ logLine("event", `tool.call ${bold(message.tool)} \xB7 ${dim(message.id.slice(0, 8))}`);
215
265
  try {
216
266
  const result = await core.call(
217
267
  message.tool,
218
268
  message.arguments || {}
219
269
  );
270
+ logLine("success", `tool.done ${message.tool} \xB7 ${Date.now() - callStarted}ms`);
220
271
  ws.send(
221
272
  JSON.stringify({
222
273
  type: "result",
@@ -225,6 +276,7 @@ async function connectAgent(config) {
225
276
  })
226
277
  );
227
278
  } catch (error) {
279
+ logLine("error", `tool.fail ${message.tool} \xB7 ${error instanceof Error ? error.message : String(error)}`);
228
280
  ws.send(
229
281
  JSON.stringify({
230
282
  type: "result",
@@ -238,16 +290,18 @@ async function connectAgent(config) {
238
290
  ws.once("error", resolve);
239
291
  });
240
292
  } catch (error) {
241
- process.stderr.write(
242
- "Remote Link connection failed: " + (error instanceof Error ? error.message : String(error)) + "\n"
293
+ logLine(
294
+ "error",
295
+ "Relay connection failed: " + (error instanceof Error ? error.message : String(error))
243
296
  );
244
297
  } finally {
245
298
  ws.removeAllListeners();
246
299
  ws.close();
247
300
  }
248
301
  if (!stopped) {
249
- process.stdout.write(
250
- "Disconnected. Reconnecting in " + Math.round(backoff / 1e3) + "s...\n"
302
+ logLine(
303
+ "warn",
304
+ "Relay disconnected \xB7 retrying in " + Math.round(backoff / 1e3) + "s"
251
305
  );
252
306
  await sleep(backoff);
253
307
  backoff = Math.min(backoff * 2, 3e4);
@@ -258,13 +312,13 @@ async function main() {
258
312
  if (argFlag("--help") || argFlag("-h")) {
259
313
  process.stdout.write(
260
314
  [
261
- "Remote Link",
315
+ "Remote Arc",
262
316
  "",
263
317
  "Usage:",
264
- " npx --yes --package=github:yaohuangguan/remote-link remote-link",
318
+ " npx remotelink",
265
319
  "",
266
320
  "After the npm release:",
267
- " npx remotelink@latest",
321
+ " npx remotelink",
268
322
  "",
269
323
  "Options:",
270
324
  " --safe Read-only local capability mode",
@@ -285,7 +339,7 @@ async function main() {
285
339
  await resetConfig();
286
340
  return;
287
341
  }
288
- const origin = process.env.REMOTE_LINK_ORIGIN || process.argv.find((value) => value.startsWith("--origin="))?.slice(9) || DEFAULT_ORIGIN;
342
+ const origin = process.env.REMOTEARC_ORIGIN || process.env.REMOTE_LINK_ORIGIN || process.argv.find((value) => value.startsWith("--origin="))?.slice(9) || DEFAULT_ORIGIN;
289
343
  let config = await readConfig();
290
344
  if (!config) {
291
345
  config = await pair(origin, selectedMode());
@@ -293,11 +347,15 @@ async function main() {
293
347
  config.mode = selectedMode();
294
348
  await writeConfig(config);
295
349
  }
350
+ if (config) {
351
+ logLine("info", `Using paired device identity ${dim(config.deviceId.slice(0, 8))}\u2026`);
352
+ }
296
353
  await connectAgent(config);
297
354
  }
298
355
  main().catch((error) => {
299
- process.stderr.write(
300
- "\nRemote Link error: " + (error instanceof Error ? error.message : String(error)) + "\n"
356
+ logLine(
357
+ "error",
358
+ "Fatal: " + (error instanceof Error ? error.message : String(error))
301
359
  );
302
360
  process.exit(1);
303
361
  });
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.2.0\";\r\nconst DEFAULT_ORIGIN = \"https://remote.samyao.me\";\r\nconst CONFIG_DIR = path.join(os.homedir(), \".remote-link\");\r\nconst CONFIG_PATH = path.join(CONFIG_DIR, \"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 return null;\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 fs.rm(CONFIG_PATH, { force: true });\r\n process.stdout.write(\"Remote Link 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 Link\\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 Link 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: \"remote-link-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 Link 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 Link\",\r\n \"\",\r\n \"Usage:\",\r\n \" npx --yes --package=github:yaohuangguan/remote-link remote-link\",\r\n \"\",\r\n \"After the npm release:\",\r\n \" npx remotelink@latest\",\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.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 Link 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.2\";\nconst DEFAULT_ORIGIN = \"https://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 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 } 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) {\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,31 +1,53 @@
1
- {
2
- "name": "remotelink",
3
- "version": "0.2.0",
4
- "description": "Connect a computer to Remote Link with one command.",
5
- "type": "module",
6
- "bin": {
7
- "remotelink": "dist/index.js",
8
- "remote-link": "dist/index.js"
9
- },
10
- "files": [
11
- "dist"
12
- ],
13
- "engines": {
14
- "node": ">=20"
15
- },
16
- "scripts": {
17
- "build": "tsup src/index.ts --format esm --platform node --target node20 --sourcemap",
18
- "typecheck": "tsc --noEmit",
19
- "prepublishOnly": "pnpm build"
20
- },
21
- "dependencies": {
22
- "@modelcontextprotocol/client": "^2.1.0",
23
- "ws": "^8.18.3"
24
- },
25
- "devDependencies": {
26
- "@types/node": "^24.13.6",
27
- "@types/ws": "^8.18.1",
28
- "tsup": "^8.5.0",
29
- "typescript": "^6.0.3"
30
- }
31
- }
1
+ {
2
+ "name": "remotelink",
3
+ "version": "0.3.2",
4
+ "description": "Connect a computer to Remote Arc with one command.",
5
+ "type": "module",
6
+ "bin": {
7
+ "remotelink": "dist/index.js",
8
+ "remote-link": "dist/index.js",
9
+ "remote-arc": "dist/index.js"
10
+ },
11
+ "files": [
12
+ "dist",
13
+ "README.md",
14
+ "LICENSE"
15
+ ],
16
+ "engines": {
17
+ "node": ">=20"
18
+ },
19
+ "scripts": {
20
+ "build": "tsup src/index.ts --format esm --platform node --target node20 --sourcemap",
21
+ "typecheck": "tsc --noEmit",
22
+ "prepublishOnly": "pnpm build"
23
+ },
24
+ "dependencies": {
25
+ "@modelcontextprotocol/client": "^2.1.0",
26
+ "ws": "^8.18.3"
27
+ },
28
+ "devDependencies": {
29
+ "@types/node": "^24.13.6",
30
+ "@types/ws": "^8.18.1",
31
+ "tsup": "^8.5.0",
32
+ "typescript": "^6.0.3"
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
+ ]
53
+ }