remote-dsh 0.2.0 → 0.4.1

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/dist/bin.js CHANGED
@@ -2,31 +2,128 @@
2
2
  /**
3
3
  * rdsh CLI 入口(手写参数解析,零依赖)。
4
4
  *
5
- * rdsh serve [--port <n>] [--host <ip>] [--pair-code <code>]
6
- * [--session-ttl <sec>] [--dsh <path>] [--reset]
5
+ * rdsh serve [--config <path>] [--reset] [--port <n>] ...
6
+ * rdsh join <hub-url> [--token <t>] [--dsh <path>]
7
+ * rdsh hub serve|user|host|service ... [--config <path>]
8
+ * rdsh user add|passwd <name> | ls | rm <name> [--config <path>]
9
+ * rdsh service install|uninstall|status [--config <path>]
7
10
  * rdsh --version | --help
8
11
  */
9
- import { serve } from "rdsh-gateway";
12
+ import { createInterface } from "node:readline";
13
+ import { serve, join, UserManager, resolveConfigPath, installService, uninstallService, serviceStatus, } from "rdsh-gateway";
14
+ import { loadHubConfig, resolveHubConfigPath, HubDb, hashPassword, serveHub, } from "rdsh-hub";
10
15
  import { VERSION } from "./index.js";
11
16
  const HELP = `rdsh — secure remote access for DeepSeek Harness
12
17
 
13
18
  Usage:
14
- rdsh serve [options] Start the LAN auth gateway in front of dsh web
19
+ rdsh serve [options] Start the gateway (LAN auth or cloud HTTPS service)
20
+ rdsh join <hub-url> Connect to a hub via outbound tunnel (no ports open)
21
+ rdsh hub serve Start the hub server (cloud, multi-host)
22
+ rdsh hub user add <name> Create a hub user (interactive password; --no-password for first-login setup)
23
+ rdsh hub user passwd <n> Reset a user's password (admin)
24
+ rdsh hub user rm|ls
25
+ rdsh hub host ls|revoke List / revoke hosts (revoke = tunnel drops instantly)
26
+ rdsh hub service ... Install hub as a systemd/launchd service
27
+ rdsh user add|passwd|ls|rm Gateway users (LAN/cloud HTTPS service)
28
+ rdsh service install|status|uninstall
29
+
30
+ Global:
31
+ --config <path> Gateway config (default ~/.rdsh/config.json; also $RDSH_CONFIG)
32
+ For hub commands: hub config (default ~/.rdsh/hub.json; also $RDSH_HUB_CONFIG)
33
+ --version, -v Print version
34
+ --help, -h Print this help
15
35
 
16
36
  Options (serve):
17
- --port <n> Listen port (default 8443; 0 = OS-assigned)
18
- --host <ip> Bind address (default 0.0.0.0)
19
- --pair-code <code> Preset pairing code (default: random, shown on start)
20
- --session-ttl <sec> Session cookie lifetime in seconds (default 43200)
21
- --dsh <path> Path to the dsh executable (default: from PATH)
22
- --reset Reset session keys (all devices must pair again)
23
- --no-code SKIP pairing auth any device on the network gets
24
- full DSH access. ONLY for fully trusted LANs!
37
+ --port <n> Listen port (overrides config; default 8443)
38
+ --host <ip> Bind address (overrides config; default 0.0.0.0)
39
+ --pair-code <code> Preset pairing code (overrides config)
40
+ --session-ttl <sec> Session cookie lifetime (overrides config; default 43200)
41
+ --dsh <path> dsh executable path (overrides config)
42
+ --reset Rotate session keys (all devices must re-auth)
43
+ --no-code Disable auth (trusted network ONLY!)
25
44
 
26
- Global:
27
- --version, -v Print version
28
- --help, -h Print this help
45
+ Options (join):
46
+ --token <t> Use an existing host token (skip pairing-code flow)
47
+ --dsh <path> dsh executable path
48
+
49
+ Options (hub serve):
50
+ --port <n> Listen port (overrides hub config; default 8443)
51
+ --host <ip> Bind address (overrides hub config; default 0.0.0.0)
52
+
53
+ Config (persistent): host, port, sessionTtlSeconds, tls{cert,key}, behindProxy,
54
+ allowFrom[], auth{mode: pair|password|none, pairCode, users[]}, dshPath.
55
+ Hub config (~/.rdsh/hub.json): host, port, tls{cert,key}, dbPath, jwtKeyPath.
29
56
  `;
57
+ /** 子命令级用法(`rdsh <cmd> --help`)。 */
58
+ const SUB_HELP = {
59
+ serve: `Usage: rdsh serve [options]
60
+
61
+ Start the gateway (LAN auth or cloud HTTPS service).
62
+
63
+ Options:
64
+ --config <path> Config file (default ~/.rdsh/config.json; also $RDSH_CONFIG)
65
+ --port <n> Listen port (overrides config; default 8443)
66
+ --host <ip> Bind address (overrides config; default 0.0.0.0)
67
+ --pair-code <code> Preset pairing code (overrides config)
68
+ --session-ttl <sec> Session cookie lifetime (overrides config; default 43200)
69
+ --dsh <path> dsh executable path (overrides config)
70
+ --reset Rotate session keys (all devices must re-auth)
71
+ --no-code Disable auth (trusted network ONLY!)
72
+ `,
73
+ join: `Usage: rdsh join <hub-url> [options]
74
+
75
+ Connect to a hub via an outbound tunnel (no ports open on this machine).
76
+
77
+ Options:
78
+ --token <t> Use an existing host token (skip the pair-code flow)
79
+ --dsh <path> dsh executable path
80
+ --insecure Skip TLS certificate verification (self-signed hub)
81
+ `,
82
+ hub: `Usage: rdsh hub <subcommand> [options]
83
+
84
+ Run the hub server or manage it.
85
+
86
+ Subcommands:
87
+ serve Start the hub server (TLS required)
88
+ user add|passwd|rm|ls Manage users (registration closed; admin creates accounts)
89
+ host ls|revoke List / revoke hosts (revoke drops the tunnel instantly)
90
+ service install|status|uninstall Run hub as a systemd/launchd service
91
+
92
+ Options (serve):
93
+ --config <path> Hub config (default ~/.rdsh/hub.json; also $RDSH_HUB_CONFIG)
94
+ --port <n> Listen port (overrides hub config; default 8443)
95
+ --host <ip> Bind address (overrides hub config; default 0.0.0.0)
96
+ `,
97
+ user: `Usage: rdsh user <action> [name]
98
+
99
+ Manage gateway users (LAN / cloud HTTPS service).
100
+
101
+ Actions:
102
+ add <name> Add a user (interactive password)
103
+ passwd <name> Change a user's password (revokes all their sessions)
104
+ ls List users
105
+ rm <name> Remove a user
106
+
107
+ Options:
108
+ --config <path> Config file (default ~/.rdsh/config.json; also $RDSH_CONFIG)
109
+ `,
110
+ service: `Usage: rdsh service <action>
111
+
112
+ Manage the gateway as a systemd/launchd service.
113
+
114
+ Actions:
115
+ install Install and start (auto-start on boot, restart on crash)
116
+ status Show service status
117
+ uninstall Stop and remove the service
118
+
119
+ Options:
120
+ --config <path> Config file (default ~/.rdsh/config.json; also $RDSH_CONFIG)
121
+ `,
122
+ };
123
+ /** 参数里是否有 --help / -h。 */
124
+ function hasHelp(args) {
125
+ return args.includes("--help") || args.includes("-h");
126
+ }
30
127
  async function main() {
31
128
  const argv = process.argv.slice(2);
32
129
  if (argv.length === 0 || argv[0] === "--help" || argv[0] === "-h") {
@@ -37,23 +134,72 @@ async function main() {
37
134
  console.log(`rdsh ${VERSION}`);
38
135
  return;
39
136
  }
40
- const command = argv[0];
41
- if (command === "serve") {
42
- try {
43
- const opts = parseServeArgs(argv.slice(1));
44
- await serve(opts);
137
+ // 全局解析:先剥 --config <path>(允许出现在任何位置),剩余为子命令参数
138
+ const cli = parseGlobal(argv);
139
+ const command = cli.flags[0];
140
+ if (command === undefined) {
141
+ console.error("rdsh: missing command. Run 'rdsh --help'.");
142
+ process.exitCode = 1;
143
+ return;
144
+ }
145
+ const rest = cli.flags.slice(1);
146
+ try {
147
+ if (hasHelp(rest)) {
148
+ console.log(SUB_HELP[command] ?? HELP);
149
+ return;
45
150
  }
46
- catch (err) {
47
- console.error(`rdsh: ${err instanceof Error ? err.message : String(err)}`);
48
- process.exitCode = 1;
151
+ switch (command) {
152
+ case "serve": {
153
+ const opts = parseServeArgs(rest, cli.configPath);
154
+ await serve(opts);
155
+ return;
156
+ }
157
+ case "join": {
158
+ const opts = parseJoinArgs(rest);
159
+ await join(opts);
160
+ return;
161
+ }
162
+ case "hub": {
163
+ await handleHub(rest, cli.configPath);
164
+ return;
165
+ }
166
+ case "user": {
167
+ await handleUser(rest, cli.configPath);
168
+ return;
169
+ }
170
+ case "service": {
171
+ await handleService(rest, cli.configPath);
172
+ return;
173
+ }
174
+ default:
175
+ console.error(`rdsh: unknown command '${command}'. Run 'rdsh --help'.`);
176
+ process.exitCode = 1;
49
177
  }
50
- return;
51
178
  }
52
- console.error(`rdsh: unknown command '${command}'. Run 'rdsh --help'.`);
53
- process.exitCode = 1;
179
+ catch (err) {
180
+ console.error(`rdsh: ${err instanceof Error ? err.message : String(err)}`);
181
+ process.exitCode = 1;
182
+ }
54
183
  }
55
- function parseServeArgs(args) {
56
- const opts = { host: "0.0.0.0", port: 8443, sessionTtlSeconds: 12 * 3600 };
184
+ /** 提取全局 --config <path>(或 $RDSH_CONFIG),返回剩余参数。 */
185
+ function parseGlobal(argv) {
186
+ const flags = [];
187
+ let configPath;
188
+ for (let i = 0; i < argv.length; i++) {
189
+ if (argv[i] === "--config") {
190
+ i += 1;
191
+ configPath = argv[i];
192
+ if (configPath === undefined)
193
+ throw new Error("missing value for --config");
194
+ }
195
+ else {
196
+ flags.push(argv[i]);
197
+ }
198
+ }
199
+ return { configPath: resolveConfigPath(configPath), flags };
200
+ }
201
+ function parseServeArgs(args, configPath) {
202
+ const opts = { configPath };
57
203
  for (let i = 0; i < args.length; i++) {
58
204
  const flag = args[i];
59
205
  const value = (name) => {
@@ -98,5 +244,333 @@ function parseServeArgs(args) {
98
244
  }
99
245
  return opts;
100
246
  }
247
+ function parseJoinArgs(args) {
248
+ const hubUrl = args[0];
249
+ if (hubUrl === undefined || !/^https?:\/\//.test(hubUrl)) {
250
+ throw new Error("usage: rdsh join <hub-url> [--token <t>] [--dsh <path>]");
251
+ }
252
+ const opts = { hubUrl };
253
+ for (let i = 1; i < args.length; i++) {
254
+ const flag = args[i];
255
+ const value = (name) => {
256
+ i += 1;
257
+ if (i >= args.length)
258
+ throw new Error(`missing value for ${name}`);
259
+ return args[i] ?? "";
260
+ };
261
+ switch (flag) {
262
+ case "--token":
263
+ opts.token = value(flag);
264
+ break;
265
+ case "--dsh":
266
+ opts.dshPath = value(flag);
267
+ break;
268
+ case "--insecure":
269
+ opts.insecure = true;
270
+ break;
271
+ default:
272
+ throw new Error(`unknown option '${flag}'`);
273
+ }
274
+ }
275
+ return opts;
276
+ }
277
+ async function handleUser(args, configPath) {
278
+ const action = args[0];
279
+ const um = new UserManager(configPath);
280
+ switch (action) {
281
+ case "add": {
282
+ const name = args[1];
283
+ if (name === undefined)
284
+ throw new Error("usage: rdsh user add <name>");
285
+ const password = await promptPassword(`password for ${name}: `);
286
+ const again = await promptPassword("confirm: ");
287
+ if (password !== again)
288
+ throw new Error("passwords do not match");
289
+ await um.add(name, password);
290
+ console.log(`rdsh: user '${name}' added (config: ${configPath})`);
291
+ return;
292
+ }
293
+ case "passwd": {
294
+ const name = args[1];
295
+ if (name === undefined)
296
+ throw new Error("usage: rdsh user passwd <name>");
297
+ const password = await promptPassword(`new password for ${name}: `);
298
+ const again = await promptPassword("confirm: ");
299
+ if (password !== again)
300
+ throw new Error("passwords do not match");
301
+ const ok = await um.passwd(name, password);
302
+ if (!ok)
303
+ throw new Error(`user '${name}' not found`);
304
+ console.log(`rdsh: password updated for '${name}' (all existing sessions revoked)`);
305
+ return;
306
+ }
307
+ case "ls": {
308
+ const users = await um.list();
309
+ console.log(users.length > 0 ? users.join("\n") : "(no users)");
310
+ return;
311
+ }
312
+ case "rm": {
313
+ const name = args[1];
314
+ if (name === undefined)
315
+ throw new Error("usage: rdsh user rm <name>");
316
+ const ok = await um.remove(name);
317
+ if (!ok)
318
+ throw new Error(`user '${name}' not found`);
319
+ console.log(`rdsh: user '${name}' removed`);
320
+ return;
321
+ }
322
+ default:
323
+ throw new Error("usage: rdsh user add|passwd|ls|rm");
324
+ }
325
+ }
326
+ async function handleService(args, configPath) {
327
+ const action = args[0];
328
+ switch (action) {
329
+ case "install":
330
+ console.log(await installService(configPath));
331
+ console.log("rdsh: service installed — it starts on boot and restarts on crash.");
332
+ return;
333
+ case "status":
334
+ console.log(`rdsh service: ${await serviceStatus()}`);
335
+ return;
336
+ case "uninstall":
337
+ console.log(await uninstallService());
338
+ return;
339
+ default:
340
+ throw new Error("usage: rdsh service install|status|uninstall");
341
+ }
342
+ }
343
+ /** 打开 hub 数据库(读 hub config 定位 dbPath)。 */
344
+ async function openHubDb(configPath) {
345
+ const hubConfigPath = resolveHubConfigPath(configPath);
346
+ const config = await loadHubConfig(hubConfigPath);
347
+ return new HubDb(config.dbPath);
348
+ }
349
+ async function handleHub(args, configPath) {
350
+ const sub = args[0];
351
+ const rest = args.slice(1);
352
+ if (sub === undefined || hasHelp(rest)) {
353
+ console.log(SUB_HELP["hub"] ?? HELP);
354
+ return;
355
+ }
356
+ switch (sub) {
357
+ case "serve": {
358
+ const opts = parseHubServeArgs(rest, configPath);
359
+ await serveHub(opts);
360
+ return;
361
+ }
362
+ case "user": {
363
+ await handleHubUser(rest, configPath);
364
+ return;
365
+ }
366
+ case "host": {
367
+ await handleHubHost(rest, configPath);
368
+ return;
369
+ }
370
+ case "service": {
371
+ const action = rest[0];
372
+ const hubConfigPath = resolveHubConfigPath(configPath);
373
+ switch (action) {
374
+ case "install":
375
+ console.log(await installService(hubConfigPath, ["hub", "serve"]));
376
+ console.log("rdsh: hub service installed — starts on boot and restarts on crash.");
377
+ return;
378
+ case "status":
379
+ console.log(`rdsh hub service: ${await serviceStatus()}`);
380
+ return;
381
+ case "uninstall":
382
+ console.log(await uninstallService());
383
+ return;
384
+ default:
385
+ throw new Error("usage: rdsh hub service install|status|uninstall");
386
+ }
387
+ }
388
+ default:
389
+ throw new Error("usage: rdsh hub serve|user|host|service");
390
+ }
391
+ }
392
+ function parseHubServeArgs(args, configPath) {
393
+ const opts = { configPath };
394
+ for (let i = 0; i < args.length; i++) {
395
+ const flag = args[i];
396
+ const value = (name) => {
397
+ i += 1;
398
+ if (i >= args.length)
399
+ throw new Error(`missing value for ${name}`);
400
+ return args[i] ?? "";
401
+ };
402
+ switch (flag) {
403
+ case "--port": {
404
+ const v = Number(value(flag));
405
+ if (!Number.isInteger(v) || v < 0 || v > 65535)
406
+ throw new Error(`invalid --port '${args[i]}'`);
407
+ opts.port = v;
408
+ break;
409
+ }
410
+ case "--host":
411
+ opts.host = value(flag);
412
+ break;
413
+ default:
414
+ throw new Error(`unknown option '${flag}'`);
415
+ }
416
+ }
417
+ return opts;
418
+ }
419
+ /** 交互输入密码两次(一致校验);不匹配重试(最多 3 次),仍失败抛错。 */
420
+ async function promptPasswordTwice(firstPrompt) {
421
+ for (let attempt = 1; attempt <= 3; attempt++) {
422
+ const password = await promptPassword(firstPrompt);
423
+ const again = await promptPassword("confirm: ");
424
+ if (password === again) {
425
+ if (password.length < 8)
426
+ throw new Error("password must be at least 8 characters");
427
+ return password;
428
+ }
429
+ console.error(`passwords do not match (attempt ${attempt}/3), try again`);
430
+ }
431
+ throw new Error("passwords do not match after 3 attempts");
432
+ }
433
+ async function handleHubUser(args, configPath) {
434
+ const action = args[0];
435
+ const db = await openHubDb(configPath);
436
+ try {
437
+ switch (action) {
438
+ case "add": {
439
+ const name = args[1];
440
+ if (name === undefined)
441
+ throw new Error("usage: rdsh hub user add <name> [--no-password]");
442
+ const noPassword = args.includes("--no-password");
443
+ const hubConfigPath = resolveHubConfigPath(configPath);
444
+ if (db.getUserByName(name) !== null)
445
+ throw new Error(`user '${name}' already exists`);
446
+ if (noPassword) {
447
+ // 首次登录自设密码(must_change=1,密码占位不可用)
448
+ db.createUser(name, "scrypt:disabled", new Date().toISOString(), true);
449
+ console.log(`rdsh: user '${name}' created — they must set a password on first sign-in (${hubConfigPath})`);
450
+ }
451
+ else {
452
+ const password = await promptPasswordTwice(`password for ${name}: `);
453
+ db.createUser(name, await hashPassword(password));
454
+ console.log(`rdsh: user '${name}' created (hub db: ${db.path})`);
455
+ }
456
+ return;
457
+ }
458
+ case "passwd": {
459
+ const name = args[1];
460
+ if (name === undefined)
461
+ throw new Error("usage: rdsh hub user passwd <name>");
462
+ const user = db.getUserByName(name);
463
+ if (user === null)
464
+ throw new Error(`user '${name}' not found`);
465
+ const password = await promptPasswordTwice(`new password for ${name}: `);
466
+ db.setPassword(user.id, await hashPassword(password));
467
+ console.log(`rdsh: password reset for '${name}' (all their sessions revoked)`);
468
+ return;
469
+ }
470
+ case "ls": {
471
+ const users = db.listUsers();
472
+ console.log(users.length > 0 ? users.map((u) => u.name).join("\n") : "(no users)");
473
+ return;
474
+ }
475
+ case "rm": {
476
+ const name = args[1];
477
+ if (name === undefined)
478
+ throw new Error("usage: rdsh hub user rm <name>");
479
+ const user = db.getUserByName(name);
480
+ if (user === null)
481
+ throw new Error(`user '${name}' not found`);
482
+ db.removeUser(user.id);
483
+ console.log(`rdsh: user '${name}' removed (their hosts removed)`);
484
+ return;
485
+ }
486
+ default:
487
+ throw new Error("usage: rdsh hub user add|passwd|ls|rm");
488
+ }
489
+ }
490
+ finally {
491
+ db.close(); // 抛错路径也必须关闭 SQLite 句柄(否则进程挂住)
492
+ }
493
+ }
494
+ async function handleHubHost(args, configPath) {
495
+ const action = args[0];
496
+ const db = await openHubDb(configPath);
497
+ try {
498
+ switch (action) {
499
+ case "ls": {
500
+ const hosts = db.listAllHosts();
501
+ if (hosts.length === 0) {
502
+ console.log("(no hosts)");
503
+ }
504
+ else {
505
+ for (const h of hosts) {
506
+ const owner = db.getUserById(h.ownerId);
507
+ console.log(`${h.id} ${h.name} owner=${owner?.name ?? h.ownerId} created=${h.createdAt}`);
508
+ }
509
+ }
510
+ return;
511
+ }
512
+ case "revoke": {
513
+ const hostId = args[1];
514
+ if (hostId === undefined)
515
+ throw new Error("usage: rdsh hub host revoke <hostId>");
516
+ const host = db.getHostById(hostId);
517
+ if (host === null)
518
+ throw new Error(`host '${hostId}' not found`);
519
+ db.removeHost(hostId);
520
+ console.log(`rdsh: host '${hostId}' revoked — its tunnel will drop and reconnects are rejected`);
521
+ return;
522
+ }
523
+ default:
524
+ throw new Error("usage: rdsh hub host ls|revoke <hostId>");
525
+ }
526
+ }
527
+ finally {
528
+ db.close();
529
+ }
530
+ }
531
+ function promptPassword(prompt) {
532
+ const stdin = process.stdin;
533
+ if (stdin.isTTY && typeof stdin.setRawMode === "function") {
534
+ process.stdout.write(prompt);
535
+ stdin.setRawMode(true);
536
+ return new Promise((resolve) => {
537
+ let input = "";
538
+ const onData = (chunk) => {
539
+ for (const byte of chunk) {
540
+ if (byte === 13 || byte === 10) {
541
+ stdin.removeListener("data", onData);
542
+ if (typeof stdin.setRawMode === "function")
543
+ stdin.setRawMode(false);
544
+ process.stdout.write("\n");
545
+ resolve(input);
546
+ return;
547
+ }
548
+ if (byte === 127 || byte === 8) {
549
+ input = input.slice(0, -1);
550
+ continue;
551
+ }
552
+ input += String.fromCharCode(byte);
553
+ }
554
+ };
555
+ stdin.on("data", onData);
556
+ });
557
+ }
558
+ // 非 TTY(管道/重定向):一次性读完 stdin(EOF),逐行消费。
559
+ // 注意:不能每次调用新建 readline —— 第二个 interface 会读不到剩余行。
560
+ process.stdout.write(prompt);
561
+ return nextPipeLine();
562
+ }
563
+ let pipeLines = null;
564
+ function nextPipeLine() {
565
+ if (pipeLines !== null) {
566
+ return Promise.resolve(pipeLines.shift() ?? "");
567
+ }
568
+ pipeLines = [];
569
+ const rl = createInterface({ input: process.stdin, output: process.stdout, terminal: false });
570
+ return new Promise((resolve) => {
571
+ rl.on("line", (l) => pipeLines.push(l));
572
+ rl.on("close", () => resolve(pipeLines.shift() ?? ""));
573
+ });
574
+ }
101
575
  void main();
102
576
  //# sourceMappingURL=bin.js.map
package/dist/index.d.ts CHANGED
@@ -1,9 +1,4 @@
1
- /**
2
- * rdsh — secure remote access for DeepSeek Harness.
3
- *
4
- * This package is the unified CLI (`rdsh serve` / `rdsh join` / `rdsh hub`).
5
- * v0.1.0 is a name-reservation skeleton; commands land with the M1 MVP.
6
- */
7
1
  export declare const NAME = "rdsh";
8
- export declare const VERSION = "0.2.0";
2
+ /** 版本单一来源:package.json(发布时 --version 与包版本一致,避免硬编码漏同步)。 */
3
+ export declare const VERSION: string;
9
4
  export declare const DESCRIPTION = "Secure remote access for DeepSeek Harness: rdsh serve / rdsh join / rdsh hub";
package/dist/index.js CHANGED
@@ -2,9 +2,11 @@
2
2
  * rdsh — secure remote access for DeepSeek Harness.
3
3
  *
4
4
  * This package is the unified CLI (`rdsh serve` / `rdsh join` / `rdsh hub`).
5
- * v0.1.0 is a name-reservation skeleton; commands land with the M1 MVP.
5
+ * v0.1.0 was a name-reservation skeleton; commands land with M1/M2/M3.
6
6
  */
7
+ import { readFileSync } from "node:fs";
7
8
  export const NAME = "rdsh";
8
- export const VERSION = "0.2.0";
9
+ /** 版本单一来源:package.json(发布时 --version 与包版本一致,避免硬编码漏同步)。 */
10
+ export const VERSION = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8")).version;
9
11
  export const DESCRIPTION = "Secure remote access for DeepSeek Harness: rdsh serve / rdsh join / rdsh hub";
10
12
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "remote-dsh",
3
- "version": "0.2.0",
3
+ "version": "0.4.1",
4
4
  "description": "Secure remote access for DeepSeek Harness: rdsh serve / rdsh join / rdsh hub",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -23,10 +23,11 @@
23
23
  "node": ">=22"
24
24
  },
25
25
  "dependencies": {
26
- "rdsh-gateway": "0.1.0"
26
+ "rdsh-hub": "0.1.0",
27
+ "rdsh-gateway": "0.2.0"
27
28
  },
28
29
  "scripts": {
29
30
  "build": "tsc -p tsconfig.json",
30
31
  "test": "node --test test/"
31
32
  }
32
- }
33
+ }