@hermespilot/link 0.3.8 → 0.4.0
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-RJB5VUT4.js → chunk-FWPHQZP6.js} +1148 -277
- package/dist/cli/index.js +144 -71
- package/dist/http/app.d.ts +17 -0
- package/dist/http/app.js +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
LINK_VERSION,
|
|
6
6
|
LinkHttpError,
|
|
7
7
|
clearPairingClaim,
|
|
8
|
+
connectRelayControl,
|
|
8
9
|
createFileLogger,
|
|
9
10
|
currentCliScriptPath,
|
|
10
11
|
daemonLogFile,
|
|
@@ -22,6 +23,7 @@ import {
|
|
|
22
23
|
preparePairing,
|
|
23
24
|
probeLocalLinkService,
|
|
24
25
|
readHermesApiServerConfig,
|
|
26
|
+
readHermesVersion,
|
|
25
27
|
readPairingClaim,
|
|
26
28
|
reportLinkStatusToServer,
|
|
27
29
|
resolveHermesConfigPath,
|
|
@@ -32,7 +34,7 @@ import {
|
|
|
32
34
|
startDaemonProcess,
|
|
33
35
|
startLinkService,
|
|
34
36
|
stopDaemonProcess
|
|
35
|
-
} from "../chunk-
|
|
37
|
+
} from "../chunk-FWPHQZP6.js";
|
|
36
38
|
|
|
37
39
|
// src/cli/index.ts
|
|
38
40
|
import { Command } from "commander";
|
|
@@ -273,16 +275,16 @@ var messages = {
|
|
|
273
275
|
"autostart.alreadyEnabled": "Boot autostart is already enabled via {method}: {path}",
|
|
274
276
|
"pair.description": "Create a Hermes Link pairing session",
|
|
275
277
|
"pair.preflight": "Checking local Hermes configuration before pairing...",
|
|
278
|
+
"pair.preflight.hermesFiles": "Checking Hermes data directory, config, and environment files...",
|
|
279
|
+
"pair.preflight.hermesCli": "Checking whether the Hermes CLI is available...",
|
|
280
|
+
"pair.preflight.hermesApiServer": "Checking whether the Hermes API Server is ready...",
|
|
276
281
|
"pair.hermesHome": "Hermes home: {path}",
|
|
282
|
+
"pair.hermesVersion": "Hermes CLI: {value}",
|
|
277
283
|
"pair.apiReady": "Hermes API Server is ready on 127.0.0.1:{port}",
|
|
278
|
-
"pair.preparing": "
|
|
279
|
-
"pair.
|
|
280
|
-
"pair.
|
|
281
|
-
"pair.
|
|
282
|
-
"pair.code": "Pairing code: {value}",
|
|
283
|
-
"pair.localApi": "Local API: http://127.0.0.1:{port}",
|
|
284
|
-
"pair.scan": "Open this pairing page in the HermesPilot App or scan the QR code below:",
|
|
285
|
-
"pair.openBrowserFailed": "Could not open the system browser automatically. You can still scan the QR code below or open this URL manually: {url}",
|
|
284
|
+
"pair.preparing": "Creating the pairing session...",
|
|
285
|
+
"pair.scan": "Please scan the QR code below in the HermesPilot App:",
|
|
286
|
+
"pair.openPairingPage": "If the QR code is hard to scan, you can open this page locally: {url}",
|
|
287
|
+
"pair.manualCode": "You can also use the HermesPilot App manual connection mode and enter this pairing code:",
|
|
286
288
|
"pair.expires": "Pairing expires in 10 minutes. Press Ctrl+C to cancel waiting.",
|
|
287
289
|
"pair.claimed": "Pairing succeeded. Starting Hermes Link in the background...",
|
|
288
290
|
"pair.claimedRunning": "Pairing succeeded. Hermes Link is already running in the background.",
|
|
@@ -298,6 +300,8 @@ var messages = {
|
|
|
298
300
|
"doctor.notAssigned": "not assigned",
|
|
299
301
|
"doctor.lanHost": "Configured LAN host: {value}",
|
|
300
302
|
"doctor.networkWarning": "Network note: {message}",
|
|
303
|
+
"doctor.hermesCli": "Hermes CLI: {value}",
|
|
304
|
+
"doctor.hermesCliUnavailable": "Hermes CLI is unavailable. Please make sure the `hermes` command can run in this system.",
|
|
301
305
|
"doctor.apiReady": "Hermes API Server: ready",
|
|
302
306
|
"doctor.apiStarted": "Hermes API Server: started and ready",
|
|
303
307
|
"doctor.apiUnavailable": "Hermes API Server: unavailable. {message}",
|
|
@@ -306,6 +310,8 @@ var messages = {
|
|
|
306
310
|
"error.relayLinkInvalid": "Relay did not return a valid link_id.",
|
|
307
311
|
"error.relayEmpty": "Relay returned an empty response.",
|
|
308
312
|
"error.serverHttp": "HermesPilot Server request failed with HTTP {status}.",
|
|
313
|
+
"error.pairingServerUnreachable": "Could not reach HermesPilot Server while creating the pairing session. Check whether {url} is reachable, then try again. If you use a proxy network, add hermes-server.clawpilot.me and hermes-relay.clawpilot.me to the proxy exclusion list, or temporarily turn off VPN/proxy and retry.",
|
|
314
|
+
"error.pairingRelayUnreachable": "Could not reach Hermes Relay while creating the pairing session. Check whether {url} is reachable, then try again. If you use a proxy network, add hermes-server.clawpilot.me and hermes-relay.clawpilot.me to the proxy exclusion list, or temporarily turn off VPN/proxy and retry.",
|
|
309
315
|
"error.portInUse": "Local port {port} is already in use by another process. Stop that process or change the Hermes Link port, then run `hermeslink pair` again.",
|
|
310
316
|
"error.pairingRequires": "Pairing needs HermesPilot Server and Relay, but this command could not start a complete pairing session.",
|
|
311
317
|
"error.pairingRequires.detail": "The deployed services may be healthy, but the installed Link package must call Server for a short-lived relay bootstrap token before it can request a link_id."
|
|
@@ -363,16 +369,16 @@ var messages = {
|
|
|
363
369
|
"autostart.alreadyEnabled": "\u5F00\u673A\u81EA\u542F\u5DF2\u542F\u7528\uFF0C\u65B9\u5F0F\uFF1A{method}\uFF0C\u6587\u4EF6\uFF1A{path}",
|
|
364
370
|
"pair.description": "\u521B\u5EFA Hermes Link \u914D\u5BF9\u4F1A\u8BDD",
|
|
365
371
|
"pair.preflight": "\u6B63\u5728\u914D\u5BF9\u524D\u68C0\u67E5\u672C\u673A Hermes \u914D\u7F6E...",
|
|
372
|
+
"pair.preflight.hermesFiles": "\u6B63\u5728\u68C0\u67E5 Hermes \u6570\u636E\u76EE\u5F55\u3001\u914D\u7F6E\u6587\u4EF6\u548C\u73AF\u5883\u6587\u4EF6...",
|
|
373
|
+
"pair.preflight.hermesCli": "\u6B63\u5728\u68C0\u67E5 Hermes CLI \u662F\u5426\u53EF\u7528...",
|
|
374
|
+
"pair.preflight.hermesApiServer": "\u6B63\u5728\u68C0\u67E5 Hermes API Server \u662F\u5426\u5C31\u7EEA...",
|
|
366
375
|
"pair.hermesHome": "Hermes \u6570\u636E\u76EE\u5F55\uFF1A{path}",
|
|
376
|
+
"pair.hermesVersion": "Hermes CLI\uFF1A{value}",
|
|
367
377
|
"pair.apiReady": "Hermes API Server \u5DF2\u5C31\u7EEA\uFF1A127.0.0.1:{port}",
|
|
368
|
-
"pair.preparing": "\u6B63\u5728\
|
|
369
|
-
"pair.
|
|
370
|
-
"pair.
|
|
371
|
-
"pair.
|
|
372
|
-
"pair.code": "\u914D\u5BF9\u7801\uFF1A{value}",
|
|
373
|
-
"pair.localApi": "\u672C\u5730 API\uFF1Ahttp://127.0.0.1:{port}",
|
|
374
|
-
"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",
|
|
375
|
-
"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}",
|
|
378
|
+
"pair.preparing": "\u6B63\u5728\u521B\u5EFA\u914D\u5BF9\u4F1A\u8BDD...",
|
|
379
|
+
"pair.scan": "\u8BF7\u5728 HermesPilot App \u4E2D\u626B\u7801\u4E0B\u9762\u7684\u4E8C\u7EF4\u7801\uFF1A",
|
|
380
|
+
"pair.openPairingPage": "\u5982\u679C\u4E8C\u7EF4\u7801\u4E0D\u5BB9\u6613\u626B\u63CF\uFF0C\u4F60\u53EF\u4EE5\u5728\u672C\u673A\u6253\u5F00\u8FD9\u4E2A\u9875\u9762\uFF1A{url}",
|
|
381
|
+
"pair.manualCode": "\u4F60\u4E5F\u53EF\u4EE5\u5728 HermesPilot App \u4E2D\u4F7F\u7528\u624B\u52A8\u8FDE\u63A5\u6A21\u5F0F\uFF0C\u8F93\u5165\u4EE5\u4E0B\u914D\u5BF9\u7801\u8FDB\u884C\u8FDE\u63A5\uFF1A",
|
|
376
382
|
"pair.expires": "\u914D\u5BF9\u4F1A\u8BDD 10 \u5206\u949F\u540E\u8FC7\u671F\u3002\u6309 Ctrl+C \u9000\u51FA\u7B49\u5F85\u3002",
|
|
377
383
|
"pair.claimed": "\u914D\u5BF9\u5DF2\u6210\u529F\u3002\u6B63\u5728\u628A Hermes Link \u5207\u6362\u5230\u540E\u53F0\u8FD0\u884C...",
|
|
378
384
|
"pair.claimedRunning": "\u914D\u5BF9\u5DF2\u6210\u529F\u3002Hermes Link \u5DF2\u5728\u540E\u53F0\u6301\u7EED\u8FD0\u884C\u3002",
|
|
@@ -388,6 +394,8 @@ var messages = {
|
|
|
388
394
|
"doctor.notAssigned": "\u5C1A\u672A\u5206\u914D",
|
|
389
395
|
"doctor.lanHost": "\u5DF2\u914D\u7F6E\u5C40\u57DF\u7F51\u4E3B\u673A\uFF1A{value}",
|
|
390
396
|
"doctor.networkWarning": "\u7F51\u7EDC\u63D0\u793A\uFF1A{message}",
|
|
397
|
+
"doctor.hermesCli": "Hermes CLI\uFF1A{value}",
|
|
398
|
+
"doctor.hermesCliUnavailable": "Hermes CLI\uFF1A\u4E0D\u53EF\u7528\u3002\u8BF7\u786E\u8BA4\u5F53\u524D\u7CFB\u7EDF\u53EF\u4EE5\u76F4\u63A5\u8FD0\u884C `hermes` \u547D\u4EE4\u3002",
|
|
391
399
|
"doctor.apiReady": "Hermes API Server\uFF1A\u5DF2\u5C31\u7EEA",
|
|
392
400
|
"doctor.apiStarted": "Hermes API Server\uFF1A\u5DF2\u81EA\u52A8\u542F\u52A8\u5E76\u5C31\u7EEA",
|
|
393
401
|
"doctor.apiUnavailable": "Hermes API Server\uFF1A\u4E0D\u53EF\u7528\u3002{message}",
|
|
@@ -396,6 +404,8 @@ var messages = {
|
|
|
396
404
|
"error.relayLinkInvalid": "Relay \u6CA1\u6709\u8FD4\u56DE\u6709\u6548\u7684 link_id\u3002",
|
|
397
405
|
"error.relayEmpty": "Relay \u8FD4\u56DE\u4E86\u7A7A\u54CD\u5E94\u3002",
|
|
398
406
|
"error.serverHttp": "HermesPilot Server \u8BF7\u6C42\u5931\u8D25\uFF0CHTTP \u72B6\u6001\u7801\uFF1A{status}\u3002",
|
|
407
|
+
"error.pairingServerUnreachable": "\u521B\u5EFA\u914D\u5BF9\u4F1A\u8BDD\u65F6\u65E0\u6CD5\u8FDE\u63A5 HermesPilot Server\u3002\u8BF7\u5148\u786E\u8BA4 {url} \u53EF\u4EE5\u8BBF\u95EE\uFF0C\u7136\u540E\u91CD\u8BD5\u3002\u91CD\u70B9\u63D0\u9192\uFF1A\u5982\u679C\u4F60\u4F7F\u7528\u4E86\u4EE3\u7406\u7F51\u7EDC\uFF0C\u53EF\u4EE5\u628A hermes-server.clawpilot.me \u548C hermes-relay.clawpilot.me \u52A0\u5165\u4EE3\u7406\u6392\u9664\u540D\u5355\uFF0C\u6216\u4E34\u65F6\u5173\u95ED VPN/\u4EE3\u7406\u540E\u518D\u8BD5\u3002",
|
|
408
|
+
"error.pairingRelayUnreachable": "\u521B\u5EFA\u914D\u5BF9\u4F1A\u8BDD\u65F6\u65E0\u6CD5\u8FDE\u63A5 Hermes Relay\u3002\u8BF7\u5148\u786E\u8BA4 {url} \u53EF\u4EE5\u8BBF\u95EE\uFF0C\u7136\u540E\u91CD\u8BD5\u3002\u91CD\u70B9\u63D0\u9192\uFF1A\u5982\u679C\u4F60\u4F7F\u7528\u4E86\u4EE3\u7406\u7F51\u7EDC\uFF0C\u53EF\u4EE5\u628A hermes-server.clawpilot.me \u548C hermes-relay.clawpilot.me \u52A0\u5165\u4EE3\u7406\u6392\u9664\u540D\u5355\uFF0C\u6216\u4E34\u65F6\u5173\u95ED VPN/\u4EE3\u7406\u540E\u518D\u8BD5\u3002",
|
|
399
409
|
"error.portInUse": "\u672C\u5730\u7AEF\u53E3 {port} \u5DF2\u88AB\u5176\u4ED6\u8FDB\u7A0B\u5360\u7528\u3002\u8BF7\u5148\u505C\u6B62\u5360\u7528\u8BE5\u7AEF\u53E3\u7684\u7A0B\u5E8F\uFF0C\u6216\u8C03\u6574 Hermes Link \u7AEF\u53E3\u540E\u91CD\u65B0\u8FD0\u884C `hermeslink pair`\u3002",
|
|
400
410
|
"error.pairingRequires": "\u914D\u5BF9\u9700\u8981 HermesPilot Server \u548C Relay\uFF0C\u4F46\u5F53\u524D\u547D\u4EE4\u6CA1\u6709\u80FD\u542F\u52A8\u5B8C\u6574\u914D\u5BF9\u4F1A\u8BDD\u3002",
|
|
401
411
|
"error.pairingRequires.detail": "\u4E91\u7AEF\u670D\u52A1\u53EF\u4EE5\u662F\u5DF2\u90E8\u7F72\u4E14\u5065\u5EB7\u7684\uFF1B\u672C\u673A Link \u4ECD\u5FC5\u987B\u5148\u5411 Server \u7533\u8BF7\u77ED\u671F relay bootstrap token\uFF0C\u624D\u80FD\u518D\u5411 Relay \u7533\u8BF7 link_id\u3002"
|
|
@@ -459,6 +469,18 @@ function translateKnownError(message, language) {
|
|
|
459
469
|
if (serverHttp?.groups?.status) {
|
|
460
470
|
return translate(language, "error.serverHttp", { status: serverHttp.groups.status });
|
|
461
471
|
}
|
|
472
|
+
const pairingServerUnreachable = /^HermesPilot Server is unreachable while trying to [^.]+\. Please check whether (?<url>\S+) is reachable\./u.exec(message);
|
|
473
|
+
if (pairingServerUnreachable?.groups?.url) {
|
|
474
|
+
return translate(language, "error.pairingServerUnreachable", {
|
|
475
|
+
url: pairingServerUnreachable.groups.url
|
|
476
|
+
});
|
|
477
|
+
}
|
|
478
|
+
const pairingRelayUnreachable = /^Hermes Relay is unreachable while trying to [^.]+\. Please check whether (?<url>\S+) is reachable\./u.exec(message);
|
|
479
|
+
if (pairingRelayUnreachable?.groups?.url) {
|
|
480
|
+
return translate(language, "error.pairingRelayUnreachable", {
|
|
481
|
+
url: pairingRelayUnreachable.groups.url
|
|
482
|
+
});
|
|
483
|
+
}
|
|
462
484
|
if (message.includes("Pairing requires HermesPilot Server and Relay")) {
|
|
463
485
|
return [translate(language, "error.pairingRequires"), translate(language, "error.pairingRequires.detail")].join("\n");
|
|
464
486
|
}
|
|
@@ -487,6 +509,7 @@ async function assertPairingPreflightReady(options = {}) {
|
|
|
487
509
|
const configPath = resolveHermesConfigPath(profileName);
|
|
488
510
|
const envPath = path2.join(hermesHome, ".env");
|
|
489
511
|
const failures = [];
|
|
512
|
+
options.onProgress?.("hermes_files");
|
|
490
513
|
if (!await isDirectory(hermesHome)) {
|
|
491
514
|
failures.push({
|
|
492
515
|
code: "hermes_home_missing",
|
|
@@ -517,6 +540,23 @@ async function assertPairingPreflightReady(options = {}) {
|
|
|
517
540
|
if (failures.length > 0) {
|
|
518
541
|
throwPairingPreflightError(failures);
|
|
519
542
|
}
|
|
543
|
+
options.onProgress?.("hermes_cli");
|
|
544
|
+
let hermesVersion;
|
|
545
|
+
try {
|
|
546
|
+
const readVersion = options.readHermesVersion ?? readHermesVersion;
|
|
547
|
+
hermesVersion = await readVersion();
|
|
548
|
+
} catch {
|
|
549
|
+
throwPairingPreflightError([
|
|
550
|
+
{
|
|
551
|
+
code: "hermes_cli_unavailable",
|
|
552
|
+
zh: "\u6682\u65F6\u627E\u4E0D\u5230\u53EF\u7528\u7684 Hermes CLI \u547D\u4EE4\u3002",
|
|
553
|
+
en: "Hermes CLI is not available right now.",
|
|
554
|
+
actionZh: "\u8BF7\u786E\u8BA4 Hermes Link \u548C Hermes Agent \u5B89\u88C5\u5728\u540C\u4E00\u4E2A\u7CFB\u7EDF\u73AF\u5883\u4E2D\uFF0C\u5E76\u4E14\u7EC8\u7AEF\u80FD\u76F4\u63A5\u8FD0\u884C `hermes`\u3002\u5982\u679C\u4F60\u4F7F\u7528\u4E86\u81EA\u5B9A\u4E49\u5B89\u88C5\u8DEF\u5F84\uFF0C\u4E5F\u53EF\u4EE5\u8BBE\u7F6E HERMES_BIN\u3002",
|
|
555
|
+
actionEn: "Make sure Hermes Link and Hermes Agent are installed in the same system environment, and that the terminal can run `hermes` directly. If Hermes is installed in a custom location, set HERMES_BIN."
|
|
556
|
+
}
|
|
557
|
+
]);
|
|
558
|
+
}
|
|
559
|
+
options.onProgress?.("hermes_api_server");
|
|
520
560
|
const apiServerConfig = await readHermesApiServerConfig(profileName, configPath);
|
|
521
561
|
if (apiServerConfig.enabled !== true) {
|
|
522
562
|
throwPairingPreflightError([
|
|
@@ -548,6 +588,10 @@ async function assertPairingPreflightReady(options = {}) {
|
|
|
548
588
|
started: availability.started,
|
|
549
589
|
host: availability.configResult.apiServer.host ?? null,
|
|
550
590
|
port: availability.configResult.apiServer.port ?? null
|
|
591
|
+
},
|
|
592
|
+
hermesVersion: {
|
|
593
|
+
raw: hermesVersion.raw,
|
|
594
|
+
version: hermesVersion.version
|
|
551
595
|
}
|
|
552
596
|
};
|
|
553
597
|
} catch (error) {
|
|
@@ -780,16 +824,17 @@ program.command("pair").description(helpText("pair.description")).action(async (
|
|
|
780
824
|
const language = languageChoice.language;
|
|
781
825
|
const t = translate.bind(null, language);
|
|
782
826
|
console.log(t("pair.preflight"));
|
|
783
|
-
const preflight = await assertPairingPreflightReady({ paths });
|
|
784
827
|
const environment = detectRuntimeEnvironment();
|
|
785
828
|
if (environment.warning) {
|
|
786
829
|
console.log(t("doctor.networkWarning", { message: environment.warning }));
|
|
787
830
|
}
|
|
788
|
-
|
|
789
|
-
|
|
831
|
+
await assertPairingPreflightReady({
|
|
832
|
+
paths,
|
|
833
|
+
onProgress: (stage) => {
|
|
834
|
+
console.log(t(pairingPreflightProgressKey(stage)));
|
|
835
|
+
}
|
|
836
|
+
});
|
|
790
837
|
console.log(t("pair.preparing"));
|
|
791
|
-
console.log(t("pair.server", { url: config.serverBaseUrl }));
|
|
792
|
-
console.log(t("pair.relay", { url: config.relayBaseUrl }));
|
|
793
838
|
await ensureIdentity(paths);
|
|
794
839
|
const hadActiveDevices = await hasActiveDevices(paths);
|
|
795
840
|
const probeBeforePair = await probeLocalLinkService({ port: config.port });
|
|
@@ -803,62 +848,71 @@ program.command("pair").description(helpText("pair.description")).action(async (
|
|
|
803
848
|
}
|
|
804
849
|
const reusedRunningService = probe.reusable;
|
|
805
850
|
const restartReusedServiceAfterClaim = reusedRunningService && !probeBeforePair.linkId;
|
|
806
|
-
const service = reusedRunningService ? null : await startLinkService({
|
|
851
|
+
const service = reusedRunningService ? null : await startLinkService({
|
|
852
|
+
paths,
|
|
853
|
+
waitForRelayReady: true
|
|
854
|
+
});
|
|
855
|
+
let pairingRelayBridge = null;
|
|
856
|
+
if (restartReusedServiceAfterClaim) {
|
|
857
|
+
pairingRelayBridge = connectRelayControl({
|
|
858
|
+
relayBaseUrl: prepared.relayBaseUrl,
|
|
859
|
+
linkId: prepared.linkId,
|
|
860
|
+
localPort: config.port
|
|
861
|
+
});
|
|
862
|
+
pairingRelayBridge.publishNetworkRoutes(prepared.routes);
|
|
863
|
+
}
|
|
807
864
|
const qrValue = JSON.stringify(prepared.qrPayload);
|
|
808
865
|
const pairingPageUrl = `http://127.0.0.1:${config.port}/pair?session_id=${encodeURIComponent(prepared.sessionId)}`;
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
console.log(t("
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
await clearPairingClaim(prepared.sessionId, paths);
|
|
829
|
-
console.log(t(reusedRunningService ? "pair.claimedRunning" : "pair.claimed"));
|
|
830
|
-
printPostPairingNetworkNotice(prepared.routes.environment, config, t);
|
|
831
|
-
try {
|
|
832
|
-
if (hadActiveDevices) {
|
|
833
|
-
console.log(t("pair.autostartUnchanged"));
|
|
834
|
-
} else {
|
|
835
|
-
const currentAutostart = await getAutostartStatus();
|
|
836
|
-
if (currentAutostart.supported && currentAutostart.enabled) {
|
|
837
|
-
console.log(
|
|
838
|
-
t("autostart.alreadyEnabled", {
|
|
839
|
-
method: currentAutostart.method,
|
|
840
|
-
path: currentAutostart.filePath ?? ""
|
|
841
|
-
})
|
|
842
|
-
);
|
|
866
|
+
try {
|
|
867
|
+
console.log(t("pair.scan"));
|
|
868
|
+
qrcode.generate(qrValue, { small: true });
|
|
869
|
+
await openSystemBrowser(pairingPageUrl);
|
|
870
|
+
console.log(t("pair.openPairingPage", { url: pairingPageUrl }));
|
|
871
|
+
console.log(t("pair.manualCode"));
|
|
872
|
+
console.log(prepared.code);
|
|
873
|
+
console.log(t("pair.expires"));
|
|
874
|
+
const result = await waitForPairingOrShutdown(prepared.sessionId, paths);
|
|
875
|
+
if (service) {
|
|
876
|
+
await service.close();
|
|
877
|
+
}
|
|
878
|
+
if (result === "claimed") {
|
|
879
|
+
await clearPairingClaim(prepared.sessionId, paths);
|
|
880
|
+
console.log(t(reusedRunningService ? "pair.claimedRunning" : "pair.claimed"));
|
|
881
|
+
printPostPairingNetworkNotice(prepared.routes.environment, config, t);
|
|
882
|
+
try {
|
|
883
|
+
if (hadActiveDevices) {
|
|
884
|
+
console.log(t("pair.autostartUnchanged"));
|
|
843
885
|
} else {
|
|
844
|
-
const
|
|
845
|
-
if (
|
|
846
|
-
console.log(
|
|
886
|
+
const currentAutostart = await getAutostartStatus();
|
|
887
|
+
if (currentAutostart.supported && currentAutostart.enabled) {
|
|
888
|
+
console.log(
|
|
889
|
+
t("autostart.alreadyEnabled", {
|
|
890
|
+
method: currentAutostart.method,
|
|
891
|
+
path: currentAutostart.filePath ?? ""
|
|
892
|
+
})
|
|
893
|
+
);
|
|
894
|
+
} else {
|
|
895
|
+
const autostart2 = await enableAutostart();
|
|
896
|
+
if (autostart2.supported && autostart2.enabled) {
|
|
897
|
+
console.log(t("autostart.enabled", { method: autostart2.method, path: autostart2.filePath ?? "" }));
|
|
898
|
+
}
|
|
847
899
|
}
|
|
848
900
|
}
|
|
901
|
+
} catch (error) {
|
|
902
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
903
|
+
console.log(t("pair.autostartFailed", { message }));
|
|
904
|
+
}
|
|
905
|
+
if (restartReusedServiceAfterClaim) {
|
|
906
|
+
await stopDaemonProcess(paths);
|
|
907
|
+
const status = await startDaemonProcess(paths);
|
|
908
|
+
console.log(t("start.backgroundStarted", { pid: status.pid ?? "unknown" }));
|
|
909
|
+
} else if (!reusedRunningService) {
|
|
910
|
+
const status = await startDaemonProcess(paths);
|
|
911
|
+
console.log(t("start.backgroundStarted", { pid: status.pid ?? "unknown" }));
|
|
849
912
|
}
|
|
850
|
-
} catch (error) {
|
|
851
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
852
|
-
console.log(t("pair.autostartFailed", { message }));
|
|
853
|
-
}
|
|
854
|
-
if (restartReusedServiceAfterClaim) {
|
|
855
|
-
await stopDaemonProcess(paths);
|
|
856
|
-
const status = await startDaemonProcess(paths);
|
|
857
|
-
console.log(t("start.backgroundStarted", { pid: status.pid ?? "unknown" }));
|
|
858
|
-
} else if (!reusedRunningService) {
|
|
859
|
-
const status = await startDaemonProcess(paths);
|
|
860
|
-
console.log(t("start.backgroundStarted", { pid: status.pid ?? "unknown" }));
|
|
861
913
|
}
|
|
914
|
+
} finally {
|
|
915
|
+
pairingRelayBridge?.close();
|
|
862
916
|
}
|
|
863
917
|
});
|
|
864
918
|
var autostart = program.command("autostart").description(helpText("autostart.description"));
|
|
@@ -923,6 +977,12 @@ program.command("doctor").description(helpText("doctor.description")).action(asy
|
|
|
923
977
|
console.log(`Hermes config backup: ${hermesConfig.backupPath}`);
|
|
924
978
|
}
|
|
925
979
|
}
|
|
980
|
+
try {
|
|
981
|
+
const hermesVersion = await readHermesVersion();
|
|
982
|
+
console.log(t("doctor.hermesCli", { value: formatHermesVersion(hermesVersion) }));
|
|
983
|
+
} catch {
|
|
984
|
+
console.log(t("doctor.hermesCliUnavailable"));
|
|
985
|
+
}
|
|
926
986
|
try {
|
|
927
987
|
const availability = await ensureHermesApiServerAvailable({ timeoutMs: 5e3 });
|
|
928
988
|
console.log(t(availability.started ? "doctor.apiStarted" : "doctor.apiReady"));
|
|
@@ -939,6 +999,19 @@ async function loadCliLanguage() {
|
|
|
939
999
|
const config = await loadConfig();
|
|
940
1000
|
return resolveLanguage(config.language);
|
|
941
1001
|
}
|
|
1002
|
+
function formatHermesVersion(version) {
|
|
1003
|
+
return version.version ?? version.raw;
|
|
1004
|
+
}
|
|
1005
|
+
function pairingPreflightProgressKey(stage) {
|
|
1006
|
+
switch (stage) {
|
|
1007
|
+
case "hermes_files":
|
|
1008
|
+
return "pair.preflight.hermesFiles";
|
|
1009
|
+
case "hermes_cli":
|
|
1010
|
+
return "pair.preflight.hermesCli";
|
|
1011
|
+
case "hermes_api_server":
|
|
1012
|
+
return "pair.preflight.hermesApiServer";
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
942
1015
|
async function deliverStagedFilesFromCli(stagingDir, paths, config) {
|
|
943
1016
|
try {
|
|
944
1017
|
return await deliverStagedFilesThroughDaemon(stagingDir, config.port);
|
package/dist/http/app.d.ts
CHANGED
|
@@ -183,6 +183,19 @@ interface BulkDeleteConversationResult {
|
|
|
183
183
|
message: string;
|
|
184
184
|
};
|
|
185
185
|
}
|
|
186
|
+
type ConversationClearPlanStatus = 'prepared' | 'executing' | 'completed' | 'failed';
|
|
187
|
+
interface ConversationClearPlan {
|
|
188
|
+
id: string;
|
|
189
|
+
status: ConversationClearPlanStatus;
|
|
190
|
+
created_at: string;
|
|
191
|
+
updated_at: string;
|
|
192
|
+
total_count: number;
|
|
193
|
+
deleted_count: number;
|
|
194
|
+
failed_count: number;
|
|
195
|
+
conversation_ids: string[];
|
|
196
|
+
conversations: BulkDeleteConversationResult[];
|
|
197
|
+
completed_at?: string;
|
|
198
|
+
}
|
|
186
199
|
interface LinkRun {
|
|
187
200
|
id: string;
|
|
188
201
|
kind?: 'agent' | 'command';
|
|
@@ -462,6 +475,10 @@ declare class ConversationService {
|
|
|
462
475
|
last_event_seq: number;
|
|
463
476
|
}>;
|
|
464
477
|
deleteConversation(conversationId: string): Promise<DeleteConversationResult>;
|
|
478
|
+
prepareClearAllConversationPlan(): Promise<ConversationClearPlan>;
|
|
479
|
+
readClearAllConversationPlan(planId: string): Promise<ConversationClearPlan>;
|
|
480
|
+
executeClearAllConversationPlan(planId: string): Promise<ConversationClearPlan>;
|
|
481
|
+
startClearAllConversationPlan(planId: string): Promise<ConversationClearPlan>;
|
|
465
482
|
deleteConversations(conversationIds: string[]): Promise<{
|
|
466
483
|
deleted_count: number;
|
|
467
484
|
failed_count: number;
|
package/dist/http/app.js
CHANGED