@hermespilot/link 0.3.7 → 0.3.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/cli/index.js CHANGED
@@ -22,6 +22,7 @@ import {
22
22
  preparePairing,
23
23
  probeLocalLinkService,
24
24
  readHermesApiServerConfig,
25
+ readHermesVersion,
25
26
  readPairingClaim,
26
27
  reportLinkStatusToServer,
27
28
  resolveHermesConfigPath,
@@ -32,7 +33,7 @@ import {
32
33
  startDaemonProcess,
33
34
  startLinkService,
34
35
  stopDaemonProcess
35
- } from "../chunk-TZVQZFWU.js";
36
+ } from "../chunk-7OVDWXR7.js";
36
37
 
37
38
  // src/cli/index.ts
38
39
  import { Command } from "commander";
@@ -273,16 +274,16 @@ var messages = {
273
274
  "autostart.alreadyEnabled": "Boot autostart is already enabled via {method}: {path}",
274
275
  "pair.description": "Create a Hermes Link pairing session",
275
276
  "pair.preflight": "Checking local Hermes configuration before pairing...",
277
+ "pair.preflight.hermesFiles": "Checking Hermes data directory, config, and environment files...",
278
+ "pair.preflight.hermesCli": "Checking whether the Hermes CLI is available...",
279
+ "pair.preflight.hermesApiServer": "Checking whether the Hermes API Server is ready...",
276
280
  "pair.hermesHome": "Hermes home: {path}",
281
+ "pair.hermesVersion": "Hermes CLI: {value}",
277
282
  "pair.apiReady": "Hermes API Server is ready on 127.0.0.1:{port}",
278
- "pair.preparing": "Preparing pairing session through HermesPilot Server and Relay...",
279
- "pair.server": "Server: {url}",
280
- "pair.relay": "Relay: {url}",
281
- "pair.linkId": "Hermes Link ID: {value}",
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}",
283
+ "pair.preparing": "Creating the pairing session...",
284
+ "pair.scan": "Please scan the QR code below in the HermesPilot App:",
285
+ "pair.openPairingPage": "If the QR code is hard to scan, you can open this page locally: {url}",
286
+ "pair.manualCode": "You can also use the HermesPilot App manual connection mode and enter this pairing code:",
286
287
  "pair.expires": "Pairing expires in 10 minutes. Press Ctrl+C to cancel waiting.",
287
288
  "pair.claimed": "Pairing succeeded. Starting Hermes Link in the background...",
288
289
  "pair.claimedRunning": "Pairing succeeded. Hermes Link is already running in the background.",
@@ -298,6 +299,8 @@ var messages = {
298
299
  "doctor.notAssigned": "not assigned",
299
300
  "doctor.lanHost": "Configured LAN host: {value}",
300
301
  "doctor.networkWarning": "Network note: {message}",
302
+ "doctor.hermesCli": "Hermes CLI: {value}",
303
+ "doctor.hermesCliUnavailable": "Hermes CLI is unavailable. Please make sure the `hermes` command can run in this system.",
301
304
  "doctor.apiReady": "Hermes API Server: ready",
302
305
  "doctor.apiStarted": "Hermes API Server: started and ready",
303
306
  "doctor.apiUnavailable": "Hermes API Server: unavailable. {message}",
@@ -306,6 +309,8 @@ var messages = {
306
309
  "error.relayLinkInvalid": "Relay did not return a valid link_id.",
307
310
  "error.relayEmpty": "Relay returned an empty response.",
308
311
  "error.serverHttp": "HermesPilot Server request failed with HTTP {status}.",
312
+ "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.",
313
+ "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
314
  "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
315
  "error.pairingRequires": "Pairing needs HermesPilot Server and Relay, but this command could not start a complete pairing session.",
311
316
  "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 +368,16 @@ var messages = {
363
368
  "autostart.alreadyEnabled": "\u5F00\u673A\u81EA\u542F\u5DF2\u542F\u7528\uFF0C\u65B9\u5F0F\uFF1A{method}\uFF0C\u6587\u4EF6\uFF1A{path}",
364
369
  "pair.description": "\u521B\u5EFA Hermes Link \u914D\u5BF9\u4F1A\u8BDD",
365
370
  "pair.preflight": "\u6B63\u5728\u914D\u5BF9\u524D\u68C0\u67E5\u672C\u673A Hermes \u914D\u7F6E...",
371
+ "pair.preflight.hermesFiles": "\u6B63\u5728\u68C0\u67E5 Hermes \u6570\u636E\u76EE\u5F55\u3001\u914D\u7F6E\u6587\u4EF6\u548C\u73AF\u5883\u6587\u4EF6...",
372
+ "pair.preflight.hermesCli": "\u6B63\u5728\u68C0\u67E5 Hermes CLI \u662F\u5426\u53EF\u7528...",
373
+ "pair.preflight.hermesApiServer": "\u6B63\u5728\u68C0\u67E5 Hermes API Server \u662F\u5426\u5C31\u7EEA...",
366
374
  "pair.hermesHome": "Hermes \u6570\u636E\u76EE\u5F55\uFF1A{path}",
375
+ "pair.hermesVersion": "Hermes CLI\uFF1A{value}",
367
376
  "pair.apiReady": "Hermes API Server \u5DF2\u5C31\u7EEA\uFF1A127.0.0.1:{port}",
368
- "pair.preparing": "\u6B63\u5728\u901A\u8FC7 HermesPilot Server \u548C Relay \u521B\u5EFA\u914D\u5BF9\u4F1A\u8BDD...",
369
- "pair.server": "Server\uFF1A{url}",
370
- "pair.relay": "Relay\uFF1A{url}",
371
- "pair.linkId": "Hermes Link ID\uFF1A{value}",
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}",
377
+ "pair.preparing": "\u6B63\u5728\u521B\u5EFA\u914D\u5BF9\u4F1A\u8BDD...",
378
+ "pair.scan": "\u8BF7\u5728 HermesPilot App \u4E2D\u626B\u7801\u4E0B\u9762\u7684\u4E8C\u7EF4\u7801\uFF1A",
379
+ "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}",
380
+ "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
381
  "pair.expires": "\u914D\u5BF9\u4F1A\u8BDD 10 \u5206\u949F\u540E\u8FC7\u671F\u3002\u6309 Ctrl+C \u9000\u51FA\u7B49\u5F85\u3002",
377
382
  "pair.claimed": "\u914D\u5BF9\u5DF2\u6210\u529F\u3002\u6B63\u5728\u628A Hermes Link \u5207\u6362\u5230\u540E\u53F0\u8FD0\u884C...",
378
383
  "pair.claimedRunning": "\u914D\u5BF9\u5DF2\u6210\u529F\u3002Hermes Link \u5DF2\u5728\u540E\u53F0\u6301\u7EED\u8FD0\u884C\u3002",
@@ -388,6 +393,8 @@ var messages = {
388
393
  "doctor.notAssigned": "\u5C1A\u672A\u5206\u914D",
389
394
  "doctor.lanHost": "\u5DF2\u914D\u7F6E\u5C40\u57DF\u7F51\u4E3B\u673A\uFF1A{value}",
390
395
  "doctor.networkWarning": "\u7F51\u7EDC\u63D0\u793A\uFF1A{message}",
396
+ "doctor.hermesCli": "Hermes CLI\uFF1A{value}",
397
+ "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
398
  "doctor.apiReady": "Hermes API Server\uFF1A\u5DF2\u5C31\u7EEA",
392
399
  "doctor.apiStarted": "Hermes API Server\uFF1A\u5DF2\u81EA\u52A8\u542F\u52A8\u5E76\u5C31\u7EEA",
393
400
  "doctor.apiUnavailable": "Hermes API Server\uFF1A\u4E0D\u53EF\u7528\u3002{message}",
@@ -396,6 +403,8 @@ var messages = {
396
403
  "error.relayLinkInvalid": "Relay \u6CA1\u6709\u8FD4\u56DE\u6709\u6548\u7684 link_id\u3002",
397
404
  "error.relayEmpty": "Relay \u8FD4\u56DE\u4E86\u7A7A\u54CD\u5E94\u3002",
398
405
  "error.serverHttp": "HermesPilot Server \u8BF7\u6C42\u5931\u8D25\uFF0CHTTP \u72B6\u6001\u7801\uFF1A{status}\u3002",
406
+ "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",
407
+ "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
408
  "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
409
  "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
410
  "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 +468,18 @@ function translateKnownError(message, language) {
459
468
  if (serverHttp?.groups?.status) {
460
469
  return translate(language, "error.serverHttp", { status: serverHttp.groups.status });
461
470
  }
471
+ const pairingServerUnreachable = /^HermesPilot Server is unreachable while trying to [^.]+\. Please check whether (?<url>\S+) is reachable\./u.exec(message);
472
+ if (pairingServerUnreachable?.groups?.url) {
473
+ return translate(language, "error.pairingServerUnreachable", {
474
+ url: pairingServerUnreachable.groups.url
475
+ });
476
+ }
477
+ const pairingRelayUnreachable = /^Hermes Relay is unreachable while trying to [^.]+\. Please check whether (?<url>\S+) is reachable\./u.exec(message);
478
+ if (pairingRelayUnreachable?.groups?.url) {
479
+ return translate(language, "error.pairingRelayUnreachable", {
480
+ url: pairingRelayUnreachable.groups.url
481
+ });
482
+ }
462
483
  if (message.includes("Pairing requires HermesPilot Server and Relay")) {
463
484
  return [translate(language, "error.pairingRequires"), translate(language, "error.pairingRequires.detail")].join("\n");
464
485
  }
@@ -487,6 +508,7 @@ async function assertPairingPreflightReady(options = {}) {
487
508
  const configPath = resolveHermesConfigPath(profileName);
488
509
  const envPath = path2.join(hermesHome, ".env");
489
510
  const failures = [];
511
+ options.onProgress?.("hermes_files");
490
512
  if (!await isDirectory(hermesHome)) {
491
513
  failures.push({
492
514
  code: "hermes_home_missing",
@@ -517,6 +539,23 @@ async function assertPairingPreflightReady(options = {}) {
517
539
  if (failures.length > 0) {
518
540
  throwPairingPreflightError(failures);
519
541
  }
542
+ options.onProgress?.("hermes_cli");
543
+ let hermesVersion;
544
+ try {
545
+ const readVersion = options.readHermesVersion ?? readHermesVersion;
546
+ hermesVersion = await readVersion();
547
+ } catch {
548
+ throwPairingPreflightError([
549
+ {
550
+ code: "hermes_cli_unavailable",
551
+ zh: "\u6682\u65F6\u627E\u4E0D\u5230\u53EF\u7528\u7684 Hermes CLI \u547D\u4EE4\u3002",
552
+ en: "Hermes CLI is not available right now.",
553
+ 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",
554
+ 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."
555
+ }
556
+ ]);
557
+ }
558
+ options.onProgress?.("hermes_api_server");
520
559
  const apiServerConfig = await readHermesApiServerConfig(profileName, configPath);
521
560
  if (apiServerConfig.enabled !== true) {
522
561
  throwPairingPreflightError([
@@ -548,6 +587,10 @@ async function assertPairingPreflightReady(options = {}) {
548
587
  started: availability.started,
549
588
  host: availability.configResult.apiServer.host ?? null,
550
589
  port: availability.configResult.apiServer.port ?? null
590
+ },
591
+ hermesVersion: {
592
+ raw: hermesVersion.raw,
593
+ version: hermesVersion.version
551
594
  }
552
595
  };
553
596
  } catch (error) {
@@ -780,16 +823,17 @@ program.command("pair").description(helpText("pair.description")).action(async (
780
823
  const language = languageChoice.language;
781
824
  const t = translate.bind(null, language);
782
825
  console.log(t("pair.preflight"));
783
- const preflight = await assertPairingPreflightReady({ paths });
784
826
  const environment = detectRuntimeEnvironment();
785
827
  if (environment.warning) {
786
828
  console.log(t("doctor.networkWarning", { message: environment.warning }));
787
829
  }
788
- console.log(t("pair.hermesHome", { path: preflight.hermesHome }));
789
- console.log(t("pair.apiReady", { port: preflight.apiServer.port ?? "unknown" }));
830
+ await assertPairingPreflightReady({
831
+ paths,
832
+ onProgress: (stage) => {
833
+ console.log(t(pairingPreflightProgressKey(stage)));
834
+ }
835
+ });
790
836
  console.log(t("pair.preparing"));
791
- console.log(t("pair.server", { url: config.serverBaseUrl }));
792
- console.log(t("pair.relay", { url: config.relayBaseUrl }));
793
837
  await ensureIdentity(paths);
794
838
  const hadActiveDevices = await hasActiveDevices(paths);
795
839
  const probeBeforePair = await probeLocalLinkService({ port: config.port });
@@ -806,19 +850,12 @@ program.command("pair").description(helpText("pair.description")).action(async (
806
850
  const service = reusedRunningService ? null : await startLinkService({ paths });
807
851
  const qrValue = JSON.stringify(prepared.qrPayload);
808
852
  const pairingPageUrl = `http://127.0.0.1:${config.port}/pair?session_id=${encodeURIComponent(prepared.sessionId)}`;
809
- console.log(t("pair.linkId", { value: prepared.linkId }));
810
- console.log(t("pair.code", { value: prepared.code }));
811
- console.log(t("pair.localApi", { port: config.port }));
812
- if (!reusedRunningService) {
813
- console.log(t("start.listening", { port: config.port }));
814
- }
815
853
  console.log(t("pair.scan"));
816
- console.log(`Pairing page: ${pairingPageUrl}`);
817
- const browserOpened = await openSystemBrowser(pairingPageUrl);
818
- if (!browserOpened) {
819
- console.log(t("pair.openBrowserFailed", { url: pairingPageUrl }));
820
- }
821
854
  qrcode.generate(qrValue, { small: true });
855
+ await openSystemBrowser(pairingPageUrl);
856
+ console.log(t("pair.openPairingPage", { url: pairingPageUrl }));
857
+ console.log(t("pair.manualCode"));
858
+ console.log(prepared.code);
822
859
  console.log(t("pair.expires"));
823
860
  const result = await waitForPairingOrShutdown(prepared.sessionId, paths);
824
861
  if (service) {
@@ -923,6 +960,12 @@ program.command("doctor").description(helpText("doctor.description")).action(asy
923
960
  console.log(`Hermes config backup: ${hermesConfig.backupPath}`);
924
961
  }
925
962
  }
963
+ try {
964
+ const hermesVersion = await readHermesVersion();
965
+ console.log(t("doctor.hermesCli", { value: formatHermesVersion(hermesVersion) }));
966
+ } catch {
967
+ console.log(t("doctor.hermesCliUnavailable"));
968
+ }
926
969
  try {
927
970
  const availability = await ensureHermesApiServerAvailable({ timeoutMs: 5e3 });
928
971
  console.log(t(availability.started ? "doctor.apiStarted" : "doctor.apiReady"));
@@ -939,6 +982,19 @@ async function loadCliLanguage() {
939
982
  const config = await loadConfig();
940
983
  return resolveLanguage(config.language);
941
984
  }
985
+ function formatHermesVersion(version) {
986
+ return version.version ?? version.raw;
987
+ }
988
+ function pairingPreflightProgressKey(stage) {
989
+ switch (stage) {
990
+ case "hermes_files":
991
+ return "pair.preflight.hermesFiles";
992
+ case "hermes_cli":
993
+ return "pair.preflight.hermesCli";
994
+ case "hermes_api_server":
995
+ return "pair.preflight.hermesApiServer";
996
+ }
997
+ }
942
998
  async function deliverStagedFilesFromCli(stagingDir, paths, config) {
943
999
  try {
944
1000
  return await deliverStagedFilesThroughDaemon(stagingDir, config.port);
package/dist/http/app.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  createApp
3
- } from "../chunk-TZVQZFWU.js";
3
+ } from "../chunk-7OVDWXR7.js";
4
4
  export {
5
5
  createApp
6
6
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hermespilot/link",
3
- "version": "0.3.7",
3
+ "version": "0.3.9",
4
4
  "private": false,
5
5
  "description": "Hermes Link companion service and CLI for connecting hermes-agent through HermesPilot",
6
6
  "license": "MIT",