@hermespilot/link 0.2.7 → 0.2.9
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/{chunk-SSJ7WDD7.js → chunk-VLTX75SY.js} +862 -373
- package/dist/cli/index.js +179 -14
- package/dist/http/app.js +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
clearPairingClaim,
|
|
7
7
|
currentCliScriptPath,
|
|
8
8
|
daemonLogFile,
|
|
9
|
+
detectRuntimeEnvironment,
|
|
9
10
|
ensureHermesApiServerAvailable,
|
|
10
11
|
ensureHermesApiServerConfig,
|
|
11
12
|
ensureIdentity,
|
|
@@ -15,21 +16,25 @@ import {
|
|
|
15
16
|
hasActiveDevices,
|
|
16
17
|
loadConfig,
|
|
17
18
|
loadIdentity,
|
|
19
|
+
normalizeLanHost,
|
|
18
20
|
preparePairing,
|
|
19
21
|
probeLocalLinkService,
|
|
20
22
|
readHermesApiServerConfig,
|
|
21
23
|
readPairingClaim,
|
|
24
|
+
reportLinkStatusToServer,
|
|
22
25
|
resolveHermesConfigPath,
|
|
23
26
|
resolveHermesProfileDir,
|
|
24
27
|
resolveRuntimePaths,
|
|
25
28
|
runDaemonSupervisor,
|
|
29
|
+
saveConfig,
|
|
26
30
|
startDaemonProcess,
|
|
27
31
|
startLinkService,
|
|
28
32
|
stopDaemonProcess
|
|
29
|
-
} from "../chunk-
|
|
33
|
+
} from "../chunk-VLTX75SY.js";
|
|
30
34
|
|
|
31
35
|
// src/cli/index.ts
|
|
32
36
|
import { Command } from "commander";
|
|
37
|
+
import { createInterface } from "readline/promises";
|
|
33
38
|
import qrcode from "qrcode-terminal";
|
|
34
39
|
|
|
35
40
|
// src/autostart/autostart.ts
|
|
@@ -221,6 +226,9 @@ var messages = {
|
|
|
221
226
|
"status.runtime": "Runtime: {value}",
|
|
222
227
|
"status.mode": "Mode: {value}",
|
|
223
228
|
"status.port": "Local port: {value}",
|
|
229
|
+
"status.lanHost": "Configured LAN host: {value}",
|
|
230
|
+
"status.notSet": "not set",
|
|
231
|
+
"status.environmentWarning": "Network note: {message}",
|
|
224
232
|
"status.linkId": "Link ID: {value}",
|
|
225
233
|
"status.notPaired": "not paired",
|
|
226
234
|
"start.description": "Start Hermes Link daemon",
|
|
@@ -234,6 +242,15 @@ var messages = {
|
|
|
234
242
|
"stop.stopped": "Hermes Link stopped.",
|
|
235
243
|
"stop.notRunning": "Hermes Link is not running.",
|
|
236
244
|
"restart.description": "Restart the background Hermes Link daemon",
|
|
245
|
+
"config.description": "Manage local Hermes Link configuration",
|
|
246
|
+
"config.set.description": "Set a configuration value",
|
|
247
|
+
"config.unset.description": "Unset a configuration value",
|
|
248
|
+
"config.unknownKey": "Unknown config key: {key}",
|
|
249
|
+
"config.lanHostInvalid": "lan-host must be a private LAN IPv4 address, such as 192.168.1.23.",
|
|
250
|
+
"config.lanHostSet": "Configured LAN host: {value}",
|
|
251
|
+
"config.lanHostUnset": "Configured LAN host cleared.",
|
|
252
|
+
"config.reported": "Updated HermesPilot Server with the latest LAN address.",
|
|
253
|
+
"config.reportSkippedUnpaired": "Hermes Link is not paired yet. The LAN address will be reported after pairing.",
|
|
237
254
|
"daemon.description": "Run Hermes Link in the foreground",
|
|
238
255
|
"daemon.foreground": "Hermes Link foreground daemon is running. Press Ctrl+C to stop.",
|
|
239
256
|
"logs.description": "Show Hermes Link log paths",
|
|
@@ -260,9 +277,13 @@ var messages = {
|
|
|
260
277
|
"pair.code": "Pairing code: {value}",
|
|
261
278
|
"pair.localApi": "Local API: http://127.0.0.1:{port}",
|
|
262
279
|
"pair.scan": "Open this pairing page in the HermesPilot App or scan the QR code below:",
|
|
280
|
+
"pair.openBrowserFailed": "Could not open the system browser automatically. You can still scan the QR code below or open this URL manually: {url}",
|
|
263
281
|
"pair.expires": "Pairing expires in 10 minutes. Press Ctrl+C to cancel waiting.",
|
|
264
282
|
"pair.claimed": "Pairing succeeded. Starting Hermes Link in the background...",
|
|
265
283
|
"pair.claimedRunning": "Pairing succeeded. Hermes Link is already running in the background.",
|
|
284
|
+
"pair.relayOnlyNotice": "Network note: this {kind} environment does not expose a phone-reachable LAN/public direct address by default. The App will connect through Relay.",
|
|
285
|
+
"pair.relayOnlyLanHostHint": "If you manually expose this Link from Windows or your router, run `hermeslink config set lan-host <Windows LAN IP>` to publish the reachable LAN address.",
|
|
286
|
+
"pair.relayOnlySafetyHint": "Hermes Link will not automatically change Windows/WSL bridge, firewall, or portproxy settings because those are system-level network exposure choices.",
|
|
266
287
|
"pair.autostartUnchanged": "Existing paired devices found. Boot autostart settings were left unchanged.",
|
|
267
288
|
"pair.autostartFailed": "Pairing succeeded, but boot autostart could not be enabled: {message}",
|
|
268
289
|
"doctor.description": "Run local diagnostics",
|
|
@@ -270,6 +291,8 @@ var messages = {
|
|
|
270
291
|
"doctor.installId": "Install ID: {value}",
|
|
271
292
|
"doctor.linkId": "Link ID: {value}",
|
|
272
293
|
"doctor.notAssigned": "not assigned",
|
|
294
|
+
"doctor.lanHost": "Configured LAN host: {value}",
|
|
295
|
+
"doctor.networkWarning": "Network note: {message}",
|
|
273
296
|
"doctor.apiReady": "Hermes API Server: ready",
|
|
274
297
|
"doctor.apiStarted": "Hermes API Server: started and ready",
|
|
275
298
|
"doctor.apiUnavailable": "Hermes API Server: unavailable. {message}",
|
|
@@ -290,6 +313,9 @@ var messages = {
|
|
|
290
313
|
"status.runtime": "\u8FD0\u884C\u76EE\u5F55\uFF1A{value}",
|
|
291
314
|
"status.mode": "\u6A21\u5F0F\uFF1A{value}",
|
|
292
315
|
"status.port": "\u672C\u5730\u7AEF\u53E3\uFF1A{value}",
|
|
316
|
+
"status.lanHost": "\u5DF2\u914D\u7F6E\u5C40\u57DF\u7F51\u4E3B\u673A\uFF1A{value}",
|
|
317
|
+
"status.notSet": "\u672A\u8BBE\u7F6E",
|
|
318
|
+
"status.environmentWarning": "\u7F51\u7EDC\u63D0\u793A\uFF1A{message}",
|
|
293
319
|
"status.linkId": "Link ID\uFF1A{value}",
|
|
294
320
|
"status.notPaired": "\u5C1A\u672A\u914D\u5BF9",
|
|
295
321
|
"start.description": "\u542F\u52A8 Hermes Link \u670D\u52A1",
|
|
@@ -303,6 +329,15 @@ var messages = {
|
|
|
303
329
|
"stop.stopped": "Hermes Link \u5DF2\u505C\u6B62\u3002",
|
|
304
330
|
"stop.notRunning": "Hermes Link \u6CA1\u6709\u5728\u8FD0\u884C\u3002",
|
|
305
331
|
"restart.description": "\u91CD\u542F\u540E\u53F0 Hermes Link \u670D\u52A1",
|
|
332
|
+
"config.description": "\u7BA1\u7406\u672C\u673A Hermes Link \u914D\u7F6E",
|
|
333
|
+
"config.set.description": "\u8BBE\u7F6E\u914D\u7F6E\u9879",
|
|
334
|
+
"config.unset.description": "\u6E05\u9664\u914D\u7F6E\u9879",
|
|
335
|
+
"config.unknownKey": "\u672A\u77E5\u914D\u7F6E\u9879\uFF1A{key}",
|
|
336
|
+
"config.lanHostInvalid": "lan-host \u5FC5\u987B\u662F\u5C40\u57DF\u7F51 IPv4 \u5730\u5740\uFF0C\u4F8B\u5982 192.168.1.23\u3002",
|
|
337
|
+
"config.lanHostSet": "\u5DF2\u914D\u7F6E\u5C40\u57DF\u7F51\u4E3B\u673A\uFF1A{value}",
|
|
338
|
+
"config.lanHostUnset": "\u5DF2\u6E05\u9664\u5C40\u57DF\u7F51\u4E3B\u673A\u914D\u7F6E\u3002",
|
|
339
|
+
"config.reported": "\u5DF2\u628A\u6700\u65B0\u5C40\u57DF\u7F51\u5730\u5740\u66F4\u65B0\u5230 HermesPilot Server\u3002",
|
|
340
|
+
"config.reportSkippedUnpaired": "Hermes Link \u8FD8\u6CA1\u6709\u914D\u5BF9\uFF0C\u5C40\u57DF\u7F51\u5730\u5740\u4F1A\u5728\u914D\u5BF9\u540E\u4E0A\u62A5\u3002",
|
|
306
341
|
"daemon.description": "\u4EE5\u524D\u53F0\u65B9\u5F0F\u8FD0\u884C Hermes Link",
|
|
307
342
|
"daemon.foreground": "Hermes Link \u524D\u53F0\u670D\u52A1\u6B63\u5728\u8FD0\u884C\u3002\u6309 Ctrl+C \u505C\u6B62\u3002",
|
|
308
343
|
"logs.description": "\u663E\u793A Hermes Link \u65E5\u5FD7\u8DEF\u5F84",
|
|
@@ -329,9 +364,13 @@ var messages = {
|
|
|
329
364
|
"pair.code": "\u914D\u5BF9\u7801\uFF1A{value}",
|
|
330
365
|
"pair.localApi": "\u672C\u5730 API\uFF1Ahttp://127.0.0.1:{port}",
|
|
331
366
|
"pair.scan": "\u8BF7\u5728 HermesPilot App \u4E2D\u6253\u5F00\u8FD9\u4E2A\u914D\u5BF9\u9875\uFF0C\u6216\u626B\u63CF\u4E0B\u9762\u7684\u4E8C\u7EF4\u7801\uFF1A",
|
|
367
|
+
"pair.openBrowserFailed": "\u65E0\u6CD5\u81EA\u52A8\u6253\u5F00\u7CFB\u7EDF\u6D4F\u89C8\u5668\u3002\u4F60\u4ECD\u7136\u53EF\u4EE5\u626B\u63CF\u4E0B\u9762\u7684\u4E8C\u7EF4\u7801\uFF0C\u6216\u624B\u52A8\u6253\u5F00\u8FD9\u4E2A\u94FE\u63A5\uFF1A{url}",
|
|
332
368
|
"pair.expires": "\u914D\u5BF9\u4F1A\u8BDD 10 \u5206\u949F\u540E\u8FC7\u671F\u3002\u6309 Ctrl+C \u9000\u51FA\u7B49\u5F85\u3002",
|
|
333
369
|
"pair.claimed": "\u914D\u5BF9\u5DF2\u6210\u529F\u3002\u6B63\u5728\u628A Hermes Link \u5207\u6362\u5230\u540E\u53F0\u8FD0\u884C...",
|
|
334
370
|
"pair.claimedRunning": "\u914D\u5BF9\u5DF2\u6210\u529F\u3002Hermes Link \u5DF2\u5728\u540E\u53F0\u6301\u7EED\u8FD0\u884C\u3002",
|
|
371
|
+
"pair.relayOnlyNotice": "\u7F51\u7EDC\u63D0\u793A\uFF1A\u5F53\u524D\u662F {kind} \u73AF\u5883\uFF0C\u9ED8\u8BA4\u4E0D\u4F1A\u66B4\u9732\u624B\u673A\u53EF\u8BBF\u95EE\u7684\u5C40\u57DF\u7F51\u6216\u516C\u7F51\u76F4\u8FDE\u5730\u5740\u3002App \u4F1A\u901A\u8FC7 Relay \u8FDE\u63A5\u3002",
|
|
372
|
+
"pair.relayOnlyLanHostHint": "\u5982\u679C\u4F60\u5DF2\u7ECF\u5728 Windows \u6216\u8DEF\u7531\u5668\u4FA7\u624B\u52A8\u628A\u8FD9\u4E2A Link \u66B4\u9732\u5230\u5C40\u57DF\u7F51\uFF0C\u53EF\u4EE5\u8FD0\u884C `hermeslink config set lan-host <Windows \u5C40\u57DF\u7F51 IP>` \u66F4\u65B0\u53EF\u8BBF\u95EE\u5730\u5740\u3002",
|
|
373
|
+
"pair.relayOnlySafetyHint": "Hermes Link \u4E0D\u4F1A\u81EA\u52A8\u4FEE\u6539 Windows/WSL \u6865\u63A5\u3001\u9632\u706B\u5899\u6216\u7AEF\u53E3\u4EE3\u7406\u914D\u7F6E\uFF0C\u56E0\u4E3A\u8FD9\u4E9B\u5C5E\u4E8E\u7CFB\u7EDF\u7EA7\u7F51\u7EDC\u66B4\u9732\u8BBE\u7F6E\u3002",
|
|
335
374
|
"pair.autostartUnchanged": "\u68C0\u6D4B\u5230\u5DF2\u6709\u914D\u5BF9\u8BBE\u5907\uFF0C\u5F00\u673A\u81EA\u542F\u8BBE\u7F6E\u4FDD\u6301\u4E0D\u53D8\u3002",
|
|
336
375
|
"pair.autostartFailed": "\u914D\u5BF9\u5DF2\u6210\u529F\uFF0C\u4F46\u542F\u7528\u5F00\u673A\u81EA\u542F\u5931\u8D25\uFF1A{message}",
|
|
337
376
|
"doctor.description": "\u8FD0\u884C\u672C\u673A\u8BCA\u65AD",
|
|
@@ -339,6 +378,8 @@ var messages = {
|
|
|
339
378
|
"doctor.installId": "Install ID\uFF1A{value}",
|
|
340
379
|
"doctor.linkId": "Link ID\uFF1A{value}",
|
|
341
380
|
"doctor.notAssigned": "\u5C1A\u672A\u5206\u914D",
|
|
381
|
+
"doctor.lanHost": "\u5DF2\u914D\u7F6E\u5C40\u57DF\u7F51\u4E3B\u673A\uFF1A{value}",
|
|
382
|
+
"doctor.networkWarning": "\u7F51\u7EDC\u63D0\u793A\uFF1A{message}",
|
|
342
383
|
"doctor.apiReady": "Hermes API Server\uFF1A\u5DF2\u5C31\u7EEA",
|
|
343
384
|
"doctor.apiStarted": "Hermes API Server\uFF1A\u5DF2\u81EA\u52A8\u542F\u52A8\u5E76\u5C31\u7EEA",
|
|
344
385
|
"doctor.apiUnavailable": "Hermes API Server\uFF1A\u4E0D\u53EF\u7528\u3002{message}",
|
|
@@ -570,16 +611,29 @@ async function openSystemBrowser(url) {
|
|
|
570
611
|
return await spawnDetached("xdg-open", [url]);
|
|
571
612
|
}
|
|
572
613
|
async function spawnDetached(command, args) {
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
614
|
+
return await new Promise((resolve) => {
|
|
615
|
+
let settled = false;
|
|
616
|
+
const settle = (ok) => {
|
|
617
|
+
if (settled) {
|
|
618
|
+
return;
|
|
619
|
+
}
|
|
620
|
+
settled = true;
|
|
621
|
+
resolve(ok);
|
|
622
|
+
};
|
|
623
|
+
try {
|
|
624
|
+
const child = spawn(command, args, {
|
|
625
|
+
detached: true,
|
|
626
|
+
stdio: "ignore"
|
|
627
|
+
});
|
|
628
|
+
child.once("error", () => settle(false));
|
|
629
|
+
child.once("spawn", () => {
|
|
630
|
+
child.unref();
|
|
631
|
+
settle(true);
|
|
632
|
+
});
|
|
633
|
+
} catch {
|
|
634
|
+
settle(false);
|
|
635
|
+
}
|
|
636
|
+
});
|
|
583
637
|
}
|
|
584
638
|
|
|
585
639
|
// src/cli/index.ts
|
|
@@ -598,6 +652,8 @@ program.command("status").option("--json", helpText("status.json")).description(
|
|
|
598
652
|
paired: Boolean(identity?.link_id),
|
|
599
653
|
mode: identity?.link_id ? "paired" : "local-only",
|
|
600
654
|
port: config.port,
|
|
655
|
+
lanHost: config.lanHost,
|
|
656
|
+
environment: detectRuntimeEnvironment(),
|
|
601
657
|
identity: identity ? getIdentityStatus(identity) : null,
|
|
602
658
|
relay: {
|
|
603
659
|
configured: Boolean(config.relayBaseUrl),
|
|
@@ -612,8 +668,43 @@ program.command("status").option("--json", helpText("status.json")).description(
|
|
|
612
668
|
console.log(t("status.runtime", { value: payload.runtimeHome }));
|
|
613
669
|
console.log(t("status.mode", { value: payload.mode }));
|
|
614
670
|
console.log(t("status.port", { value: payload.port }));
|
|
671
|
+
console.log(t("status.lanHost", { value: payload.lanHost ?? t("status.notSet") }));
|
|
672
|
+
if (payload.environment.warning) {
|
|
673
|
+
console.log(t("status.environmentWarning", { message: payload.environment.warning }));
|
|
674
|
+
}
|
|
615
675
|
console.log(t("status.linkId", { value: payload.identity?.linkId ?? t("status.notPaired") }));
|
|
616
676
|
});
|
|
677
|
+
var configCommand = program.command("config").description(helpText("config.description"));
|
|
678
|
+
configCommand.command("set").argument("<key>").argument("<value>").description(helpText("config.set.description")).action(async (key, value) => {
|
|
679
|
+
const paths = resolveRuntimePaths();
|
|
680
|
+
const current = await loadConfig(paths);
|
|
681
|
+
const language = resolveLanguage(current.language);
|
|
682
|
+
const t = translate.bind(null, language);
|
|
683
|
+
const normalizedKey = key.trim().toLowerCase();
|
|
684
|
+
if (normalizedKey !== "lan-host") {
|
|
685
|
+
throw new Error(t("config.unknownKey", { key }));
|
|
686
|
+
}
|
|
687
|
+
const lanHost = normalizeLanHost(value);
|
|
688
|
+
if (!lanHost) {
|
|
689
|
+
throw new Error(t("config.lanHostInvalid"));
|
|
690
|
+
}
|
|
691
|
+
const next = await saveConfig({ lanHost }, paths);
|
|
692
|
+
console.log(t("config.lanHostSet", { value: next.lanHost ?? lanHost }));
|
|
693
|
+
await reportConfigNetworkUpdate(paths, t);
|
|
694
|
+
});
|
|
695
|
+
configCommand.command("unset").argument("<key>").description(helpText("config.unset.description")).action(async (key) => {
|
|
696
|
+
const paths = resolveRuntimePaths();
|
|
697
|
+
const current = await loadConfig(paths);
|
|
698
|
+
const language = resolveLanguage(current.language);
|
|
699
|
+
const t = translate.bind(null, language);
|
|
700
|
+
const normalizedKey = key.trim().toLowerCase();
|
|
701
|
+
if (normalizedKey !== "lan-host") {
|
|
702
|
+
throw new Error(t("config.unknownKey", { key }));
|
|
703
|
+
}
|
|
704
|
+
await saveConfig({ lanHost: null }, paths);
|
|
705
|
+
console.log(t("config.lanHostUnset"));
|
|
706
|
+
await reportConfigNetworkUpdate(paths, t);
|
|
707
|
+
});
|
|
617
708
|
program.command("start").description(helpText("start.description")).action(async () => {
|
|
618
709
|
const [config, status] = await Promise.all([loadConfig(), getDaemonStatus()]);
|
|
619
710
|
const language = resolveLanguage(config.language);
|
|
@@ -661,11 +752,17 @@ program.command("daemon-supervisor", { hidden: true }).action(async () => {
|
|
|
661
752
|
});
|
|
662
753
|
program.command("pair").description(helpText("pair.description")).action(async () => {
|
|
663
754
|
const paths = resolveRuntimePaths();
|
|
664
|
-
|
|
665
|
-
const
|
|
755
|
+
let config = await loadConfig(paths);
|
|
756
|
+
const languageChoice = await resolvePairingLanguage(paths, config);
|
|
757
|
+
config = languageChoice.config;
|
|
758
|
+
const language = languageChoice.language;
|
|
666
759
|
const t = translate.bind(null, language);
|
|
667
760
|
console.log(t("pair.preflight"));
|
|
668
761
|
const preflight = await assertPairingPreflightReady({ paths });
|
|
762
|
+
const environment = detectRuntimeEnvironment();
|
|
763
|
+
if (environment.warning) {
|
|
764
|
+
console.log(t("doctor.networkWarning", { message: environment.warning }));
|
|
765
|
+
}
|
|
669
766
|
console.log(t("pair.hermesHome", { path: preflight.hermesHome }));
|
|
670
767
|
console.log(t("pair.apiReady", { port: preflight.apiServer.port ?? "unknown" }));
|
|
671
768
|
console.log(t("pair.preparing"));
|
|
@@ -695,7 +792,10 @@ program.command("pair").description(helpText("pair.description")).action(async (
|
|
|
695
792
|
}
|
|
696
793
|
console.log(t("pair.scan"));
|
|
697
794
|
console.log(`Pairing page: ${pairingPageUrl}`);
|
|
698
|
-
|
|
795
|
+
const browserOpened = await openSystemBrowser(pairingPageUrl);
|
|
796
|
+
if (!browserOpened) {
|
|
797
|
+
console.log(t("pair.openBrowserFailed", { url: pairingPageUrl }));
|
|
798
|
+
}
|
|
699
799
|
qrcode.generate(qrValue, { small: true });
|
|
700
800
|
console.log(t("pair.expires"));
|
|
701
801
|
const result = await waitForPairingOrShutdown(prepared.sessionId, paths);
|
|
@@ -705,6 +805,7 @@ program.command("pair").description(helpText("pair.description")).action(async (
|
|
|
705
805
|
if (result === "claimed") {
|
|
706
806
|
await clearPairingClaim(prepared.sessionId, paths);
|
|
707
807
|
console.log(t(reusedRunningService ? "pair.claimedRunning" : "pair.claimed"));
|
|
808
|
+
printPostPairingNetworkNotice(prepared.routes.environment, config, t);
|
|
708
809
|
try {
|
|
709
810
|
if (hadActiveDevices) {
|
|
710
811
|
console.log(t("pair.autostartUnchanged"));
|
|
@@ -789,6 +890,11 @@ program.command("doctor").description(helpText("doctor.description")).action(asy
|
|
|
789
890
|
console.log(t("doctor.identityOk"));
|
|
790
891
|
console.log(t("doctor.installId", { value: identity.install_id }));
|
|
791
892
|
console.log(t("doctor.linkId", { value: identity.link_id ?? t("doctor.notAssigned") }));
|
|
893
|
+
const environment = detectRuntimeEnvironment();
|
|
894
|
+
if (environment.warning) {
|
|
895
|
+
console.log(t("doctor.networkWarning", { message: environment.warning }));
|
|
896
|
+
}
|
|
897
|
+
console.log(t("doctor.lanHost", { value: config.lanHost ?? t("status.notSet") }));
|
|
792
898
|
if (hermesConfig.notice) {
|
|
793
899
|
console.log(hermesConfig.notice);
|
|
794
900
|
if (hermesConfig.backupPath) {
|
|
@@ -811,6 +917,48 @@ async function loadCliLanguage() {
|
|
|
811
917
|
const config = await loadConfig();
|
|
812
918
|
return resolveLanguage(config.language);
|
|
813
919
|
}
|
|
920
|
+
async function resolvePairingLanguage(paths, config) {
|
|
921
|
+
if (config.language !== "auto") {
|
|
922
|
+
return { config, language: resolveLanguage(config.language) };
|
|
923
|
+
}
|
|
924
|
+
const selected = await promptForLanguage();
|
|
925
|
+
if (!selected) {
|
|
926
|
+
return { config, language: resolveLanguage(config.language) };
|
|
927
|
+
}
|
|
928
|
+
const next = await saveConfig({ language: selected }, paths);
|
|
929
|
+
return { config: next, language: selected };
|
|
930
|
+
}
|
|
931
|
+
async function promptForLanguage() {
|
|
932
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
933
|
+
return null;
|
|
934
|
+
}
|
|
935
|
+
const rl = createInterface({
|
|
936
|
+
input: process.stdin,
|
|
937
|
+
output: process.stdout
|
|
938
|
+
});
|
|
939
|
+
try {
|
|
940
|
+
for (; ; ) {
|
|
941
|
+
const answer = await rl.question(
|
|
942
|
+
[
|
|
943
|
+
"\u8BF7\u9009\u62E9 Hermes Link \u663E\u793A\u8BED\u8A00 / Choose Hermes Link language:",
|
|
944
|
+
" 1. \u4E2D\u6587",
|
|
945
|
+
" 2. English",
|
|
946
|
+
"\u8F93\u5165 1 \u6216 2 \u540E\u56DE\u8F66 / Enter 1 or 2: "
|
|
947
|
+
].join("\n")
|
|
948
|
+
);
|
|
949
|
+
const normalized = answer.trim().toLowerCase();
|
|
950
|
+
if (normalized === "1" || normalized === "zh" || normalized === "zh-cn" || normalized === "\u4E2D\u6587") {
|
|
951
|
+
return "zh-CN";
|
|
952
|
+
}
|
|
953
|
+
if (normalized === "2" || normalized === "en" || normalized === "english") {
|
|
954
|
+
return "en";
|
|
955
|
+
}
|
|
956
|
+
console.log("\u8BF7\u8F93\u5165 1 \u6216 2\u3002 / Please enter 1 or 2.");
|
|
957
|
+
}
|
|
958
|
+
} finally {
|
|
959
|
+
rl.close();
|
|
960
|
+
}
|
|
961
|
+
}
|
|
814
962
|
async function waitForShutdown(cleanup) {
|
|
815
963
|
await new Promise((resolve) => {
|
|
816
964
|
const stop = () => resolve();
|
|
@@ -843,3 +991,20 @@ async function waitForPairingOrShutdown(sessionId, paths) {
|
|
|
843
991
|
function sleep(ms) {
|
|
844
992
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
845
993
|
}
|
|
994
|
+
async function reportConfigNetworkUpdate(paths, t) {
|
|
995
|
+
const identity = await loadIdentity(paths);
|
|
996
|
+
if (!identity?.link_id) {
|
|
997
|
+
console.log(t("config.reportSkippedUnpaired"));
|
|
998
|
+
return;
|
|
999
|
+
}
|
|
1000
|
+
await reportLinkStatusToServer({ paths });
|
|
1001
|
+
console.log(t("config.reported"));
|
|
1002
|
+
}
|
|
1003
|
+
function printPostPairingNetworkNotice(environment, config, t) {
|
|
1004
|
+
if (environment.lanAutoDiscoveryUsable || config.lanHost) {
|
|
1005
|
+
return;
|
|
1006
|
+
}
|
|
1007
|
+
console.log(t("pair.relayOnlyNotice", { kind: environment.kind }));
|
|
1008
|
+
console.log(t("pair.relayOnlyLanHostHint"));
|
|
1009
|
+
console.log(t("pair.relayOnlySafetyHint"));
|
|
1010
|
+
}
|
package/dist/http/app.js
CHANGED