@hermespilot/link 0.6.3 → 0.6.5

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
@@ -12,6 +12,7 @@ import {
12
12
  daemonLogFile,
13
13
  defaultLinkConfig,
14
14
  detectRuntimeEnvironment,
15
+ detectSystemLanguage,
15
16
  ensureHermesApiServerAvailable,
16
17
  ensureHermesApiServerConfig,
17
18
  ensureHermesLinkSkillInstalledBestEffort,
@@ -25,6 +26,7 @@ import {
25
26
  hasActiveDevices,
26
27
  loadConfig,
27
28
  loadIdentity,
29
+ localizeErrorMessage,
28
30
  normalizeLanHost,
29
31
  parseLogLevel,
30
32
  preparePairing,
@@ -38,13 +40,15 @@ import {
38
40
  reportLinkStatusToServer,
39
41
  resolveHermesConfigPath,
40
42
  resolveHermesProfileDir,
43
+ resolveLanguage,
41
44
  resolveRuntimePaths,
42
45
  runDaemonSupervisor,
43
46
  saveConfig,
44
47
  startDaemonProcess,
45
48
  startLinkService,
46
- stopDaemonProcess
47
- } from "../chunk-PCJGVIKH.js";
49
+ stopDaemonProcess,
50
+ translate
51
+ } from "../chunk-IJOWAEQ4.js";
48
52
 
49
53
  // src/cli/index.ts
50
54
  import { Command } from "commander";
@@ -297,490 +301,6 @@ function cmdEnvironmentLines(environment) {
297
301
  );
298
302
  }
299
303
 
300
- // src/i18n.ts
301
- var messages = {
302
- en: {
303
- "program.description": "Hermes Link companion service",
304
- "program.version": "print Hermes Link version",
305
- "status.description": "Show local Hermes Link status",
306
- "status.json": "print machine-readable status",
307
- "status.runtime": "Runtime: {value}",
308
- "status.mode": "Mode: {value}",
309
- "status.daemon": "Service: {value}",
310
- "status.daemon.runningReachable": "running (PID {pid}, local API reachable)",
311
- "status.daemon.runningUnreachable": "running (PID {pid}, local API is not responding)",
312
- "status.daemon.notRunning": "not running",
313
- "status.port": "Local port: {value}",
314
- "status.lanHost": "LAN access address (manual override): {value}",
315
- "status.notSet": "not set",
316
- "status.unknown": "unknown",
317
- "status.environmentWarning": "Network note: {message}",
318
- "status.linkId": "Link ID: {value}",
319
- "status.notPaired": "not paired",
320
- "status.relay": "Relay: {value}",
321
- "status.relay.notPaired": "not connected (not paired yet; Relay is disabled until pairing)",
322
- "status.relay.notConfigured": "not configured",
323
- "status.relay.serviceStopped": "not connected (background service is not running)",
324
- "status.relay.serviceUnreachable": "unknown (background service is running but local API is not responding)",
325
- "status.relay.unknown": "unknown (background service has not reported Relay state yet)",
326
- "status.relay.state.connecting": "connecting",
327
- "status.relay.state.connected": "connected",
328
- "status.relay.state.disconnected": "disconnected",
329
- "status.relay.state.retrying": "retrying",
330
- "status.relay.state.cooldown": "cooling down",
331
- "status.relay.state.failed": "failed",
332
- "status.relay.stateWithAttempt": "{state}, attempt {attempt}",
333
- "status.relay.updatedAt": "updated {time}",
334
- "status.relay.withMessage": "{state} - {message}",
335
- "status.relay.withUpdatedAt": "{state}; {updatedAt}",
336
- "status.relay.withMessageAndUpdatedAt": "{state} - {message}; {updatedAt}",
337
- "status.recentError": "Latest error: {value}",
338
- "status.recentError.none": "none",
339
- "status.recentError.format": "{time} [{source}] {message}",
340
- "status.logSource.service": "service",
341
- "status.logSource.daemon": "daemon",
342
- "status.logSource.gateway": "gateway",
343
- "status.timeUnknown": "time unknown",
344
- "start.description": "Start Hermes Link daemon",
345
- "start.backgroundStarted": "Hermes Link is running in the background. PID: {pid}",
346
- "start.alreadyRunning": "Hermes Link is already running. PID: {pid}",
347
- "start.notPaired": "Hermes Link is not paired yet. Starting in local-only maintenance mode.",
348
- "start.notPaired.detail": "Relay, Server polling, and LAN entrypoints stay disabled until you run `hermeslink pair`.",
349
- "start.listening": "Hermes Link API listening on http://127.0.0.1:{port}",
350
- "start.relayConnecting": "Relay control connecting for {linkId}",
351
- "stop.description": "Stop the background Hermes Link daemon",
352
- "stop.stopped": "Hermes Link stopped.",
353
- "stop.notRunning": "Hermes Link is not running.",
354
- "restart.description": "Restart the background Hermes Link daemon",
355
- "deliver.description": "Import files from a Hermes Link delivery staging directory",
356
- "deliver.imported": "Delivered {count} file(s) to conversation {conversationId}.",
357
- "deliver.none": "No new files were delivered for conversation {conversationId}.",
358
- "config.description": "Manage local Hermes Link configuration",
359
- "config.set.description": "Set a configuration value",
360
- "config.unset.description": "Unset a configuration value",
361
- "config.unknownKey": "Unknown config key: {key}",
362
- "config.lanHostInvalid": "lan-host must be a private LAN IPv4 address, such as 192.168.1.23.",
363
- "config.lanHostSet": "LAN access address override set: {value}",
364
- "config.lanHostUnset": "LAN access address override cleared.",
365
- "config.logLevelInvalid": "log-level must be one of: debug, info, warn, error.",
366
- "config.logLevelSet": "Configured log level: {value}",
367
- "config.logLevelRestartRequired": "The running daemon keeps its current logger until restart. Run `hermeslink restart` to apply this write level immediately.",
368
- "config.logLevelUnset": "Configured log level reset to the default: {value}.",
369
- "config.reported": "Updated HermesPilot Server with the latest LAN address.",
370
- "config.reportSkippedUnpaired": "Hermes Link is not paired yet. The LAN address will be reported after pairing.",
371
- "daemon.description": "Run Hermes Link in the foreground",
372
- "daemon.foreground": "Hermes Link foreground daemon is running. Press Ctrl+C to stop.",
373
- "logs.description": "Show or follow Hermes Link logs",
374
- "logs.follow": "follow log output",
375
- "logs.tail": "print the last N lines before exiting or following",
376
- "logs.serviceOnly": "only read the service JSONL log",
377
- "logs.daemonOnly": "only read the daemon stdout/stderr log",
378
- "logs.gatewayOnly": "only read Hermes Gateway logs",
379
- "logs.all": "read service, daemon, and Gateway logs",
380
- "logs.level": "minimum level to display: debug, info, warn, or error",
381
- "logs.debugLevel": "show debug and above",
382
- "logs.infoLevel": "show info and above",
383
- "logs.warnLevel": "show warn and above",
384
- "logs.errorLevel": "show errors only",
385
- "logs.servicePath": "Service log: {path}",
386
- "logs.daemonPath": "Daemon stdout/stderr log: {path}",
387
- "logs.gatewayPath": "Gateway log: {path}",
388
- "logs.followHint": "Use `hermeslink logs -f` to follow logs, or `hermeslink logs -n 100` to print recent lines.",
389
- "logs.following": "Following logs. Press Ctrl+C to stop.",
390
- "logs.flush.description": "Clear Hermes Link log files",
391
- "logs.flush.all": "clear service, daemon, and Gateway logs",
392
- "logs.flush.flushed": "Cleared {truncated} active log file(s) and removed {removed} rotated log file(s).",
393
- "autostart.description": "Manage boot autostart",
394
- "autostart.on.description": "Enable boot autostart",
395
- "autostart.off.description": "Disable boot autostart",
396
- "autostart.status.description": "Show boot autostart status",
397
- "autostart.enabled": "Boot autostart enabled via {method}: {path}",
398
- "autostart.disabled": "Boot autostart disabled.",
399
- "autostart.status.enabled": "Boot autostart: enabled via {method}: {path}",
400
- "autostart.status.disabled": "Boot autostart: disabled. Method: {method}. File: {path}",
401
- "autostart.unsupported": "Boot autostart is not supported on this platform yet.",
402
- "autostart.alreadyEnabled": "Boot autostart is already enabled via {method}: {path}",
403
- "pair.description": "Create a Hermes Link pairing session",
404
- "pair.preflight": "Checking local Hermes configuration before pairing...",
405
- "pair.preflight.hermesFiles": "Checking Hermes data directory, config, and environment files...",
406
- "pair.preflight.hermesCli": "Checking whether the Hermes CLI is available...",
407
- "pair.preflight.hermesApiServer": "Checking whether the Hermes API Server is ready...",
408
- "pair.hermesHome": "Hermes home: {path}",
409
- "pair.hermesVersion": "Hermes CLI: {value}",
410
- "pair.apiReady": "Hermes API Server is ready on 127.0.0.1:{port}",
411
- "pair.preparing": "Creating the pairing session...",
412
- "pair.scan": "Please scan the QR code below in the HermesPilot App:",
413
- "pair.openPairingPage": "If the QR code is hard to scan, you can open this page locally: {url}",
414
- "pair.manualCode": "You can also use the HermesPilot App manual connection mode and enter this pairing code:",
415
- "pair.expires": "Pairing expires in 10 minutes. Press Ctrl+C to cancel waiting.",
416
- "pair.expired": "Pairing expired. Please run `hermeslink pair` again.",
417
- "pair.claimed": "Pairing succeeded. Starting Hermes Link in the background...",
418
- "pair.claimedRunning": "Pairing succeeded. Hermes Link is already running in the background.",
419
- "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.",
420
- "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.",
421
- "pair.relayOnlySafetyHint": "Hermes Link will not automatically change Windows/WSL bridge, firewall, or portproxy settings because those are system-level network exposure choices.",
422
- "pair.autostartUnchanged": "Existing paired devices found. Boot autostart settings were left unchanged.",
423
- "pair.autostartFailed": "Pairing succeeded, but boot autostart could not be enabled: {message}",
424
- "doctor.description": "Run local diagnostics",
425
- "doctor.installOnly": "only check npm global command and PATH setup",
426
- "doctor.installHeader": "Install/PATH diagnostics:",
427
- "doctor.installNpmPrefix": "npm global prefix: {value}",
428
- "doctor.installGlobalBin": "npm global bin directory: {value}",
429
- "doctor.installExpectedCommand": "expected hermeslink command: {value} ({state})",
430
- "doctor.installCommandOnPath": "hermeslink found on PATH: {value}",
431
- "doctor.installUnknown": "unknown",
432
- "doctor.installOk": "ok",
433
- "doctor.installMissing": "missing",
434
- "doctor.installReady": "The global hermeslink command is visible to this shell.",
435
- "doctor.installPrefixUnavailable": "Could not read npm global prefix with `{command} prefix -g`. Check that npm is available in this shell.",
436
- "doctor.installExpectedMissing": "npm does not appear to have created the global hermeslink shim. Re-run `npm install -g @hermespilot/link` in the same system environment where Hermes runs.",
437
- "doctor.installPathMissing": "npm installed hermeslink, but this shell cannot see npm's global bin directory on PATH.",
438
- "doctor.installShadowed": "A different hermeslink command appears earlier on PATH. Remove the old command or move npm's global bin directory earlier on PATH.",
439
- "doctor.installWslWindowsNpm": "This looks like Windows Node/npm being used from WSL (`/mnt/c/...`). Prefer installing Linux Node.js inside WSL, or run both Hermes Agent and Hermes Link on the Windows host.",
440
- "doctor.installDirectRun": "Direct run without changing PATH: {command}",
441
- "doctor.installUnixPathHint": 'Temporary PATH fix: export PATH="{path}:$PATH"',
442
- "doctor.installWindowsPathHint": "Add this directory to your user Path, then open a new terminal: {path}",
443
- "doctor.installNpxFallback": "PATH-independent fallback: npx --yes @hermespilot/link doctor --install",
444
- "doctor.identityOk": "Runtime identity: OK",
445
- "doctor.installId": "Install ID: {value}",
446
- "doctor.linkId": "Link ID: {value}",
447
- "doctor.notAssigned": "not assigned",
448
- "doctor.lanHost": "LAN access address (manual override): {value}",
449
- "doctor.networkWarning": "Network note: {message}",
450
- "doctor.hermesCli": "Hermes CLI: {value}",
451
- "doctor.hermesCliUnavailable": "Hermes CLI is unavailable. Please make sure the `hermes` command can run in this system.",
452
- "doctor.apiReady": "Hermes API Server: ready",
453
- "doctor.apiStarted": "Hermes API Server: started and ready",
454
- "doctor.apiUnavailable": "Hermes API Server: unavailable. {message}",
455
- "doctor.apiUnavailable.summary": "Hermes API Server: unavailable",
456
- "doctor.apiUnavailable.profile": "Profile: {profile}; port: {port}",
457
- "doctor.apiUnavailable.diagnosisDivider": "----- API Server diagnosis -----",
458
- "doctor.apiUnavailable.check": "Check: {check}",
459
- "doctor.apiUnavailable.result": "Result: {result}",
460
- "doctor.apiUnavailable.startAttempt": "Link tried to start it with: {command}",
461
- "doctor.apiUnavailable.startSkipped": "Auto-start was skipped; Link only checked the existing server.",
462
- "doctor.apiUnavailable.recentLog": "Recent Gateway log: {message}",
463
- "doctor.apiUnavailable.gatewayLog": "Gateway log: {path}",
464
- "doctor.apiUnavailable.fix.port": "Suggestion: check whether another process is using port {port}, or run `hermes gateway run --replace` to view the Hermes startup error directly.",
465
- "doctor.apiUnavailable.fix.auth": "Suggestion: check API_SERVER_KEY in the current Profile .env/config.yaml, or make sure this port belongs to the same Hermes Profile.",
466
- "doctor.apiUnavailable.fix.notHermes": "Suggestion: change the Hermes API Server port or stop the non-Hermes service using this port.",
467
- "doctor.apiUnavailable.fix.models": "Suggestion: the health endpoint responds, but the model API does not. Check Hermes provider/model configuration and Gateway logs.",
468
- "doctor.apiUnavailable.fix.gateway": "Suggestion: start Hermes Gateway with `hermes gateway run --replace` and check the printed Hermes error.",
469
- "doctor.apiCheck.notHermes": "Read the Hermes health response from {probe}.",
470
- "doctor.apiCheck.authInvalid": "Call {probe} with the configured API key.",
471
- "doctor.apiCheck.modelsTimeout": "Call {probe} to verify the API key and model API.",
472
- "doctor.apiCheck.modelsHttp": "Call {probe} to verify the API key and model API.",
473
- "doctor.apiCheck.port": "Connect to the Hermes health endpoints: {probe}.",
474
- "doctor.apiCheck.gatewayState": "Read gateway_state from /health/detailed.",
475
- "doctor.apiCheck.apiServerState": "Read platforms.api_server.state from /health/detailed.",
476
- "doctor.apiCheck.exitReason": "Read exit_reason from /health/detailed.",
477
- "doctor.apiCheck.unknown": "Run the Hermes API Server health checks.",
478
- "doctor.apiIssue.notHermes": "The configured port returned a non-Hermes health response. Another local service may be using this port.",
479
- "doctor.apiIssue.authInvalid": "The API key was rejected (HTTP 401). The key in Profile .env/config.yaml may be stale, or this port may belong to another Profile.",
480
- "doctor.apiIssue.modelsTimeout": "/v1/models did not respond before the timeout.",
481
- "doctor.apiIssue.modelsHttp": "/v1/models returned HTTP {status}.",
482
- "doctor.apiIssue.port": "Port {port} did not respond.",
483
- "doctor.apiIssue.gatewayState": "Gateway state is {state}.",
484
- "doctor.apiIssue.apiServerState": "API Server state is {state}{detail}.",
485
- "doctor.apiIssue.exitReason": "Gateway exit reason: {detail}.",
486
- "doctor.apiIssue.unknown": "{message}",
487
- "error.relayPublicKeyMismatch": "Relay rejected the pairing request because the Server-issued bootstrap token does not match this Link public key. Make sure Server and Relay are deployed with the same bootstrap key configuration, then run `hermeslink pair` again.",
488
- "error.relayChallengeInvalid": "Relay did not return a valid install challenge.",
489
- "error.relayLinkInvalid": "Relay did not return a valid link_id.",
490
- "error.relayEmpty": "Relay returned an empty response.",
491
- "error.serverHttp": "HermesPilot Server request failed with HTTP {status}.",
492
- "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.",
493
- "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.",
494
- "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.",
495
- "error.pairingRequires": "Pairing needs HermesPilot Server and Relay, but this command could not start a complete pairing session.",
496
- "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."
497
- },
498
- "zh-CN": {
499
- "program.description": "Hermes Link \u672C\u5730\u4F34\u968F\u670D\u52A1",
500
- "program.version": "\u8F93\u51FA Hermes Link \u7248\u672C\u53F7",
501
- "status.description": "\u67E5\u770B\u672C\u673A Hermes Link \u72B6\u6001",
502
- "status.json": "\u8F93\u51FA\u673A\u5668\u53EF\u8BFB\u7684\u72B6\u6001 JSON",
503
- "status.runtime": "\u8FD0\u884C\u76EE\u5F55\uFF1A{value}",
504
- "status.mode": "\u6A21\u5F0F\uFF1A{value}",
505
- "status.daemon": "\u540E\u53F0\u670D\u52A1\uFF1A{value}",
506
- "status.daemon.runningReachable": "\u8FD0\u884C\u4E2D\uFF08PID\uFF1A{pid}\uFF0C\u672C\u5730 API \u53EF\u8BBF\u95EE\uFF09",
507
- "status.daemon.runningUnreachable": "\u8FD0\u884C\u4E2D\uFF08PID\uFF1A{pid}\uFF0C\u4F46\u672C\u5730 API \u6682\u4E0D\u53EF\u8BBF\u95EE\uFF09",
508
- "status.daemon.notRunning": "\u672A\u8FD0\u884C",
509
- "status.port": "\u672C\u5730\u7AEF\u53E3\uFF1A{value}",
510
- "status.lanHost": "\u5C40\u57DF\u7F51\u8BBF\u95EE\u5730\u5740\uFF08\u624B\u52A8\u6307\u5B9A\uFF09\uFF1A{value}",
511
- "status.notSet": "\u672A\u8BBE\u7F6E",
512
- "status.unknown": "\u672A\u77E5",
513
- "status.environmentWarning": "\u7F51\u7EDC\u63D0\u793A\uFF1A{message}",
514
- "status.linkId": "Link ID\uFF1A{value}",
515
- "status.notPaired": "\u5C1A\u672A\u914D\u5BF9",
516
- "status.relay": "Relay\uFF1A{value}",
517
- "status.relay.notPaired": "\u672A\u8FDE\u63A5\uFF08\u5C1A\u672A\u914D\u5BF9\uFF0CRelay \u4F1A\u4FDD\u6301\u5173\u95ED\uFF09",
518
- "status.relay.notConfigured": "\u672A\u914D\u7F6E",
519
- "status.relay.serviceStopped": "\u672A\u8FDE\u63A5\uFF08\u540E\u53F0\u670D\u52A1\u672A\u8FD0\u884C\uFF09",
520
- "status.relay.serviceUnreachable": "\u672A\u77E5\uFF08\u540E\u53F0\u670D\u52A1\u6B63\u5728\u8FD0\u884C\uFF0C\u4F46\u672C\u5730 API \u6682\u4E0D\u53EF\u8BBF\u95EE\uFF09",
521
- "status.relay.unknown": "\u672A\u77E5\uFF08\u540E\u53F0\u670D\u52A1\u8FD8\u6CA1\u6709\u4E0A\u62A5 Relay \u72B6\u6001\uFF09",
522
- "status.relay.state.connecting": "\u8FDE\u63A5\u4E2D",
523
- "status.relay.state.connected": "\u5DF2\u8FDE\u63A5",
524
- "status.relay.state.disconnected": "\u672A\u8FDE\u63A5",
525
- "status.relay.state.retrying": "\u91CD\u8BD5\u4E2D",
526
- "status.relay.state.cooldown": "\u51B7\u5374\u4E2D",
527
- "status.relay.state.failed": "\u8FDE\u63A5\u5931\u8D25",
528
- "status.relay.stateWithAttempt": "{state}\uFF08\u7B2C {attempt} \u6B21\uFF09",
529
- "status.relay.updatedAt": "\u66F4\u65B0\u4E8E {time}",
530
- "status.relay.withMessage": "{state} - {message}",
531
- "status.relay.withUpdatedAt": "{state}\uFF1B{updatedAt}",
532
- "status.relay.withMessageAndUpdatedAt": "{state} - {message}\uFF1B{updatedAt}",
533
- "status.recentError": "\u6700\u8FD1\u9519\u8BEF\uFF1A{value}",
534
- "status.recentError.none": "\u65E0",
535
- "status.recentError.format": "{time} [{source}] {message}",
536
- "status.logSource.service": "\u670D\u52A1",
537
- "status.logSource.daemon": "\u5B88\u62A4\u8FDB\u7A0B",
538
- "status.logSource.gateway": "Gateway",
539
- "status.timeUnknown": "\u65F6\u95F4\u672A\u77E5",
540
- "start.description": "\u542F\u52A8 Hermes Link \u670D\u52A1",
541
- "start.backgroundStarted": "Hermes Link \u5DF2\u5728\u540E\u53F0\u8FD0\u884C\u3002PID\uFF1A{pid}",
542
- "start.alreadyRunning": "Hermes Link \u5DF2\u7ECF\u5728\u8FD0\u884C\u3002PID\uFF1A{pid}",
543
- "start.notPaired": "Hermes Link \u8FD8\u6CA1\u6709\u914D\u5BF9\uFF0C\u5C06\u4EE5\u672C\u5730\u7EF4\u62A4\u6A21\u5F0F\u542F\u52A8\u3002",
544
- "start.notPaired.detail": "\u5728\u4F60\u8FD0\u884C `hermeslink pair` \u524D\uFF0CRelay\u3001Server \u8F6E\u8BE2\u548C\u5C40\u57DF\u7F51\u5165\u53E3\u90FD\u4F1A\u4FDD\u6301\u5173\u95ED\u3002",
545
- "start.listening": "Hermes Link API \u6B63\u5728\u76D1\u542C http://127.0.0.1:{port}",
546
- "start.relayConnecting": "\u6B63\u5728\u4E3A {linkId} \u8FDE\u63A5 Relay \u63A7\u5236\u901A\u9053",
547
- "stop.description": "\u505C\u6B62\u540E\u53F0 Hermes Link \u670D\u52A1",
548
- "stop.stopped": "Hermes Link \u5DF2\u505C\u6B62\u3002",
549
- "stop.notRunning": "Hermes Link \u6CA1\u6709\u5728\u8FD0\u884C\u3002",
550
- "restart.description": "\u91CD\u542F\u540E\u53F0 Hermes Link \u670D\u52A1",
551
- "deliver.description": "\u5BFC\u5165 Hermes Link \u4EA4\u4ED8\u4E2D\u8F6C\u76EE\u5F55\u4E2D\u7684\u6587\u4EF6",
552
- "deliver.imported": "\u5DF2\u5411\u4F1A\u8BDD {conversationId} \u4EA4\u4ED8 {count} \u4E2A\u6587\u4EF6\u3002",
553
- "deliver.none": "\u4F1A\u8BDD {conversationId} \u6CA1\u6709\u65B0\u7684\u53EF\u4EA4\u4ED8\u6587\u4EF6\u3002",
554
- "config.description": "\u7BA1\u7406\u672C\u673A Hermes Link \u914D\u7F6E",
555
- "config.set.description": "\u8BBE\u7F6E\u914D\u7F6E\u9879",
556
- "config.unset.description": "\u6E05\u9664\u914D\u7F6E\u9879",
557
- "config.unknownKey": "\u672A\u77E5\u914D\u7F6E\u9879\uFF1A{key}",
558
- "config.lanHostInvalid": "lan-host \u5FC5\u987B\u662F\u5C40\u57DF\u7F51 IPv4 \u5730\u5740\uFF0C\u4F8B\u5982 192.168.1.23\u3002",
559
- "config.lanHostSet": "\u5DF2\u8BBE\u7F6E\u5C40\u57DF\u7F51\u8BBF\u95EE\u5730\u5740\uFF08\u624B\u52A8\u6307\u5B9A\uFF09\uFF1A{value}",
560
- "config.lanHostUnset": "\u5DF2\u6E05\u9664\u5C40\u57DF\u7F51\u8BBF\u95EE\u5730\u5740\u624B\u52A8\u914D\u7F6E\u3002",
561
- "config.logLevelInvalid": "log-level \u53EA\u80FD\u662F\u4EE5\u4E0B\u503C\u4E4B\u4E00\uFF1Adebug\u3001info\u3001warn\u3001error\u3002",
562
- "config.logLevelSet": "\u5DF2\u914D\u7F6E\u65E5\u5FD7\u7EA7\u522B\uFF1A{value}",
563
- "config.logLevelRestartRequired": "\u6B63\u5728\u8FD0\u884C\u7684 daemon \u4F1A\u7EE7\u7EED\u4F7F\u7528\u542F\u52A8\u65F6\u7684\u65E5\u5FD7\u5199\u5165\u7EA7\u522B\u3002\u8FD0\u884C `hermeslink restart` \u53EF\u7ACB\u5373\u5E94\u7528\u65B0\u7684\u5199\u5165\u7EA7\u522B\u3002",
564
- "config.logLevelUnset": "\u5DF2\u5C06\u65E5\u5FD7\u7EA7\u522B\u6062\u590D\u4E3A\u9ED8\u8BA4\u503C\uFF1A{value}\u3002",
565
- "config.reported": "\u5DF2\u628A\u6700\u65B0\u5C40\u57DF\u7F51\u5730\u5740\u66F4\u65B0\u5230 HermesPilot Server\u3002",
566
- "config.reportSkippedUnpaired": "Hermes Link \u8FD8\u6CA1\u6709\u914D\u5BF9\uFF0C\u5C40\u57DF\u7F51\u5730\u5740\u4F1A\u5728\u914D\u5BF9\u540E\u4E0A\u62A5\u3002",
567
- "daemon.description": "\u4EE5\u524D\u53F0\u65B9\u5F0F\u8FD0\u884C Hermes Link",
568
- "daemon.foreground": "Hermes Link \u524D\u53F0\u670D\u52A1\u6B63\u5728\u8FD0\u884C\u3002\u6309 Ctrl+C \u505C\u6B62\u3002",
569
- "logs.description": "\u663E\u793A\u6216\u8DDF\u8E2A Hermes Link \u65E5\u5FD7",
570
- "logs.follow": "\u6301\u7EED\u8DDF\u8E2A\u65E5\u5FD7\u8F93\u51FA",
571
- "logs.tail": "\u9000\u51FA\u6216\u6301\u7EED\u8DDF\u8E2A\u524D\u5148\u8F93\u51FA\u6700\u8FD1 N \u884C",
572
- "logs.serviceOnly": "\u53EA\u8BFB\u53D6\u670D\u52A1 JSONL \u65E5\u5FD7",
573
- "logs.daemonOnly": "\u53EA\u8BFB\u53D6 Daemon \u6807\u51C6\u8F93\u51FA/\u9519\u8BEF\u65E5\u5FD7",
574
- "logs.gatewayOnly": "\u53EA\u8BFB\u53D6 Hermes Gateway \u65E5\u5FD7",
575
- "logs.all": "\u8BFB\u53D6\u670D\u52A1\u3001Daemon \u4E0E Gateway \u65E5\u5FD7",
576
- "logs.level": "\u6700\u4F4E\u663E\u793A\u7EA7\u522B\uFF1Adebug\u3001info\u3001warn \u6216 error",
577
- "logs.debugLevel": "\u663E\u793A debug \u53CA\u4EE5\u4E0A\u7EA7\u522B",
578
- "logs.infoLevel": "\u663E\u793A info \u53CA\u4EE5\u4E0A\u7EA7\u522B",
579
- "logs.warnLevel": "\u663E\u793A warn \u53CA\u4EE5\u4E0A\u7EA7\u522B",
580
- "logs.errorLevel": "\u53EA\u663E\u793A error \u7EA7\u522B",
581
- "logs.servicePath": "\u670D\u52A1\u65E5\u5FD7\uFF1A{path}",
582
- "logs.daemonPath": "Daemon \u6807\u51C6\u8F93\u51FA/\u9519\u8BEF\u65E5\u5FD7\uFF1A{path}",
583
- "logs.gatewayPath": "Gateway \u65E5\u5FD7\uFF1A{path}",
584
- "logs.followHint": "\u4F7F\u7528 `hermeslink logs -f` \u6301\u7EED\u8DDF\u8E2A\u65E5\u5FD7\uFF0C\u6216 `hermeslink logs -n 100` \u8F93\u51FA\u6700\u8FD1\u65E5\u5FD7\u3002",
585
- "logs.following": "\u6B63\u5728\u6301\u7EED\u8DDF\u8E2A\u65E5\u5FD7\u3002\u6309 Ctrl+C \u505C\u6B62\u3002",
586
- "logs.flush.description": "\u6E05\u7A7A Hermes Link \u65E5\u5FD7\u6587\u4EF6",
587
- "logs.flush.all": "\u6E05\u7A7A\u670D\u52A1\u3001Daemon \u4E0E Gateway \u65E5\u5FD7",
588
- "logs.flush.flushed": "\u5DF2\u6E05\u7A7A {truncated} \u4E2A\u5F53\u524D\u65E5\u5FD7\u6587\u4EF6\uFF0C\u5E76\u5220\u9664 {removed} \u4E2A\u8F6E\u8F6C\u65E5\u5FD7\u6587\u4EF6\u3002",
589
- "autostart.description": "\u7BA1\u7406\u5F00\u673A\u81EA\u542F",
590
- "autostart.on.description": "\u542F\u7528\u5F00\u673A\u81EA\u542F",
591
- "autostart.off.description": "\u5173\u95ED\u5F00\u673A\u81EA\u542F",
592
- "autostart.status.description": "\u67E5\u770B\u5F00\u673A\u81EA\u542F\u72B6\u6001",
593
- "autostart.enabled": "\u5DF2\u542F\u7528\u5F00\u673A\u81EA\u542F\uFF0C\u65B9\u5F0F\uFF1A{method}\uFF0C\u6587\u4EF6\uFF1A{path}",
594
- "autostart.disabled": "\u5DF2\u5173\u95ED\u5F00\u673A\u81EA\u542F\u3002",
595
- "autostart.status.enabled": "\u5F00\u673A\u81EA\u542F\uFF1A\u5DF2\u542F\u7528\uFF0C\u65B9\u5F0F\uFF1A{method}\uFF0C\u6587\u4EF6\uFF1A{path}",
596
- "autostart.status.disabled": "\u5F00\u673A\u81EA\u542F\uFF1A\u672A\u542F\u7528\u3002\u65B9\u5F0F\uFF1A{method}\uFF0C\u6587\u4EF6\uFF1A{path}",
597
- "autostart.unsupported": "\u5F53\u524D\u5E73\u53F0\u6682\u4E0D\u652F\u6301\u5F00\u673A\u81EA\u542F\u3002",
598
- "autostart.alreadyEnabled": "\u5F00\u673A\u81EA\u542F\u5DF2\u542F\u7528\uFF0C\u65B9\u5F0F\uFF1A{method}\uFF0C\u6587\u4EF6\uFF1A{path}",
599
- "pair.description": "\u521B\u5EFA Hermes Link \u914D\u5BF9\u4F1A\u8BDD",
600
- "pair.preflight": "\u6B63\u5728\u914D\u5BF9\u524D\u68C0\u67E5\u672C\u673A Hermes \u914D\u7F6E...",
601
- "pair.preflight.hermesFiles": "\u6B63\u5728\u68C0\u67E5 Hermes \u6570\u636E\u76EE\u5F55\u3001\u914D\u7F6E\u6587\u4EF6\u548C\u73AF\u5883\u6587\u4EF6...",
602
- "pair.preflight.hermesCli": "\u6B63\u5728\u68C0\u67E5 Hermes CLI \u662F\u5426\u53EF\u7528...",
603
- "pair.preflight.hermesApiServer": "\u6B63\u5728\u68C0\u67E5 Hermes API Server \u662F\u5426\u5C31\u7EEA...",
604
- "pair.hermesHome": "Hermes \u6570\u636E\u76EE\u5F55\uFF1A{path}",
605
- "pair.hermesVersion": "Hermes CLI\uFF1A{value}",
606
- "pair.apiReady": "Hermes API Server \u5DF2\u5C31\u7EEA\uFF1A127.0.0.1:{port}",
607
- "pair.preparing": "\u6B63\u5728\u521B\u5EFA\u914D\u5BF9\u4F1A\u8BDD...",
608
- "pair.scan": "\u8BF7\u5728 HermesPilot App \u4E2D\u626B\u7801\u4E0B\u9762\u7684\u4E8C\u7EF4\u7801\uFF1A",
609
- "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}",
610
- "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",
611
- "pair.expires": "\u914D\u5BF9\u4F1A\u8BDD 10 \u5206\u949F\u540E\u8FC7\u671F\u3002\u6309 Ctrl+C \u9000\u51FA\u7B49\u5F85\u3002",
612
- "pair.expired": "\u914D\u5BF9\u4F1A\u8BDD\u5DF2\u8FC7\u671F\uFF0C\u8BF7\u91CD\u65B0\u8FD0\u884C `hermeslink pair`\u3002",
613
- "pair.claimed": "\u914D\u5BF9\u5DF2\u6210\u529F\u3002\u6B63\u5728\u628A Hermes Link \u5207\u6362\u5230\u540E\u53F0\u8FD0\u884C...",
614
- "pair.claimedRunning": "\u914D\u5BF9\u5DF2\u6210\u529F\u3002Hermes Link \u5DF2\u5728\u540E\u53F0\u6301\u7EED\u8FD0\u884C\u3002",
615
- "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",
616
- "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",
617
- "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",
618
- "pair.autostartUnchanged": "\u68C0\u6D4B\u5230\u5DF2\u6709\u914D\u5BF9\u8BBE\u5907\uFF0C\u5F00\u673A\u81EA\u542F\u8BBE\u7F6E\u4FDD\u6301\u4E0D\u53D8\u3002",
619
- "pair.autostartFailed": "\u914D\u5BF9\u5DF2\u6210\u529F\uFF0C\u4F46\u542F\u7528\u5F00\u673A\u81EA\u542F\u5931\u8D25\uFF1A{message}",
620
- "doctor.description": "\u8FD0\u884C\u672C\u673A\u8BCA\u65AD",
621
- "doctor.installOnly": "\u53EA\u68C0\u67E5 npm \u5168\u5C40\u547D\u4EE4\u548C PATH \u8BBE\u7F6E",
622
- "doctor.installHeader": "\u5B89\u88C5 / PATH \u8BCA\u65AD\uFF1A",
623
- "doctor.installNpmPrefix": "npm \u5168\u5C40 prefix\uFF1A{value}",
624
- "doctor.installGlobalBin": "npm \u5168\u5C40 bin \u76EE\u5F55\uFF1A{value}",
625
- "doctor.installExpectedCommand": "\u9884\u671F\u7684 hermeslink \u547D\u4EE4\uFF1A{value}\uFF08{state}\uFF09",
626
- "doctor.installCommandOnPath": "\u5F53\u524D PATH \u627E\u5230\u7684 hermeslink\uFF1A{value}",
627
- "doctor.installUnknown": "\u672A\u77E5",
628
- "doctor.installOk": "\u5B58\u5728",
629
- "doctor.installMissing": "\u672A\u627E\u5230",
630
- "doctor.installReady": "\u5F53\u524D shell \u53EF\u4EE5\u76F4\u63A5\u627E\u5230\u5168\u5C40 hermeslink \u547D\u4EE4\u3002",
631
- "doctor.installPrefixUnavailable": "\u65E0\u6CD5\u901A\u8FC7 `{command} prefix -g` \u8BFB\u53D6 npm \u5168\u5C40 prefix\u3002\u8BF7\u5148\u786E\u8BA4\u5F53\u524D shell \u80FD\u8FD0\u884C npm\u3002",
632
- "doctor.installExpectedMissing": "npm \u4F3C\u4E4E\u6CA1\u6709\u521B\u5EFA\u5168\u5C40 hermeslink shim\u3002\u8BF7\u5728 Hermes \u6240\u5728\u7684\u540C\u4E00\u7CFB\u7EDF\u73AF\u5883\u91CC\u91CD\u65B0\u6267\u884C `npm install -g @hermespilot/link`\u3002",
633
- "doctor.installPathMissing": "npm \u5DF2\u5B89\u88C5 hermeslink\uFF0C\u4F46\u5F53\u524D shell \u7684 PATH \u91CC\u6CA1\u6709 npm \u5168\u5C40 bin \u76EE\u5F55\u3002",
634
- "doctor.installShadowed": "PATH \u524D\u9762\u5B58\u5728\u53E6\u4E00\u4E2A hermeslink \u547D\u4EE4\u3002\u8BF7\u5220\u9664\u65E7\u547D\u4EE4\uFF0C\u6216\u628A npm \u5168\u5C40 bin \u76EE\u5F55\u653E\u5230 PATH \u66F4\u524D\u9762\u3002",
635
- "doctor.installWslWindowsNpm": "\u5F53\u524D\u770B\u8D77\u6765\u662F\u5728 WSL \u4E2D\u8C03\u7528\u4E86 Windows Node/npm\uFF08`/mnt/c/...`\uFF09\u3002\u5EFA\u8BAE\u5728 WSL \u5185\u5B89\u88C5 Linux \u7248 Node.js\uFF0C\u6216\u628A Hermes Agent \u4E0E Hermes Link \u90FD\u653E\u5728 Windows \u5BBF\u4E3B\u673A\u8FD0\u884C\u3002",
636
- "doctor.installDirectRun": "\u4E0D\u6539 PATH \u4E5F\u53EF\u4EE5\u76F4\u63A5\u8FD0\u884C\uFF1A{command}",
637
- "doctor.installUnixPathHint": '\u4E34\u65F6\u8865 PATH\uFF1Aexport PATH="{path}:$PATH"',
638
- "doctor.installWindowsPathHint": "\u628A\u8FD9\u4E2A\u76EE\u5F55\u52A0\u5165\u5F53\u524D\u7528\u6237\u7684 Path\uFF0C\u7136\u540E\u91CD\u65B0\u6253\u5F00\u7EC8\u7AEF\uFF1A{path}",
639
- "doctor.installNpxFallback": "\u4E0D\u4F9D\u8D56 PATH \u7684\u515C\u5E95\u547D\u4EE4\uFF1Anpx --yes @hermespilot/link doctor --install",
640
- "doctor.identityOk": "\u8FD0\u884C\u8EAB\u4EFD\uFF1A\u6B63\u5E38",
641
- "doctor.installId": "Install ID\uFF1A{value}",
642
- "doctor.linkId": "Link ID\uFF1A{value}",
643
- "doctor.notAssigned": "\u5C1A\u672A\u5206\u914D",
644
- "doctor.lanHost": "\u5C40\u57DF\u7F51\u8BBF\u95EE\u5730\u5740\uFF08\u624B\u52A8\u6307\u5B9A\uFF09\uFF1A{value}",
645
- "doctor.networkWarning": "\u7F51\u7EDC\u63D0\u793A\uFF1A{message}",
646
- "doctor.hermesCli": "Hermes CLI\uFF1A{value}",
647
- "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",
648
- "doctor.apiReady": "Hermes API Server\uFF1A\u5DF2\u5C31\u7EEA",
649
- "doctor.apiStarted": "Hermes API Server\uFF1A\u5DF2\u81EA\u52A8\u542F\u52A8\u5E76\u5C31\u7EEA",
650
- "doctor.apiUnavailable": "Hermes API Server\uFF1A\u4E0D\u53EF\u7528\u3002{message}",
651
- "doctor.apiUnavailable.summary": "Hermes API Server\uFF1A\u4E0D\u53EF\u7528",
652
- "doctor.apiUnavailable.profile": "Profile\uFF1A{profile}\uFF1B\u7AEF\u53E3\uFF1A{port}",
653
- "doctor.apiUnavailable.diagnosisDivider": "----- API Server \u8BCA\u65AD -----",
654
- "doctor.apiUnavailable.check": "\u68C0\u6D4B\u73AF\u8282\uFF1A{check}",
655
- "doctor.apiUnavailable.result": "\u68C0\u6D4B\u7ED3\u679C\uFF1A{result}",
656
- "doctor.apiUnavailable.startAttempt": "Link \u5DF2\u5C1D\u8BD5\u542F\u52A8\uFF1A{command}",
657
- "doctor.apiUnavailable.startSkipped": "\u5DF2\u8DF3\u8FC7\u81EA\u52A8\u542F\u52A8\uFF1BLink \u53EA\u68C0\u67E5\u4E86\u5F53\u524D\u5DF2\u6709\u7684 API Server\u3002",
658
- "doctor.apiUnavailable.recentLog": "\u6700\u8FD1 Gateway \u65E5\u5FD7\uFF1A{message}",
659
- "doctor.apiUnavailable.gatewayLog": "Gateway \u65E5\u5FD7\uFF1A{path}",
660
- "doctor.apiUnavailable.fix.port": "\u5EFA\u8BAE\uFF1A\u786E\u8BA4\u7AEF\u53E3 {port} \u662F\u5426\u88AB\u5176\u4ED6\u8FDB\u7A0B\u5360\u7528\uFF0C\u6216\u76F4\u63A5\u8FD0\u884C `hermes gateway run --replace` \u67E5\u770B Hermes \u539F\u59CB\u542F\u52A8\u9519\u8BEF\u3002",
661
- "doctor.apiUnavailable.fix.auth": "\u5EFA\u8BAE\uFF1A\u68C0\u67E5\u5F53\u524D Profile \u7684 .env/config.yaml \u4E2D API_SERVER_KEY \u662F\u5426\u4E00\u81F4\uFF0C\u6216\u786E\u8BA4\u8FD9\u4E2A\u7AEF\u53E3\u5C5E\u4E8E\u540C\u4E00\u4E2A Hermes Profile\u3002",
662
- "doctor.apiUnavailable.fix.notHermes": "\u5EFA\u8BAE\uFF1A\u8C03\u6574 Hermes API Server \u7AEF\u53E3\uFF0C\u6216\u505C\u6B62\u5360\u7528\u8BE5\u7AEF\u53E3\u7684\u975E Hermes \u670D\u52A1\u3002",
663
- "doctor.apiUnavailable.fix.models": "\u5EFA\u8BAE\uFF1A\u5065\u5EB7\u63A5\u53E3\u5DF2\u6709\u54CD\u5E94\uFF0C\u4F46\u6A21\u578B\u63A5\u53E3\u4E0D\u53EF\u7528\uFF1B\u8BF7\u68C0\u67E5 Hermes \u7684\u6A21\u578B/provider \u914D\u7F6E\u548C Gateway \u65E5\u5FD7\u3002",
664
- "doctor.apiUnavailable.fix.gateway": "\u5EFA\u8BAE\uFF1A\u76F4\u63A5\u8FD0\u884C `hermes gateway run --replace`\uFF0C\u67E5\u770B Hermes Gateway \u8F93\u51FA\u7684\u539F\u59CB\u9519\u8BEF\u3002",
665
- "doctor.apiCheck.notHermes": "\u8BFB\u53D6 Hermes \u5065\u5EB7\u68C0\u67E5\u54CD\u5E94\uFF08{probe}\uFF09\u3002",
666
- "doctor.apiCheck.authInvalid": "\u4F7F\u7528\u5F53\u524D\u914D\u7F6E\u7684 API key \u8BF7\u6C42 {probe}\u3002",
667
- "doctor.apiCheck.modelsTimeout": "\u8BF7\u6C42 {probe}\uFF0C\u9A8C\u8BC1 API key \u548C\u6A21\u578B\u63A5\u53E3\u662F\u5426\u53EF\u7528\u3002",
668
- "doctor.apiCheck.modelsHttp": "\u8BF7\u6C42 {probe}\uFF0C\u9A8C\u8BC1 API key \u548C\u6A21\u578B\u63A5\u53E3\u662F\u5426\u53EF\u7528\u3002",
669
- "doctor.apiCheck.port": "\u8FDE\u63A5 Hermes \u5065\u5EB7\u68C0\u67E5\u63A5\u53E3\uFF1A{probe}\u3002",
670
- "doctor.apiCheck.gatewayState": "\u8BFB\u53D6 /health/detailed \u91CC\u7684 gateway_state\u3002",
671
- "doctor.apiCheck.apiServerState": "\u8BFB\u53D6 /health/detailed \u91CC\u7684 platforms.api_server.state\u3002",
672
- "doctor.apiCheck.exitReason": "\u8BFB\u53D6 /health/detailed \u91CC\u7684 exit_reason\u3002",
673
- "doctor.apiCheck.unknown": "\u6267\u884C Hermes API Server \u5065\u5EB7\u68C0\u67E5\u3002",
674
- "doctor.apiIssue.notHermes": "\u5F53\u524D\u914D\u7F6E\u7AEF\u53E3\u8FD4\u56DE\u7684\u4E0D\u662F Hermes API Server \u5065\u5EB7\u54CD\u5E94\uFF0C\u53EF\u80FD\u88AB\u5176\u4ED6\u672C\u673A\u670D\u52A1\u5360\u7528\u3002",
675
- "doctor.apiIssue.authInvalid": "API key \u88AB\u62D2\u7EDD\uFF08HTTP 401\uFF09\u3002\u5F53\u524D Profile .env/config.yaml \u91CC\u7684 key \u53EF\u80FD\u5DF2\u8FC7\u671F\uFF0C\u6216\u8FD9\u4E2A\u7AEF\u53E3\u5C5E\u4E8E\u53E6\u4E00\u4E2A Profile\u3002",
676
- "doctor.apiIssue.modelsTimeout": "/v1/models \u5728\u8D85\u65F6\u65F6\u95F4\u5185\u6CA1\u6709\u54CD\u5E94\u3002",
677
- "doctor.apiIssue.modelsHttp": "/v1/models \u8FD4\u56DE HTTP {status}\u3002",
678
- "doctor.apiIssue.port": "\u7AEF\u53E3 {port} \u6CA1\u6709\u54CD\u5E94\u3002",
679
- "doctor.apiIssue.gatewayState": "Gateway \u72B6\u6001\u662F {state}\u3002",
680
- "doctor.apiIssue.apiServerState": "API Server \u72B6\u6001\u662F {state}{detail}\u3002",
681
- "doctor.apiIssue.exitReason": "Gateway \u9000\u51FA\u539F\u56E0\uFF1A{detail}\u3002",
682
- "doctor.apiIssue.unknown": "{message}",
683
- "error.relayPublicKeyMismatch": "Relay \u62D2\u7EDD\u4E86\u914D\u5BF9\u8BF7\u6C42\uFF1AServer \u7B7E\u53D1\u7684 bootstrap token \u4E0E\u672C\u673A Link \u516C\u94A5\u4E0D\u5339\u914D\u3002\u8BF7\u786E\u8BA4 Server \u548C Relay \u4F7F\u7528\u540C\u4E00\u5957 bootstrap key \u914D\u7F6E\uFF0C\u7136\u540E\u91CD\u65B0\u8FD0\u884C `hermeslink pair`\u3002",
684
- "error.relayChallengeInvalid": "Relay \u6CA1\u6709\u8FD4\u56DE\u6709\u6548\u7684\u5B89\u88C5\u6311\u6218\u3002",
685
- "error.relayLinkInvalid": "Relay \u6CA1\u6709\u8FD4\u56DE\u6709\u6548\u7684 link_id\u3002",
686
- "error.relayEmpty": "Relay \u8FD4\u56DE\u4E86\u7A7A\u54CD\u5E94\u3002",
687
- "error.serverHttp": "HermesPilot Server \u8BF7\u6C42\u5931\u8D25\uFF0CHTTP \u72B6\u6001\u7801\uFF1A{status}\u3002",
688
- "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",
689
- "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",
690
- "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",
691
- "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",
692
- "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"
693
- }
694
- };
695
- function detectSystemLanguage(env = process.env) {
696
- const candidates = [
697
- env.HERMESLINK_LANG,
698
- env.HERMESLINK_LANGUAGE,
699
- env.LC_ALL,
700
- env.LC_MESSAGES,
701
- env.LANG,
702
- env.LANGUAGE?.split(":")[0],
703
- Intl.DateTimeFormat().resolvedOptions().locale
704
- ];
705
- for (const candidate of candidates) {
706
- const language = parseLanguage(candidate);
707
- if (language) {
708
- return language;
709
- }
710
- }
711
- return "en";
712
- }
713
- function resolveLanguage(setting) {
714
- const configured = parseLanguage(setting);
715
- if (configured) {
716
- return configured;
717
- }
718
- return detectSystemLanguage();
719
- }
720
- function translate(language, key, values = {}) {
721
- const template = messages[language][key] ?? messages.en[key];
722
- return template.replace(/\{(\w+)\}/gu, (_, name) => String(values[name] ?? ""));
723
- }
724
- function localizeErrorMessage(error, language) {
725
- const message = error instanceof Error ? error.message : String(error);
726
- if (language === "en") {
727
- return message;
728
- }
729
- const mapped = translateKnownError(message, language);
730
- return mapped ?? message;
731
- }
732
- function translateKnownError(message, language) {
733
- if (message === "Relay bootstrap token does not match public key") {
734
- return translate(language, "error.relayPublicKeyMismatch");
735
- }
736
- if (message === "Relay did not return a valid install challenge") {
737
- return translate(language, "error.relayChallengeInvalid");
738
- }
739
- if (message === "Relay did not return a valid link_id") {
740
- return translate(language, "error.relayLinkInvalid");
741
- }
742
- if (message === "Relay returned an empty response") {
743
- return translate(language, "error.relayEmpty");
744
- }
745
- const portInUse = /^listen EADDRINUSE: address already in use .*:(?<port>\d+)$/u.exec(message);
746
- if (portInUse?.groups?.port) {
747
- return translate(language, "error.portInUse", { port: portInUse.groups.port });
748
- }
749
- const serverHttp = /^HermesPilot Server request failed with HTTP (?<status>\d+)$/u.exec(message);
750
- if (serverHttp?.groups?.status) {
751
- return translate(language, "error.serverHttp", { status: serverHttp.groups.status });
752
- }
753
- const pairingServerUnreachable = /^HermesPilot Server is unreachable while trying to [^.]+\. Please check whether (?<url>\S+) is reachable\./u.exec(message);
754
- if (pairingServerUnreachable?.groups?.url) {
755
- return translate(language, "error.pairingServerUnreachable", {
756
- url: pairingServerUnreachable.groups.url
757
- });
758
- }
759
- const pairingRelayUnreachable = /^Hermes Relay is unreachable while trying to [^.]+\. Please check whether (?<url>\S+) is reachable\./u.exec(message);
760
- if (pairingRelayUnreachable?.groups?.url) {
761
- return translate(language, "error.pairingRelayUnreachable", {
762
- url: pairingRelayUnreachable.groups.url
763
- });
764
- }
765
- if (message.includes("Pairing requires HermesPilot Server and Relay")) {
766
- return [translate(language, "error.pairingRequires"), translate(language, "error.pairingRequires.detail")].join("\n");
767
- }
768
- return null;
769
- }
770
- function parseLanguage(value) {
771
- const normalized = value?.trim().replace("_", "-").toLowerCase();
772
- if (!normalized || normalized === "auto" || normalized === "c" || normalized === "posix") {
773
- return null;
774
- }
775
- if (normalized.startsWith("zh")) {
776
- return "zh-CN";
777
- }
778
- if (normalized.startsWith("en")) {
779
- return "en";
780
- }
781
- return null;
782
- }
783
-
784
304
  // src/hermes/api-server-diagnostics.ts
785
305
  function formatHermesApiServerUnavailable(error, language) {
786
306
  if (!(error instanceof HermesApiServerUnavailableError)) {
@@ -978,7 +498,8 @@ async function assertPairingPreflightReady(options = {}) {
978
498
  profileName,
979
499
  fetchImpl: options.fetchImpl,
980
500
  timeoutMs: 5e3,
981
- autoStart: true
501
+ autoStart: true,
502
+ language: options.language
982
503
  });
983
504
  return {
984
505
  profileName,
@@ -1305,8 +826,9 @@ program.command("status").option("--json", helpText("status.json")).description(
1305
826
  if (payload.lanHost) {
1306
827
  console.log(t("status.lanHost", { value: payload.lanHost }));
1307
828
  }
1308
- if (payload.environment.warning) {
1309
- console.log(t("status.environmentWarning", { message: payload.environment.warning }));
829
+ const environmentWarning = formatRuntimeEnvironmentWarning(payload.environment, t);
830
+ if (environmentWarning) {
831
+ console.log(t("status.environmentWarning", { message: environmentWarning }));
1310
832
  }
1311
833
  console.log(t("status.linkId", { value: payload.identity?.linkId ?? t("status.notPaired") }));
1312
834
  console.log(t("status.relay", { value: formatRelayStatus(payload.relay, t, language) }));
@@ -1451,8 +973,9 @@ program.command("pair").description(helpText("pair.description")).action(async (
1451
973
  const t = translate.bind(null, language);
1452
974
  console.log(t("pair.preflight"));
1453
975
  const environment = detectRuntimeEnvironment();
1454
- if (environment.warning) {
1455
- console.log(t("doctor.networkWarning", { message: environment.warning }));
976
+ const environmentWarning = formatRuntimeEnvironmentWarning(environment, t);
977
+ if (environmentWarning) {
978
+ console.log(t("doctor.networkWarning", { message: environmentWarning }));
1456
979
  }
1457
980
  const preflight = await assertPairingPreflightReady({
1458
981
  paths,
@@ -1464,7 +987,7 @@ program.command("pair").description(helpText("pair.description")).action(async (
1464
987
  if (preflight.notice) {
1465
988
  console.log(preflight.notice);
1466
989
  if (preflight.backupPath) {
1467
- console.log(`Hermes config backup: ${preflight.backupPath}`);
990
+ console.log(t("config.backup", { path: preflight.backupPath }));
1468
991
  }
1469
992
  }
1470
993
  console.log(t("pair.preparing"));
@@ -1649,19 +1172,20 @@ program.command("doctor").option("--install", helpText("doctor.installOnly")).de
1649
1172
  const [identity, config] = await Promise.all([ensureIdentity(), loadConfig()]);
1650
1173
  const language = resolveLanguage(config.language);
1651
1174
  const t = translate.bind(null, language);
1652
- const hermesConfig = await ensureHermesApiServerConfig();
1175
+ const hermesConfig = await ensureHermesApiServerConfig("default", void 0, language);
1653
1176
  console.log(t("doctor.identityOk"));
1654
1177
  console.log(t("doctor.installId", { value: identity.install_id }));
1655
1178
  console.log(t("doctor.linkId", { value: identity.link_id ?? t("doctor.notAssigned") }));
1656
1179
  const environment = detectRuntimeEnvironment();
1657
- if (environment.warning) {
1658
- console.log(t("doctor.networkWarning", { message: environment.warning }));
1180
+ const environmentWarning = formatRuntimeEnvironmentWarning(environment, t);
1181
+ if (environmentWarning) {
1182
+ console.log(t("doctor.networkWarning", { message: environmentWarning }));
1659
1183
  }
1660
1184
  console.log(t("doctor.lanHost", { value: config.lanHost ?? t("status.notSet") }));
1661
1185
  if (hermesConfig.notice) {
1662
1186
  console.log(hermesConfig.notice);
1663
1187
  if (hermesConfig.backupPath) {
1664
- console.log(`Hermes config backup: ${hermesConfig.backupPath}`);
1188
+ console.log(t("config.backup", { path: hermesConfig.backupPath }));
1665
1189
  }
1666
1190
  }
1667
1191
  try {
@@ -1671,7 +1195,7 @@ program.command("doctor").option("--install", helpText("doctor.installOnly")).de
1671
1195
  console.log(t("doctor.hermesCliUnavailable"));
1672
1196
  }
1673
1197
  try {
1674
- const availability = await ensureHermesApiServerAvailable({ timeoutMs: 5e3 });
1198
+ const availability = await ensureHermesApiServerAvailable({ timeoutMs: 5e3, language });
1675
1199
  console.log(t(availability.started ? "doctor.apiStarted" : "doctor.apiReady"));
1676
1200
  } catch (error) {
1677
1201
  console.log(formatHermesApiServerUnavailable(error, language));
@@ -1857,6 +1381,18 @@ function formatLogSourceLabel(source, t) {
1857
1381
  return t("status.logSource.gateway");
1858
1382
  }
1859
1383
  }
1384
+ function formatRuntimeEnvironmentWarning(environment, t) {
1385
+ if (!environment.warning) {
1386
+ return null;
1387
+ }
1388
+ if (environment.kind === "wsl") {
1389
+ return t("environment.warning.wsl");
1390
+ }
1391
+ if (environment.kind === "container") {
1392
+ return t("environment.warning.container");
1393
+ }
1394
+ return environment.warning;
1395
+ }
1860
1396
  function formatTimestamp(value, language) {
1861
1397
  const timestamp = Date.parse(value);
1862
1398
  if (!Number.isFinite(timestamp)) {
@@ -2212,28 +1748,40 @@ async function promptForLanguage() {
2212
1748
  output: process.stdout
2213
1749
  });
2214
1750
  try {
1751
+ const promptLanguage = detectSystemLanguage();
2215
1752
  for (; ; ) {
2216
- const answer = await rl.question(
2217
- [
2218
- "\u8BF7\u9009\u62E9 Hermes Link \u663E\u793A\u8BED\u8A00 / Choose Hermes Link language:",
2219
- " 1. \u4E2D\u6587",
2220
- " 2. English",
2221
- "\u8F93\u5165 1 \u6216 2 \u540E\u56DE\u8F66 / Enter 1 or 2: "
2222
- ].join("\n")
2223
- );
1753
+ const answer = await rl.question(formatLanguagePrompt(promptLanguage));
2224
1754
  const normalized = answer.trim().toLowerCase();
2225
- if (normalized === "1" || normalized === "zh" || normalized === "zh-cn" || normalized === "\u4E2D\u6587") {
1755
+ if (normalized === "zh" || normalized === "zh-cn" || normalized === "\u4E2D\u6587" || normalized === "1" && promptLanguage === "zh-CN" || normalized === "2" && promptLanguage === "en") {
2226
1756
  return "zh-CN";
2227
1757
  }
2228
- if (normalized === "2" || normalized === "en" || normalized === "english") {
1758
+ if (normalized === "en" || normalized === "english" || normalized === "1" && promptLanguage === "en" || normalized === "2" && promptLanguage === "zh-CN") {
2229
1759
  return "en";
2230
1760
  }
2231
- console.log("\u8BF7\u8F93\u5165 1 \u6216 2\u3002 / Please enter 1 or 2.");
1761
+ console.log(
1762
+ promptLanguage === "zh-CN" ? "\u8BF7\u8F93\u5165 1 \u6216 2\u3002" : "Please enter 1 or 2."
1763
+ );
2232
1764
  }
2233
1765
  } finally {
2234
1766
  rl.close();
2235
1767
  }
2236
1768
  }
1769
+ function formatLanguagePrompt(language) {
1770
+ if (language === "zh-CN") {
1771
+ return [
1772
+ "\u8BF7\u9009\u62E9 Hermes Link \u663E\u793A\u8BED\u8A00\uFF1A",
1773
+ " 1. \u4E2D\u6587",
1774
+ " 2. English",
1775
+ "\u8F93\u5165 1 \u6216 2 \u540E\u56DE\u8F66\uFF1A"
1776
+ ].join("\n");
1777
+ }
1778
+ return [
1779
+ "Choose Hermes Link language:",
1780
+ " 1. English",
1781
+ " 2. Chinese",
1782
+ "Enter 1 or 2:"
1783
+ ].join("\n");
1784
+ }
2237
1785
  async function waitForShutdown(cleanup) {
2238
1786
  await new Promise((resolve) => {
2239
1787
  const stop = () => resolve();