@hermespilot/link 0.6.4 → 0.6.6

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.
@@ -1386,6 +1386,506 @@ import { readFile as readFile2, readdir as readdir2 } from "fs/promises";
1386
1386
  import os from "os";
1387
1387
  import path3 from "path";
1388
1388
  import YAML from "yaml";
1389
+
1390
+ // src/i18n.ts
1391
+ var messages = {
1392
+ en: {
1393
+ "program.description": "Hermes Link companion service",
1394
+ "program.version": "print Hermes Link version",
1395
+ "status.description": "Show local Hermes Link status",
1396
+ "status.json": "print machine-readable status",
1397
+ "status.runtime": "Runtime: {value}",
1398
+ "status.mode": "Mode: {value}",
1399
+ "status.daemon": "Service: {value}",
1400
+ "status.daemon.runningReachable": "running (PID {pid}, local API reachable)",
1401
+ "status.daemon.runningUnreachable": "running (PID {pid}, local API is not responding)",
1402
+ "status.daemon.notRunning": "not running",
1403
+ "status.port": "Local port: {value}",
1404
+ "status.lanHost": "LAN access address (manual override): {value}",
1405
+ "status.notSet": "not set",
1406
+ "status.unknown": "unknown",
1407
+ "status.environmentWarning": "Network note: {message}",
1408
+ "status.linkId": "Link ID: {value}",
1409
+ "status.notPaired": "not paired",
1410
+ "status.relay": "Relay: {value}",
1411
+ "status.relay.notPaired": "not connected (not paired yet; Relay is disabled until pairing)",
1412
+ "status.relay.notConfigured": "not configured",
1413
+ "status.relay.serviceStopped": "not connected (background service is not running)",
1414
+ "status.relay.serviceUnreachable": "unknown (background service is running but local API is not responding)",
1415
+ "status.relay.unknown": "unknown (background service has not reported Relay state yet)",
1416
+ "status.relay.state.connecting": "connecting",
1417
+ "status.relay.state.connected": "connected",
1418
+ "status.relay.state.disconnected": "disconnected",
1419
+ "status.relay.state.retrying": "retrying",
1420
+ "status.relay.state.cooldown": "cooling down",
1421
+ "status.relay.state.failed": "failed",
1422
+ "status.relay.stateWithAttempt": "{state}, attempt {attempt}",
1423
+ "status.relay.updatedAt": "updated {time}",
1424
+ "status.relay.withMessage": "{state} - {message}",
1425
+ "status.relay.withUpdatedAt": "{state}; {updatedAt}",
1426
+ "status.relay.withMessageAndUpdatedAt": "{state} - {message}; {updatedAt}",
1427
+ "status.recentError": "Latest error: {value}",
1428
+ "status.recentError.none": "none",
1429
+ "status.recentError.format": "{time} [{source}] {message}",
1430
+ "status.logSource.service": "service",
1431
+ "status.logSource.daemon": "daemon",
1432
+ "status.logSource.gateway": "gateway",
1433
+ "status.timeUnknown": "time unknown",
1434
+ "environment.warning.wsl": "Detected WSL. The LAN IP found inside WSL is usually a private VM address and is not reachable from your phone. Use Relay or set `hermeslink config set lan-host <Windows LAN IP>`.",
1435
+ "environment.warning.container": "Detected a container environment. Container LAN IPs are usually not reachable from your phone. Use Relay or set `hermeslink config set lan-host <host LAN IP>`.",
1436
+ "start.description": "Start Hermes Link daemon",
1437
+ "start.backgroundStarted": "Hermes Link is running in the background. PID: {pid}",
1438
+ "start.alreadyRunning": "Hermes Link is already running. PID: {pid}",
1439
+ "start.notPaired": "Hermes Link is not paired yet. Starting in local-only maintenance mode.",
1440
+ "start.notPaired.detail": "Relay, Server polling, and LAN entrypoints stay disabled until you run `hermeslink pair`.",
1441
+ "start.listening": "Hermes Link API listening on http://127.0.0.1:{port}",
1442
+ "start.relayConnecting": "Relay control connecting for {linkId}",
1443
+ "stop.description": "Stop the background Hermes Link daemon",
1444
+ "stop.stopped": "Hermes Link stopped.",
1445
+ "stop.notRunning": "Hermes Link is not running.",
1446
+ "restart.description": "Restart the background Hermes Link daemon",
1447
+ "deliver.description": "Import files from a Hermes Link delivery staging directory",
1448
+ "deliver.imported": "Delivered {count} file(s) to conversation {conversationId}.",
1449
+ "deliver.none": "No new files were delivered for conversation {conversationId}.",
1450
+ "config.description": "Manage local Hermes Link configuration",
1451
+ "config.set.description": "Set a configuration value",
1452
+ "config.unset.description": "Unset a configuration value",
1453
+ "config.unknownKey": "Unknown config key: {key}",
1454
+ "config.lanHostInvalid": "lan-host must be a private LAN IPv4 address, such as 192.168.1.23.",
1455
+ "config.lanHostSet": "LAN access address override set: {value}",
1456
+ "config.lanHostUnset": "LAN access address override cleared.",
1457
+ "config.logLevelInvalid": "log-level must be one of: debug, info, warn, error.",
1458
+ "config.logLevelSet": "Configured log level: {value}",
1459
+ "config.logLevelRestartRequired": "The running daemon keeps its current logger until restart. Run `hermeslink restart` to apply this write level immediately.",
1460
+ "config.logLevelUnset": "Configured log level reset to the default: {value}.",
1461
+ "config.reported": "Updated HermesPilot Server with the latest LAN address.",
1462
+ "config.reportSkippedUnpaired": "Hermes Link is not paired yet. The LAN address will be reported after pairing.",
1463
+ "config.backup": "Hermes config backup: {path}",
1464
+ "config.notice.synced": "Synchronized Hermes API Server config.yaml with the effective Profile .env settings.",
1465
+ "config.notice.autoFilled": "Hermes API Server was auto-filled with {fields}; existing port/host/key were not overwritten.",
1466
+ "config.notice.repairDefault": "Hermes API Server kept the default port and rotated the key to repair an old Gateway or a key mismatch that caused 401.",
1467
+ "config.notice.repairProfile": "Hermes API Server was reassigned a local port and had its key rotated to repair an old Gateway or a key mismatch that caused 401.",
1468
+ "daemon.description": "Run Hermes Link in the foreground",
1469
+ "daemon.foreground": "Hermes Link foreground daemon is running. Press Ctrl+C to stop.",
1470
+ "logs.description": "Show or follow Hermes Link logs",
1471
+ "logs.follow": "follow log output",
1472
+ "logs.tail": "print the last N lines before exiting or following",
1473
+ "logs.serviceOnly": "only read the service JSONL log",
1474
+ "logs.daemonOnly": "only read the daemon stdout/stderr log",
1475
+ "logs.gatewayOnly": "only read Hermes Gateway logs",
1476
+ "logs.all": "read service, daemon, and Gateway logs",
1477
+ "logs.level": "minimum level to display: debug, info, warn, or error",
1478
+ "logs.debugLevel": "show debug and above",
1479
+ "logs.infoLevel": "show info and above",
1480
+ "logs.warnLevel": "show warn and above",
1481
+ "logs.errorLevel": "show errors only",
1482
+ "logs.servicePath": "Service log: {path}",
1483
+ "logs.daemonPath": "Daemon stdout/stderr log: {path}",
1484
+ "logs.gatewayPath": "Gateway log: {path}",
1485
+ "logs.followHint": "Use `hermeslink logs -f` to follow logs, or `hermeslink logs -n 100` to print recent lines.",
1486
+ "logs.following": "Following logs. Press Ctrl+C to stop.",
1487
+ "logs.flush.description": "Clear Hermes Link log files",
1488
+ "logs.flush.all": "clear service, daemon, and Gateway logs",
1489
+ "logs.flush.flushed": "Cleared {truncated} active log file(s) and removed {removed} rotated log file(s).",
1490
+ "autostart.description": "Manage boot autostart",
1491
+ "autostart.on.description": "Enable boot autostart",
1492
+ "autostart.off.description": "Disable boot autostart",
1493
+ "autostart.status.description": "Show boot autostart status",
1494
+ "autostart.enabled": "Boot autostart enabled via {method}: {path}",
1495
+ "autostart.disabled": "Boot autostart disabled.",
1496
+ "autostart.status.enabled": "Boot autostart: enabled via {method}: {path}",
1497
+ "autostart.status.disabled": "Boot autostart: disabled. Method: {method}. File: {path}",
1498
+ "autostart.unsupported": "Boot autostart is not supported on this platform yet.",
1499
+ "autostart.alreadyEnabled": "Boot autostart is already enabled via {method}: {path}",
1500
+ "pair.description": "Create a Hermes Link pairing session",
1501
+ "pair.preflight": "Checking local Hermes configuration before pairing...",
1502
+ "pair.preflight.hermesFiles": "Checking Hermes data directory, config, and environment files...",
1503
+ "pair.preflight.hermesCli": "Checking whether the Hermes CLI is available...",
1504
+ "pair.preflight.hermesApiServer": "Checking whether the Hermes API Server is ready...",
1505
+ "pair.hermesHome": "Hermes home: {path}",
1506
+ "pair.hermesVersion": "Hermes CLI: {value}",
1507
+ "pair.apiReady": "Hermes API Server is ready on 127.0.0.1:{port}",
1508
+ "pair.preparing": "Creating the pairing session...",
1509
+ "pair.scan": "Please scan the QR code below in the HermesPilot App:",
1510
+ "pair.openPairingPage": "If the QR code is hard to scan, you can open this page locally: {url}",
1511
+ "pair.manualCode": "You can also use the HermesPilot App manual connection mode and enter this pairing code:",
1512
+ "pair.expires": "Pairing expires in 10 minutes. Press Ctrl+C to cancel waiting.",
1513
+ "pair.expired": "Pairing expired. Please run `hermeslink pair` again.",
1514
+ "pair.claimed": "Pairing succeeded. Starting Hermes Link in the background...",
1515
+ "pair.claimedRunning": "Pairing succeeded. Hermes Link is already running in the background.",
1516
+ "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.",
1517
+ "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.",
1518
+ "pair.relayOnlySafetyHint": "Hermes Link will not automatically change Windows/WSL bridge, firewall, or portproxy settings because those are system-level network exposure choices.",
1519
+ "pair.autostartUnchanged": "Existing paired devices found. Boot autostart settings were left unchanged.",
1520
+ "pair.autostartFailed": "Pairing succeeded, but boot autostart could not be enabled: {message}",
1521
+ "doctor.description": "Run local diagnostics",
1522
+ "doctor.installOnly": "only check npm global command and PATH setup",
1523
+ "doctor.installHeader": "Install/PATH diagnostics:",
1524
+ "doctor.installNpmPrefix": "npm global prefix: {value}",
1525
+ "doctor.installGlobalBin": "npm global bin directory: {value}",
1526
+ "doctor.installExpectedCommand": "expected hermeslink command: {value} ({state})",
1527
+ "doctor.installCommandOnPath": "hermeslink found on PATH: {value}",
1528
+ "doctor.installUnknown": "unknown",
1529
+ "doctor.installOk": "ok",
1530
+ "doctor.installMissing": "missing",
1531
+ "doctor.installReady": "The global hermeslink command is visible to this shell.",
1532
+ "doctor.installPrefixUnavailable": "Could not read npm global prefix with `{command} prefix -g`. Check that npm is available in this shell.",
1533
+ "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.",
1534
+ "doctor.installPathMissing": "npm installed hermeslink, but this shell cannot see npm's global bin directory on PATH.",
1535
+ "doctor.installShadowed": "A different hermeslink command appears earlier on PATH. Remove the old command or move npm's global bin directory earlier on PATH.",
1536
+ "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.",
1537
+ "doctor.installDirectRun": "Direct run without changing PATH: {command}",
1538
+ "doctor.installUnixPathHint": 'Temporary PATH fix: export PATH="{path}:$PATH"',
1539
+ "doctor.installWindowsPathHint": "Add this directory to your user Path, then open a new terminal: {path}",
1540
+ "doctor.installNpxFallback": "PATH-independent fallback: npx --yes @hermespilot/link doctor --install",
1541
+ "doctor.identityOk": "Runtime identity: OK",
1542
+ "doctor.installId": "Install ID: {value}",
1543
+ "doctor.linkId": "Link ID: {value}",
1544
+ "doctor.notAssigned": "not assigned",
1545
+ "doctor.lanHost": "LAN access address (manual override): {value}",
1546
+ "doctor.networkWarning": "Network note: {message}",
1547
+ "doctor.hermesCli": "Hermes CLI: {value}",
1548
+ "doctor.hermesCliUnavailable": "Hermes CLI is unavailable. Please make sure the `hermes` command can run in this system.",
1549
+ "doctor.apiReady": "Hermes API Server: ready",
1550
+ "doctor.apiStarted": "Hermes API Server: started and ready",
1551
+ "doctor.apiUnavailable": "Hermes API Server: unavailable. {message}",
1552
+ "doctor.apiUnavailable.summary": "Hermes API Server: unavailable",
1553
+ "doctor.apiUnavailable.profile": "Profile: {profile}; port: {port}",
1554
+ "doctor.apiUnavailable.diagnosisDivider": "----- API Server diagnosis -----",
1555
+ "doctor.apiUnavailable.check": "Check: {check}",
1556
+ "doctor.apiUnavailable.result": "Result: {result}",
1557
+ "doctor.apiUnavailable.startAttempt": "Link tried to start it with: {command}",
1558
+ "doctor.apiUnavailable.startSkipped": "Auto-start was skipped; Link only checked the existing server.",
1559
+ "doctor.apiUnavailable.recentLog": "Recent Gateway log: {message}",
1560
+ "doctor.apiUnavailable.gatewayLog": "Gateway log: {path}",
1561
+ "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.",
1562
+ "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.",
1563
+ "doctor.apiUnavailable.fix.notHermes": "Suggestion: change the Hermes API Server port or stop the non-Hermes service using this port.",
1564
+ "doctor.apiUnavailable.fix.models": "Suggestion: the health endpoint responds, but the model API does not. Check Hermes provider/model configuration and Gateway logs.",
1565
+ "doctor.apiUnavailable.fix.gateway": "Suggestion: start Hermes Gateway with `hermes gateway run --replace` and check the printed Hermes error.",
1566
+ "doctor.apiCheck.notHermes": "Read the Hermes health response from {probe}.",
1567
+ "doctor.apiCheck.authInvalid": "Call {probe} with the configured API key.",
1568
+ "doctor.apiCheck.modelsTimeout": "Call {probe} to verify the API key and model API.",
1569
+ "doctor.apiCheck.modelsHttp": "Call {probe} to verify the API key and model API.",
1570
+ "doctor.apiCheck.port": "Connect to the Hermes health endpoints: {probe}.",
1571
+ "doctor.apiCheck.gatewayState": "Read gateway_state from /health/detailed.",
1572
+ "doctor.apiCheck.apiServerState": "Read platforms.api_server.state from /health/detailed.",
1573
+ "doctor.apiCheck.exitReason": "Read exit_reason from /health/detailed.",
1574
+ "doctor.apiCheck.unknown": "Run the Hermes API Server health checks.",
1575
+ "doctor.apiIssue.notHermes": "The configured port returned a non-Hermes health response. Another local service may be using this port.",
1576
+ "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.",
1577
+ "doctor.apiIssue.modelsTimeout": "/v1/models did not respond before the timeout.",
1578
+ "doctor.apiIssue.modelsHttp": "/v1/models returned HTTP {status}.",
1579
+ "doctor.apiIssue.port": "Port {port} did not respond.",
1580
+ "doctor.apiIssue.gatewayState": "Gateway state is {state}.",
1581
+ "doctor.apiIssue.apiServerState": "API Server state is {state}{detail}.",
1582
+ "doctor.apiIssue.exitReason": "Gateway exit reason: {detail}.",
1583
+ "doctor.apiIssue.unknown": "{message}",
1584
+ "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.",
1585
+ "error.relayChallengeInvalid": "Relay did not return a valid install challenge.",
1586
+ "error.relayLinkInvalid": "Relay did not return a valid link_id.",
1587
+ "error.relayEmpty": "Relay returned an empty response.",
1588
+ "error.serverHttp": "HermesPilot Server request failed with HTTP {status}.",
1589
+ "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.",
1590
+ "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.",
1591
+ "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.",
1592
+ "error.pairingRequires": "Pairing needs HermesPilot Server and Relay, but this command could not start a complete pairing session.",
1593
+ "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."
1594
+ },
1595
+ "zh-CN": {
1596
+ "program.description": "Hermes Link \u672C\u5730\u4F34\u968F\u670D\u52A1",
1597
+ "program.version": "\u8F93\u51FA Hermes Link \u7248\u672C\u53F7",
1598
+ "status.description": "\u67E5\u770B\u672C\u673A Hermes Link \u72B6\u6001",
1599
+ "status.json": "\u8F93\u51FA\u673A\u5668\u53EF\u8BFB\u7684\u72B6\u6001 JSON",
1600
+ "status.runtime": "\u8FD0\u884C\u76EE\u5F55\uFF1A{value}",
1601
+ "status.mode": "\u6A21\u5F0F\uFF1A{value}",
1602
+ "status.daemon": "\u540E\u53F0\u670D\u52A1\uFF1A{value}",
1603
+ "status.daemon.runningReachable": "\u8FD0\u884C\u4E2D\uFF08PID\uFF1A{pid}\uFF0C\u672C\u5730 API \u53EF\u8BBF\u95EE\uFF09",
1604
+ "status.daemon.runningUnreachable": "\u8FD0\u884C\u4E2D\uFF08PID\uFF1A{pid}\uFF0C\u4F46\u672C\u5730 API \u6682\u4E0D\u53EF\u8BBF\u95EE\uFF09",
1605
+ "status.daemon.notRunning": "\u672A\u8FD0\u884C",
1606
+ "status.port": "\u672C\u5730\u7AEF\u53E3\uFF1A{value}",
1607
+ "status.lanHost": "\u5C40\u57DF\u7F51\u8BBF\u95EE\u5730\u5740\uFF08\u624B\u52A8\u6307\u5B9A\uFF09\uFF1A{value}",
1608
+ "status.notSet": "\u672A\u8BBE\u7F6E",
1609
+ "status.unknown": "\u672A\u77E5",
1610
+ "status.environmentWarning": "\u7F51\u7EDC\u63D0\u793A\uFF1A{message}",
1611
+ "status.linkId": "Link ID\uFF1A{value}",
1612
+ "status.notPaired": "\u5C1A\u672A\u914D\u5BF9",
1613
+ "status.relay": "Relay\uFF1A{value}",
1614
+ "status.relay.notPaired": "\u672A\u8FDE\u63A5\uFF08\u5C1A\u672A\u914D\u5BF9\uFF0CRelay \u4F1A\u4FDD\u6301\u5173\u95ED\uFF09",
1615
+ "status.relay.notConfigured": "\u672A\u914D\u7F6E",
1616
+ "status.relay.serviceStopped": "\u672A\u8FDE\u63A5\uFF08\u540E\u53F0\u670D\u52A1\u672A\u8FD0\u884C\uFF09",
1617
+ "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",
1618
+ "status.relay.unknown": "\u672A\u77E5\uFF08\u540E\u53F0\u670D\u52A1\u8FD8\u6CA1\u6709\u4E0A\u62A5 Relay \u72B6\u6001\uFF09",
1619
+ "status.relay.state.connecting": "\u8FDE\u63A5\u4E2D",
1620
+ "status.relay.state.connected": "\u5DF2\u8FDE\u63A5",
1621
+ "status.relay.state.disconnected": "\u672A\u8FDE\u63A5",
1622
+ "status.relay.state.retrying": "\u91CD\u8BD5\u4E2D",
1623
+ "status.relay.state.cooldown": "\u51B7\u5374\u4E2D",
1624
+ "status.relay.state.failed": "\u8FDE\u63A5\u5931\u8D25",
1625
+ "status.relay.stateWithAttempt": "{state}\uFF08\u7B2C {attempt} \u6B21\uFF09",
1626
+ "status.relay.updatedAt": "\u66F4\u65B0\u4E8E {time}",
1627
+ "status.relay.withMessage": "{state} - {message}",
1628
+ "status.relay.withUpdatedAt": "{state}\uFF1B{updatedAt}",
1629
+ "status.relay.withMessageAndUpdatedAt": "{state} - {message}\uFF1B{updatedAt}",
1630
+ "status.recentError": "\u6700\u8FD1\u9519\u8BEF\uFF1A{value}",
1631
+ "status.recentError.none": "\u65E0",
1632
+ "status.recentError.format": "{time} [{source}] {message}",
1633
+ "status.logSource.service": "\u670D\u52A1",
1634
+ "status.logSource.daemon": "\u5B88\u62A4\u8FDB\u7A0B",
1635
+ "status.logSource.gateway": "Gateway",
1636
+ "status.timeUnknown": "\u65F6\u95F4\u672A\u77E5",
1637
+ "environment.warning.wsl": "\u68C0\u6D4B\u5230 WSL\u3002WSL \u91CC\u627E\u5230\u7684 LAN IP \u901A\u5E38\u53EA\u662F\u865A\u62DF\u673A\u5185\u7F51\u5730\u5740\uFF0C\u624B\u673A\u4E00\u822C\u65E0\u6CD5\u8BBF\u95EE\u3002\u8BF7\u4F18\u5148\u4F7F\u7528 Relay\uFF0C\u6216\u8FD0\u884C `hermeslink config set lan-host <Windows LAN IP>` \u624B\u52A8\u6307\u5B9A Windows \u5BBF\u4E3B\u673A\u7684\u53EF\u8FBE\u5730\u5740\u3002",
1638
+ "environment.warning.container": "\u68C0\u6D4B\u5230\u5BB9\u5668\u73AF\u5883\u3002\u5BB9\u5668\u91CC\u7684 LAN IP \u901A\u5E38\u65E0\u6CD5\u88AB\u624B\u673A\u8BBF\u95EE\u3002\u8BF7\u4F18\u5148\u4F7F\u7528 Relay\uFF0C\u6216\u8FD0\u884C `hermeslink config set lan-host <\u5BBF\u4E3B\u673A LAN IP>` \u624B\u52A8\u6307\u5B9A\u53EF\u8FBE\u5730\u5740\u3002",
1639
+ "start.description": "\u542F\u52A8 Hermes Link \u670D\u52A1",
1640
+ "start.backgroundStarted": "Hermes Link \u5DF2\u5728\u540E\u53F0\u8FD0\u884C\u3002PID\uFF1A{pid}",
1641
+ "start.alreadyRunning": "Hermes Link \u5DF2\u7ECF\u5728\u8FD0\u884C\u3002PID\uFF1A{pid}",
1642
+ "start.notPaired": "Hermes Link \u8FD8\u6CA1\u6709\u914D\u5BF9\uFF0C\u5C06\u4EE5\u672C\u5730\u7EF4\u62A4\u6A21\u5F0F\u542F\u52A8\u3002",
1643
+ "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",
1644
+ "start.listening": "Hermes Link API \u6B63\u5728\u76D1\u542C http://127.0.0.1:{port}",
1645
+ "start.relayConnecting": "\u6B63\u5728\u4E3A {linkId} \u8FDE\u63A5 Relay \u63A7\u5236\u901A\u9053",
1646
+ "stop.description": "\u505C\u6B62\u540E\u53F0 Hermes Link \u670D\u52A1",
1647
+ "stop.stopped": "Hermes Link \u5DF2\u505C\u6B62\u3002",
1648
+ "stop.notRunning": "Hermes Link \u6CA1\u6709\u5728\u8FD0\u884C\u3002",
1649
+ "restart.description": "\u91CD\u542F\u540E\u53F0 Hermes Link \u670D\u52A1",
1650
+ "deliver.description": "\u5BFC\u5165 Hermes Link \u4EA4\u4ED8\u4E2D\u8F6C\u76EE\u5F55\u4E2D\u7684\u6587\u4EF6",
1651
+ "deliver.imported": "\u5DF2\u5411\u4F1A\u8BDD {conversationId} \u4EA4\u4ED8 {count} \u4E2A\u6587\u4EF6\u3002",
1652
+ "deliver.none": "\u4F1A\u8BDD {conversationId} \u6CA1\u6709\u65B0\u7684\u53EF\u4EA4\u4ED8\u6587\u4EF6\u3002",
1653
+ "config.description": "\u7BA1\u7406\u672C\u673A Hermes Link \u914D\u7F6E",
1654
+ "config.set.description": "\u8BBE\u7F6E\u914D\u7F6E\u9879",
1655
+ "config.unset.description": "\u6E05\u9664\u914D\u7F6E\u9879",
1656
+ "config.unknownKey": "\u672A\u77E5\u914D\u7F6E\u9879\uFF1A{key}",
1657
+ "config.lanHostInvalid": "lan-host \u5FC5\u987B\u662F\u5C40\u57DF\u7F51 IPv4 \u5730\u5740\uFF0C\u4F8B\u5982 192.168.1.23\u3002",
1658
+ "config.lanHostSet": "\u5DF2\u8BBE\u7F6E\u5C40\u57DF\u7F51\u8BBF\u95EE\u5730\u5740\uFF08\u624B\u52A8\u6307\u5B9A\uFF09\uFF1A{value}",
1659
+ "config.lanHostUnset": "\u5DF2\u6E05\u9664\u5C40\u57DF\u7F51\u8BBF\u95EE\u5730\u5740\u624B\u52A8\u914D\u7F6E\u3002",
1660
+ "config.logLevelInvalid": "log-level \u53EA\u80FD\u662F\u4EE5\u4E0B\u503C\u4E4B\u4E00\uFF1Adebug\u3001info\u3001warn\u3001error\u3002",
1661
+ "config.logLevelSet": "\u5DF2\u914D\u7F6E\u65E5\u5FD7\u7EA7\u522B\uFF1A{value}",
1662
+ "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",
1663
+ "config.logLevelUnset": "\u5DF2\u5C06\u65E5\u5FD7\u7EA7\u522B\u6062\u590D\u4E3A\u9ED8\u8BA4\u503C\uFF1A{value}\u3002",
1664
+ "config.reported": "\u5DF2\u628A\u6700\u65B0\u5C40\u57DF\u7F51\u5730\u5740\u66F4\u65B0\u5230 HermesPilot Server\u3002",
1665
+ "config.reportSkippedUnpaired": "Hermes Link \u8FD8\u6CA1\u6709\u914D\u5BF9\uFF0C\u5C40\u57DF\u7F51\u5730\u5740\u4F1A\u5728\u914D\u5BF9\u540E\u4E0A\u62A5\u3002",
1666
+ "config.backup": "Hermes \u914D\u7F6E\u5907\u4EFD\uFF1A{path}",
1667
+ "config.notice.synced": "\u5DF2\u540C\u6B65 Hermes API Server config.yaml \u4E0E Profile .env \u7684\u6709\u6548\u914D\u7F6E\u3002",
1668
+ "config.notice.autoFilled": "\u5DF2\u4E3A Hermes API Server \u81EA\u52A8\u8865\u5145 {fields}\uFF1B\u672A\u8986\u76D6\u5DF2\u6709 port/host/key\u3002",
1669
+ "config.notice.repairDefault": "\u5DF2\u4E3A Hermes API Server \u4FDD\u6301\u9ED8\u8BA4\u7AEF\u53E3\u5E76\u8F6E\u6362 key\uFF0C\u7528\u4E8E\u4FEE\u590D\u65E7 Gateway \u6216 key \u4E0D\u4E00\u81F4\u5BFC\u81F4\u7684 401\u3002",
1670
+ "config.notice.repairProfile": "\u5DF2\u4E3A Hermes API Server \u91CD\u65B0\u5206\u914D\u672C\u673A\u7AEF\u53E3\u5E76\u8F6E\u6362 key\uFF0C\u7528\u4E8E\u4FEE\u590D\u65E7 Gateway \u6216 key \u4E0D\u4E00\u81F4\u5BFC\u81F4\u7684 401\u3002",
1671
+ "daemon.description": "\u4EE5\u524D\u53F0\u65B9\u5F0F\u8FD0\u884C Hermes Link",
1672
+ "daemon.foreground": "Hermes Link \u524D\u53F0\u670D\u52A1\u6B63\u5728\u8FD0\u884C\u3002\u6309 Ctrl+C \u505C\u6B62\u3002",
1673
+ "logs.description": "\u663E\u793A\u6216\u8DDF\u8E2A Hermes Link \u65E5\u5FD7",
1674
+ "logs.follow": "\u6301\u7EED\u8DDF\u8E2A\u65E5\u5FD7\u8F93\u51FA",
1675
+ "logs.tail": "\u9000\u51FA\u6216\u6301\u7EED\u8DDF\u8E2A\u524D\u5148\u8F93\u51FA\u6700\u8FD1 N \u884C",
1676
+ "logs.serviceOnly": "\u53EA\u8BFB\u53D6\u670D\u52A1 JSONL \u65E5\u5FD7",
1677
+ "logs.daemonOnly": "\u53EA\u8BFB\u53D6 Daemon \u6807\u51C6\u8F93\u51FA/\u9519\u8BEF\u65E5\u5FD7",
1678
+ "logs.gatewayOnly": "\u53EA\u8BFB\u53D6 Hermes Gateway \u65E5\u5FD7",
1679
+ "logs.all": "\u8BFB\u53D6\u670D\u52A1\u3001Daemon \u4E0E Gateway \u65E5\u5FD7",
1680
+ "logs.level": "\u6700\u4F4E\u663E\u793A\u7EA7\u522B\uFF1Adebug\u3001info\u3001warn \u6216 error",
1681
+ "logs.debugLevel": "\u663E\u793A debug \u53CA\u4EE5\u4E0A\u7EA7\u522B",
1682
+ "logs.infoLevel": "\u663E\u793A info \u53CA\u4EE5\u4E0A\u7EA7\u522B",
1683
+ "logs.warnLevel": "\u663E\u793A warn \u53CA\u4EE5\u4E0A\u7EA7\u522B",
1684
+ "logs.errorLevel": "\u53EA\u663E\u793A error \u7EA7\u522B",
1685
+ "logs.servicePath": "\u670D\u52A1\u65E5\u5FD7\uFF1A{path}",
1686
+ "logs.daemonPath": "Daemon \u6807\u51C6\u8F93\u51FA/\u9519\u8BEF\u65E5\u5FD7\uFF1A{path}",
1687
+ "logs.gatewayPath": "Gateway \u65E5\u5FD7\uFF1A{path}",
1688
+ "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",
1689
+ "logs.following": "\u6B63\u5728\u6301\u7EED\u8DDF\u8E2A\u65E5\u5FD7\u3002\u6309 Ctrl+C \u505C\u6B62\u3002",
1690
+ "logs.flush.description": "\u6E05\u7A7A Hermes Link \u65E5\u5FD7\u6587\u4EF6",
1691
+ "logs.flush.all": "\u6E05\u7A7A\u670D\u52A1\u3001Daemon \u4E0E Gateway \u65E5\u5FD7",
1692
+ "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",
1693
+ "autostart.description": "\u7BA1\u7406\u5F00\u673A\u81EA\u542F",
1694
+ "autostart.on.description": "\u542F\u7528\u5F00\u673A\u81EA\u542F",
1695
+ "autostart.off.description": "\u5173\u95ED\u5F00\u673A\u81EA\u542F",
1696
+ "autostart.status.description": "\u67E5\u770B\u5F00\u673A\u81EA\u542F\u72B6\u6001",
1697
+ "autostart.enabled": "\u5DF2\u542F\u7528\u5F00\u673A\u81EA\u542F\uFF0C\u65B9\u5F0F\uFF1A{method}\uFF0C\u6587\u4EF6\uFF1A{path}",
1698
+ "autostart.disabled": "\u5DF2\u5173\u95ED\u5F00\u673A\u81EA\u542F\u3002",
1699
+ "autostart.status.enabled": "\u5F00\u673A\u81EA\u542F\uFF1A\u5DF2\u542F\u7528\uFF0C\u65B9\u5F0F\uFF1A{method}\uFF0C\u6587\u4EF6\uFF1A{path}",
1700
+ "autostart.status.disabled": "\u5F00\u673A\u81EA\u542F\uFF1A\u672A\u542F\u7528\u3002\u65B9\u5F0F\uFF1A{method}\uFF0C\u6587\u4EF6\uFF1A{path}",
1701
+ "autostart.unsupported": "\u5F53\u524D\u5E73\u53F0\u6682\u4E0D\u652F\u6301\u5F00\u673A\u81EA\u542F\u3002",
1702
+ "autostart.alreadyEnabled": "\u5F00\u673A\u81EA\u542F\u5DF2\u542F\u7528\uFF0C\u65B9\u5F0F\uFF1A{method}\uFF0C\u6587\u4EF6\uFF1A{path}",
1703
+ "pair.description": "\u521B\u5EFA Hermes Link \u914D\u5BF9\u4F1A\u8BDD",
1704
+ "pair.preflight": "\u6B63\u5728\u914D\u5BF9\u524D\u68C0\u67E5\u672C\u673A Hermes \u914D\u7F6E...",
1705
+ "pair.preflight.hermesFiles": "\u6B63\u5728\u68C0\u67E5 Hermes \u6570\u636E\u76EE\u5F55\u3001\u914D\u7F6E\u6587\u4EF6\u548C\u73AF\u5883\u6587\u4EF6...",
1706
+ "pair.preflight.hermesCli": "\u6B63\u5728\u68C0\u67E5 Hermes CLI \u662F\u5426\u53EF\u7528...",
1707
+ "pair.preflight.hermesApiServer": "\u6B63\u5728\u68C0\u67E5 Hermes API Server \u662F\u5426\u5C31\u7EEA...",
1708
+ "pair.hermesHome": "Hermes \u6570\u636E\u76EE\u5F55\uFF1A{path}",
1709
+ "pair.hermesVersion": "Hermes CLI\uFF1A{value}",
1710
+ "pair.apiReady": "Hermes API Server \u5DF2\u5C31\u7EEA\uFF1A127.0.0.1:{port}",
1711
+ "pair.preparing": "\u6B63\u5728\u521B\u5EFA\u914D\u5BF9\u4F1A\u8BDD...",
1712
+ "pair.scan": "\u8BF7\u5728 HermesPilot App \u4E2D\u626B\u7801\u4E0B\u9762\u7684\u4E8C\u7EF4\u7801\uFF1A",
1713
+ "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}",
1714
+ "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",
1715
+ "pair.expires": "\u914D\u5BF9\u4F1A\u8BDD 10 \u5206\u949F\u540E\u8FC7\u671F\u3002\u6309 Ctrl+C \u9000\u51FA\u7B49\u5F85\u3002",
1716
+ "pair.expired": "\u914D\u5BF9\u4F1A\u8BDD\u5DF2\u8FC7\u671F\uFF0C\u8BF7\u91CD\u65B0\u8FD0\u884C `hermeslink pair`\u3002",
1717
+ "pair.claimed": "\u914D\u5BF9\u5DF2\u6210\u529F\u3002\u6B63\u5728\u628A Hermes Link \u5207\u6362\u5230\u540E\u53F0\u8FD0\u884C...",
1718
+ "pair.claimedRunning": "\u914D\u5BF9\u5DF2\u6210\u529F\u3002Hermes Link \u5DF2\u5728\u540E\u53F0\u6301\u7EED\u8FD0\u884C\u3002",
1719
+ "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",
1720
+ "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",
1721
+ "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",
1722
+ "pair.autostartUnchanged": "\u68C0\u6D4B\u5230\u5DF2\u6709\u914D\u5BF9\u8BBE\u5907\uFF0C\u5F00\u673A\u81EA\u542F\u8BBE\u7F6E\u4FDD\u6301\u4E0D\u53D8\u3002",
1723
+ "pair.autostartFailed": "\u914D\u5BF9\u5DF2\u6210\u529F\uFF0C\u4F46\u542F\u7528\u5F00\u673A\u81EA\u542F\u5931\u8D25\uFF1A{message}",
1724
+ "doctor.description": "\u8FD0\u884C\u672C\u673A\u8BCA\u65AD",
1725
+ "doctor.installOnly": "\u53EA\u68C0\u67E5 npm \u5168\u5C40\u547D\u4EE4\u548C PATH \u8BBE\u7F6E",
1726
+ "doctor.installHeader": "\u5B89\u88C5 / PATH \u8BCA\u65AD\uFF1A",
1727
+ "doctor.installNpmPrefix": "npm \u5168\u5C40 prefix\uFF1A{value}",
1728
+ "doctor.installGlobalBin": "npm \u5168\u5C40 bin \u76EE\u5F55\uFF1A{value}",
1729
+ "doctor.installExpectedCommand": "\u9884\u671F\u7684 hermeslink \u547D\u4EE4\uFF1A{value}\uFF08{state}\uFF09",
1730
+ "doctor.installCommandOnPath": "\u5F53\u524D PATH \u627E\u5230\u7684 hermeslink\uFF1A{value}",
1731
+ "doctor.installUnknown": "\u672A\u77E5",
1732
+ "doctor.installOk": "\u5B58\u5728",
1733
+ "doctor.installMissing": "\u672A\u627E\u5230",
1734
+ "doctor.installReady": "\u5F53\u524D shell \u53EF\u4EE5\u76F4\u63A5\u627E\u5230\u5168\u5C40 hermeslink \u547D\u4EE4\u3002",
1735
+ "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",
1736
+ "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",
1737
+ "doctor.installPathMissing": "npm \u5DF2\u5B89\u88C5 hermeslink\uFF0C\u4F46\u5F53\u524D shell \u7684 PATH \u91CC\u6CA1\u6709 npm \u5168\u5C40 bin \u76EE\u5F55\u3002",
1738
+ "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",
1739
+ "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",
1740
+ "doctor.installDirectRun": "\u4E0D\u6539 PATH \u4E5F\u53EF\u4EE5\u76F4\u63A5\u8FD0\u884C\uFF1A{command}",
1741
+ "doctor.installUnixPathHint": '\u4E34\u65F6\u8865 PATH\uFF1Aexport PATH="{path}:$PATH"',
1742
+ "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}",
1743
+ "doctor.installNpxFallback": "\u4E0D\u4F9D\u8D56 PATH \u7684\u515C\u5E95\u547D\u4EE4\uFF1Anpx --yes @hermespilot/link doctor --install",
1744
+ "doctor.identityOk": "\u8FD0\u884C\u8EAB\u4EFD\uFF1A\u6B63\u5E38",
1745
+ "doctor.installId": "Install ID\uFF1A{value}",
1746
+ "doctor.linkId": "Link ID\uFF1A{value}",
1747
+ "doctor.notAssigned": "\u5C1A\u672A\u5206\u914D",
1748
+ "doctor.lanHost": "\u5C40\u57DF\u7F51\u8BBF\u95EE\u5730\u5740\uFF08\u624B\u52A8\u6307\u5B9A\uFF09\uFF1A{value}",
1749
+ "doctor.networkWarning": "\u7F51\u7EDC\u63D0\u793A\uFF1A{message}",
1750
+ "doctor.hermesCli": "Hermes CLI\uFF1A{value}",
1751
+ "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",
1752
+ "doctor.apiReady": "Hermes API Server\uFF1A\u5DF2\u5C31\u7EEA",
1753
+ "doctor.apiStarted": "Hermes API Server\uFF1A\u5DF2\u81EA\u52A8\u542F\u52A8\u5E76\u5C31\u7EEA",
1754
+ "doctor.apiUnavailable": "Hermes API Server\uFF1A\u4E0D\u53EF\u7528\u3002{message}",
1755
+ "doctor.apiUnavailable.summary": "Hermes API Server\uFF1A\u4E0D\u53EF\u7528",
1756
+ "doctor.apiUnavailable.profile": "Profile\uFF1A{profile}\uFF1B\u7AEF\u53E3\uFF1A{port}",
1757
+ "doctor.apiUnavailable.diagnosisDivider": "----- API Server \u8BCA\u65AD -----",
1758
+ "doctor.apiUnavailable.check": "\u68C0\u6D4B\u73AF\u8282\uFF1A{check}",
1759
+ "doctor.apiUnavailable.result": "\u68C0\u6D4B\u7ED3\u679C\uFF1A{result}",
1760
+ "doctor.apiUnavailable.startAttempt": "Link \u5DF2\u5C1D\u8BD5\u542F\u52A8\uFF1A{command}",
1761
+ "doctor.apiUnavailable.startSkipped": "\u5DF2\u8DF3\u8FC7\u81EA\u52A8\u542F\u52A8\uFF1BLink \u53EA\u68C0\u67E5\u4E86\u5F53\u524D\u5DF2\u6709\u7684 API Server\u3002",
1762
+ "doctor.apiUnavailable.recentLog": "\u6700\u8FD1 Gateway \u65E5\u5FD7\uFF1A{message}",
1763
+ "doctor.apiUnavailable.gatewayLog": "Gateway \u65E5\u5FD7\uFF1A{path}",
1764
+ "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",
1765
+ "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",
1766
+ "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",
1767
+ "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",
1768
+ "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",
1769
+ "doctor.apiCheck.notHermes": "\u8BFB\u53D6 Hermes \u5065\u5EB7\u68C0\u67E5\u54CD\u5E94\uFF08{probe}\uFF09\u3002",
1770
+ "doctor.apiCheck.authInvalid": "\u4F7F\u7528\u5F53\u524D\u914D\u7F6E\u7684 API key \u8BF7\u6C42 {probe}\u3002",
1771
+ "doctor.apiCheck.modelsTimeout": "\u8BF7\u6C42 {probe}\uFF0C\u9A8C\u8BC1 API key \u548C\u6A21\u578B\u63A5\u53E3\u662F\u5426\u53EF\u7528\u3002",
1772
+ "doctor.apiCheck.modelsHttp": "\u8BF7\u6C42 {probe}\uFF0C\u9A8C\u8BC1 API key \u548C\u6A21\u578B\u63A5\u53E3\u662F\u5426\u53EF\u7528\u3002",
1773
+ "doctor.apiCheck.port": "\u8FDE\u63A5 Hermes \u5065\u5EB7\u68C0\u67E5\u63A5\u53E3\uFF1A{probe}\u3002",
1774
+ "doctor.apiCheck.gatewayState": "\u8BFB\u53D6 /health/detailed \u91CC\u7684 gateway_state\u3002",
1775
+ "doctor.apiCheck.apiServerState": "\u8BFB\u53D6 /health/detailed \u91CC\u7684 platforms.api_server.state\u3002",
1776
+ "doctor.apiCheck.exitReason": "\u8BFB\u53D6 /health/detailed \u91CC\u7684 exit_reason\u3002",
1777
+ "doctor.apiCheck.unknown": "\u6267\u884C Hermes API Server \u5065\u5EB7\u68C0\u67E5\u3002",
1778
+ "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",
1779
+ "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",
1780
+ "doctor.apiIssue.modelsTimeout": "/v1/models \u5728\u8D85\u65F6\u65F6\u95F4\u5185\u6CA1\u6709\u54CD\u5E94\u3002",
1781
+ "doctor.apiIssue.modelsHttp": "/v1/models \u8FD4\u56DE HTTP {status}\u3002",
1782
+ "doctor.apiIssue.port": "\u7AEF\u53E3 {port} \u6CA1\u6709\u54CD\u5E94\u3002",
1783
+ "doctor.apiIssue.gatewayState": "Gateway \u72B6\u6001\u662F {state}\u3002",
1784
+ "doctor.apiIssue.apiServerState": "API Server \u72B6\u6001\u662F {state}{detail}\u3002",
1785
+ "doctor.apiIssue.exitReason": "Gateway \u9000\u51FA\u539F\u56E0\uFF1A{detail}\u3002",
1786
+ "doctor.apiIssue.unknown": "{message}",
1787
+ "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",
1788
+ "error.relayChallengeInvalid": "Relay \u6CA1\u6709\u8FD4\u56DE\u6709\u6548\u7684\u5B89\u88C5\u6311\u6218\u3002",
1789
+ "error.relayLinkInvalid": "Relay \u6CA1\u6709\u8FD4\u56DE\u6709\u6548\u7684 link_id\u3002",
1790
+ "error.relayEmpty": "Relay \u8FD4\u56DE\u4E86\u7A7A\u54CD\u5E94\u3002",
1791
+ "error.serverHttp": "HermesPilot Server \u8BF7\u6C42\u5931\u8D25\uFF0CHTTP \u72B6\u6001\u7801\uFF1A{status}\u3002",
1792
+ "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",
1793
+ "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",
1794
+ "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",
1795
+ "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",
1796
+ "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"
1797
+ }
1798
+ };
1799
+ function detectSystemLanguage(env = process.env) {
1800
+ const candidates = [
1801
+ env.HERMESLINK_LANG,
1802
+ env.HERMESLINK_LANGUAGE,
1803
+ env.LC_ALL,
1804
+ env.LC_MESSAGES,
1805
+ env.LANG,
1806
+ env.LANGUAGE?.split(":")[0],
1807
+ Intl.DateTimeFormat().resolvedOptions().locale
1808
+ ];
1809
+ for (const candidate of candidates) {
1810
+ const language = parseLanguage(candidate);
1811
+ if (language) {
1812
+ return language;
1813
+ }
1814
+ }
1815
+ return "en";
1816
+ }
1817
+ function resolveLanguage(setting) {
1818
+ const configured = parseLanguage(setting);
1819
+ if (configured) {
1820
+ return configured;
1821
+ }
1822
+ return detectSystemLanguage();
1823
+ }
1824
+ function translate(language, key, values = {}) {
1825
+ const template = messages[language][key] ?? messages.en[key];
1826
+ return template.replace(/\{(\w+)\}/gu, (_, name) => String(values[name] ?? ""));
1827
+ }
1828
+ function localizeErrorMessage(error, language) {
1829
+ const message = error instanceof Error ? error.message : String(error);
1830
+ if (language === "en") {
1831
+ return message;
1832
+ }
1833
+ const mapped = translateKnownError(message, language);
1834
+ return mapped ?? message;
1835
+ }
1836
+ function translateKnownError(message, language) {
1837
+ if (message === "Relay bootstrap token does not match public key") {
1838
+ return translate(language, "error.relayPublicKeyMismatch");
1839
+ }
1840
+ if (message === "Relay did not return a valid install challenge") {
1841
+ return translate(language, "error.relayChallengeInvalid");
1842
+ }
1843
+ if (message === "Relay did not return a valid link_id") {
1844
+ return translate(language, "error.relayLinkInvalid");
1845
+ }
1846
+ if (message === "Relay returned an empty response") {
1847
+ return translate(language, "error.relayEmpty");
1848
+ }
1849
+ const portInUse = /^listen EADDRINUSE: address already in use .*:(?<port>\d+)$/u.exec(message);
1850
+ if (portInUse?.groups?.port) {
1851
+ return translate(language, "error.portInUse", { port: portInUse.groups.port });
1852
+ }
1853
+ const serverHttp = /^HermesPilot Server request failed with HTTP (?<status>\d+)$/u.exec(message);
1854
+ if (serverHttp?.groups?.status) {
1855
+ return translate(language, "error.serverHttp", { status: serverHttp.groups.status });
1856
+ }
1857
+ const pairingServerUnreachable = /^HermesPilot Server is unreachable while trying to [^.]+\. Please check whether (?<url>\S+) is reachable\./u.exec(message);
1858
+ if (pairingServerUnreachable?.groups?.url) {
1859
+ return translate(language, "error.pairingServerUnreachable", {
1860
+ url: pairingServerUnreachable.groups.url
1861
+ });
1862
+ }
1863
+ const pairingRelayUnreachable = /^Hermes Relay is unreachable while trying to [^.]+\. Please check whether (?<url>\S+) is reachable\./u.exec(message);
1864
+ if (pairingRelayUnreachable?.groups?.url) {
1865
+ return translate(language, "error.pairingRelayUnreachable", {
1866
+ url: pairingRelayUnreachable.groups.url
1867
+ });
1868
+ }
1869
+ if (message.includes("Pairing requires HermesPilot Server and Relay")) {
1870
+ return [translate(language, "error.pairingRequires"), translate(language, "error.pairingRequires.detail")].join("\n");
1871
+ }
1872
+ return null;
1873
+ }
1874
+ function parseLanguage(value) {
1875
+ const normalized = value?.trim().replace("_", "-").toLowerCase();
1876
+ if (!normalized || normalized === "auto" || normalized === "c" || normalized === "posix") {
1877
+ return null;
1878
+ }
1879
+ if (normalized.startsWith("zh")) {
1880
+ return "zh-CN";
1881
+ }
1882
+ if (normalized.startsWith("en")) {
1883
+ return "en";
1884
+ }
1885
+ return null;
1886
+ }
1887
+
1888
+ // src/hermes/config.ts
1389
1889
  var DEFAULT_HERMES_API_SERVER_HOST = "127.0.0.1";
1390
1890
  var DEFAULT_HERMES_API_SERVER_PORT = 8642;
1391
1891
  var PROFILE_API_SERVER_PORT_START = DEFAULT_HERMES_API_SERVER_PORT + 1;
@@ -2456,26 +2956,26 @@ async function saveHermesProfileToolConfig(profileName, toolKey, input, configPa
2456
2956
  restartHint: PROFILE_TOOL_CONFIG_RESTART_HINT
2457
2957
  };
2458
2958
  }
2459
- async function ensureHermesApiServerKey(profileName = "default", configPath = resolveHermesConfigPath(profileName)) {
2460
- return ensureHermesApiServerConfig(profileName, configPath);
2959
+ async function ensureHermesApiServerKey(profileName = "default", configPath = resolveHermesConfigPath(profileName), language) {
2960
+ return ensureHermesApiServerConfig(profileName, configPath, language);
2461
2961
  }
2462
- async function ensureHermesApiServerConfig(profileName = "default", configPath = resolveHermesConfigPath(profileName)) {
2962
+ async function ensureHermesApiServerConfig(profileName = "default", configPath = resolveHermesConfigPath(profileName), language) {
2463
2963
  if (profileName !== "default") {
2464
2964
  return withProfileApiServerPortAssignmentLock(
2465
- () => ensureHermesApiServerConfigUnlocked(profileName, configPath)
2965
+ () => ensureHermesApiServerConfigUnlocked(profileName, configPath, language)
2466
2966
  );
2467
2967
  }
2468
- return ensureHermesApiServerConfigUnlocked(profileName, configPath);
2968
+ return ensureHermesApiServerConfigUnlocked(profileName, configPath, language);
2469
2969
  }
2470
- async function repairHermesApiServerConfig(profileName = "default", configPath = resolveHermesConfigPath(profileName)) {
2970
+ async function repairHermesApiServerConfig(profileName = "default", configPath = resolveHermesConfigPath(profileName), language) {
2471
2971
  if (profileName !== "default") {
2472
2972
  return withProfileApiServerPortAssignmentLock(
2473
- () => repairHermesApiServerConfigUnlocked(profileName, configPath)
2973
+ () => repairHermesApiServerConfigUnlocked(profileName, configPath, language)
2474
2974
  );
2475
2975
  }
2476
- return repairHermesApiServerConfigUnlocked(profileName, configPath);
2976
+ return repairHermesApiServerConfigUnlocked(profileName, configPath, language);
2477
2977
  }
2478
- async function ensureHermesApiServerConfigUnlocked(profileName = "default", configPath = resolveHermesConfigPath(profileName)) {
2978
+ async function ensureHermesApiServerConfigUnlocked(profileName = "default", configPath = resolveHermesConfigPath(profileName), language) {
2479
2979
  const existingRaw = await readFile2(configPath, "utf8").catch(
2480
2980
  (error) => {
2481
2981
  if (isNodeError3(error, "ENOENT")) {
@@ -2569,16 +3069,19 @@ async function ensureHermesApiServerConfigUnlocked(profileName = "default", conf
2569
3069
  hostAdded,
2570
3070
  portAdded,
2571
3071
  backupPath,
2572
- notice: buildNotice({
2573
- keyAdded: !configKey,
2574
- enabledAdded,
2575
- hostAdded,
2576
- portAdded,
2577
- port: desiredPort
2578
- })
3072
+ notice: buildNotice(
3073
+ {
3074
+ keyAdded: !configKey,
3075
+ enabledAdded,
3076
+ hostAdded,
3077
+ portAdded,
3078
+ port: desiredPort
3079
+ },
3080
+ language
3081
+ )
2579
3082
  };
2580
3083
  }
2581
- async function repairHermesApiServerConfigUnlocked(profileName = "default", configPath = resolveHermesConfigPath(profileName)) {
3084
+ async function repairHermesApiServerConfigUnlocked(profileName = "default", configPath = resolveHermesConfigPath(profileName), language) {
2582
3085
  const existingRaw = await readFile2(configPath, "utf8").catch(
2583
3086
  (error) => {
2584
3087
  if (isNodeError3(error, "ENOENT")) {
@@ -2626,7 +3129,7 @@ async function repairHermesApiServerConfigUnlocked(profileName = "default", conf
2626
3129
  hostAdded: previous.host !== DEFAULT_HERMES_API_SERVER_HOST,
2627
3130
  portAdded: previous.port !== freshPort,
2628
3131
  backupPath,
2629
- notice: profileName === "default" ? "\u5DF2\u4E3A Hermes API Server \u4FDD\u6301\u9ED8\u8BA4\u7AEF\u53E3\u5E76\u8F6E\u6362 key\uFF0C\u7528\u4E8E\u4FEE\u590D\u65E7 Gateway \u6216 key \u4E0D\u4E00\u81F4\u5BFC\u81F4\u7684 401\u3002" : "\u5DF2\u4E3A Hermes API Server \u91CD\u65B0\u5206\u914D\u672C\u673A\u7AEF\u53E3\u5E76\u8F6E\u6362 key\uFF0C\u7528\u4E8E\u4FEE\u590D\u65E7 Gateway \u6216 key \u4E0D\u4E00\u81F4\u5BFC\u81F4\u7684 401\u3002"
3132
+ notice: buildRepairNotice(language, profileName)
2630
3133
  };
2631
3134
  }
2632
3135
  async function readHermesConfigDocument(configPath) {
@@ -4618,7 +5121,22 @@ function formatEnvValue(value) {
4618
5121
  function escapeRegExp(value) {
4619
5122
  return value.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
4620
5123
  }
4621
- function buildNotice(flags) {
5124
+ function buildNotice(flags, language) {
5125
+ const fields = configNoticeFields(flags);
5126
+ if (!language) {
5127
+ if (fields.length === 0) {
5128
+ return "\u5DF2\u540C\u6B65 Hermes API Server config.yaml \u4E0E Profile .env \u7684\u6709\u6548\u914D\u7F6E\u3002";
5129
+ }
5130
+ return `\u5DF2\u4E3A Hermes API Server \u81EA\u52A8\u8865\u5145 ${fields.join("\u3001")}\uFF1B\u672A\u8986\u76D6\u5DF2\u6709 port/host/key\u3002`;
5131
+ }
5132
+ if (fields.length === 0) {
5133
+ return translate(language, "config.notice.synced");
5134
+ }
5135
+ return translate(language, "config.notice.autoFilled", {
5136
+ fields: joinNoticeFields(fields, language)
5137
+ });
5138
+ }
5139
+ function configNoticeFields(flags) {
4622
5140
  const fields = [];
4623
5141
  if (flags.enabledAdded) {
4624
5142
  fields.push("enabled");
@@ -4632,10 +5150,19 @@ function buildNotice(flags) {
4632
5150
  if (flags.keyAdded) {
4633
5151
  fields.push("key");
4634
5152
  }
4635
- if (fields.length === 0) {
4636
- return "\u5DF2\u540C\u6B65 Hermes API Server config.yaml \u4E0E Profile .env \u7684\u6709\u6548\u914D\u7F6E\u3002";
5153
+ return fields;
5154
+ }
5155
+ function buildRepairNotice(language, profileName) {
5156
+ if (!language) {
5157
+ return profileName === "default" ? "\u5DF2\u4E3A Hermes API Server \u4FDD\u6301\u9ED8\u8BA4\u7AEF\u53E3\u5E76\u8F6E\u6362 key\uFF0C\u7528\u4E8E\u4FEE\u590D\u65E7 Gateway \u6216 key \u4E0D\u4E00\u81F4\u5BFC\u81F4\u7684 401\u3002" : "\u5DF2\u4E3A Hermes API Server \u91CD\u65B0\u5206\u914D\u672C\u673A\u7AEF\u53E3\u5E76\u8F6E\u6362 key\uFF0C\u7528\u4E8E\u4FEE\u590D\u65E7 Gateway \u6216 key \u4E0D\u4E00\u81F4\u5BFC\u81F4\u7684 401\u3002";
4637
5158
  }
4638
- return `\u5DF2\u4E3A Hermes API Server \u81EA\u52A8\u8865\u5145 ${fields.join("\u3001")}\uFF1B\u672A\u8986\u76D6\u5DF2\u6709 port/host/key\u3002`;
5159
+ return translate(
5160
+ language,
5161
+ profileName === "default" ? "config.notice.repairDefault" : "config.notice.repairProfile"
5162
+ );
5163
+ }
5164
+ function joinNoticeFields(fields, language) {
5165
+ return language === "zh-CN" ? fields.join("\u3001") : fields.join(", ");
4639
5166
  }
4640
5167
  function toRecord(value) {
4641
5168
  return typeof value === "object" && value !== null ? value : {};
@@ -4891,7 +5418,7 @@ import os2 from "os";
4891
5418
  import path5 from "path";
4892
5419
 
4893
5420
  // src/constants.ts
4894
- var LINK_VERSION = "0.6.4";
5421
+ var LINK_VERSION = "0.6.6";
4895
5422
  var LINK_COMMAND = "hermeslink";
4896
5423
  var LINK_DEFAULT_PORT = 52379;
4897
5424
  var LINK_RUNTIME_DIR_NAME = ".hermeslink";
@@ -5436,7 +5963,7 @@ var HermesApiServerUnavailableError = class extends LinkHttpError {
5436
5963
  async function ensureHermesApiServerAvailable(options = {}) {
5437
5964
  const profileName = normalizeProfileName(options.profileName);
5438
5965
  await assertProfileExists(profileName);
5439
- const configResult = await ensureHermesApiServerConfig(profileName);
5966
+ const configResult = await ensureHermesApiServerConfig(profileName, void 0, options.language);
5440
5967
  const fetcher = options.fetchImpl ?? fetch;
5441
5968
  void options.logger?.debug("gateway_health_check_started", {
5442
5969
  profile: profileName,
@@ -5499,7 +6026,7 @@ async function ensureHermesApiServerAvailable(options = {}) {
5499
6026
  port: configResult.apiServer.port ?? null,
5500
6027
  issue: health.issue ?? "auth_invalid"
5501
6028
  });
5502
- const repairedConfigResult = await repairHermesApiServerConfig(profileName);
6029
+ const repairedConfigResult = await repairHermesApiServerConfig(profileName, void 0, options.language);
5503
6030
  const repairedStart = await startHermesGatewayOnce(
5504
6031
  options.paths ?? resolveRuntimePaths(),
5505
6032
  profileName,
@@ -5559,7 +6086,7 @@ async function reloadHermesGateway(options = {}) {
5559
6086
  });
5560
6087
  const serviceRestart = await restartHermesGatewayServiceIfAvailable(options);
5561
6088
  if (serviceRestart) {
5562
- const configResult = await ensureHermesApiServerConfig(profileName);
6089
+ const configResult = await ensureHermesApiServerConfig(profileName, void 0, options.language);
5563
6090
  const fetcher = options.fetchImpl ?? fetch;
5564
6091
  const health = await waitForHermesApiHealth(
5565
6092
  configResult.apiServer,
@@ -7746,6 +8273,37 @@ function hasRunningRuns(snapshot) {
7746
8273
  function hasQueuedRuns(snapshot) {
7747
8274
  return snapshot.runs.some((run) => run.status === "queued");
7748
8275
  }
8276
+ function buildConversationEventStreamState(snapshot) {
8277
+ const pendingApprovalRunIds = /* @__PURE__ */ new Set();
8278
+ let hasPendingApproval = false;
8279
+ for (const message of snapshot.messages) {
8280
+ if (!message.approvals?.some((approval) => approval.status === "pending")) {
8281
+ continue;
8282
+ }
8283
+ hasPendingApproval = true;
8284
+ if (message.run_id) {
8285
+ pendingApprovalRunIds.add(message.run_id);
8286
+ }
8287
+ }
8288
+ const summaries = snapshot.runs.map(
8289
+ (run) => toEventStreamRunSummary(run, pendingApprovalRunIds.has(run.id))
8290
+ );
8291
+ const activeRuns = summaries.filter((run) => isRealtimeRunStatus(run.status));
8292
+ const unknownRuns = summaries.filter((run) => run.status === "unknown");
8293
+ const requiresUserAction = hasPendingApproval || summaries.some((run) => run.requires_user_action);
8294
+ const hasQueuedRun = activeRuns.some((run) => run.status === "queued");
8295
+ const hasRunningRun = activeRuns.some((run) => run.status === "running");
8296
+ const hasUnknownRun = unknownRuns.length > 0;
8297
+ const reason = requiresUserAction ? "requires_user_action" : hasQueuedRun ? "queued_run" : hasRunningRun ? "active_run" : hasUnknownRun ? "unknown" : "terminal";
8298
+ return {
8299
+ should_subscribe: !requiresUserAction && activeRuns.length > 0,
8300
+ reason,
8301
+ has_active_runs: activeRuns.length > 0 || hasUnknownRun,
8302
+ requires_user_action: requiresUserAction,
8303
+ active_runs: activeRuns,
8304
+ latest_runs: summaries.slice().sort((left, right) => right.updated_at.localeCompare(left.updated_at)).slice(0, 5)
8305
+ };
8306
+ }
7749
8307
  function isRetryableUserMessage(message) {
7750
8308
  return message.role === "user" && message.raw?.format !== "hermes-link-slash-command" && (messageText(message).length > 0 || message.parts.some((part) => Boolean(part.blob)));
7751
8309
  }
@@ -7798,6 +8356,18 @@ function previewText(message) {
7798
8356
  function messageText(message) {
7799
8357
  return message.parts.filter((part) => part.type === "text" && part.text).map((part) => part.text).join("").trim();
7800
8358
  }
8359
+ function toEventStreamRunSummary(run, requiresUserAction) {
8360
+ return {
8361
+ id: run.id,
8362
+ status: run.status,
8363
+ assistant_message_id: run.assistant_message_id,
8364
+ requires_user_action: requiresUserAction,
8365
+ updated_at: run.completed_at ?? run.started_at
8366
+ };
8367
+ }
8368
+ function isRealtimeRunStatus(status) {
8369
+ return status === "queued" || status === "running";
8370
+ }
7801
8371
 
7802
8372
  // src/conversations/slash-commands.ts
7803
8373
  import { randomUUID as randomUUID4 } from "crypto";
@@ -10993,12 +11563,12 @@ var ConversationQueryCoordinator = class {
10993
11563
  );
10994
11564
  }
10995
11565
  const startIndex = Math.max(0, endIndex - limit);
10996
- const messages = await this.hydrateAgentEventsForMessages(
11566
+ const messages2 = await this.hydrateAgentEventsForMessages(
10997
11567
  conversationId,
10998
11568
  snapshot.messages.slice(startIndex, endIndex)
10999
11569
  );
11000
11570
  return {
11001
- messages,
11571
+ messages: messages2,
11002
11572
  last_event_seq: manifest.last_event_seq,
11003
11573
  runtime: await buildConversationRuntimeMetadata(
11004
11574
  this.deps.paths,
@@ -11009,9 +11579,10 @@ var ConversationQueryCoordinator = class {
11009
11579
  limit,
11010
11580
  has_more_before: startIndex > 0,
11011
11581
  has_more_after: endIndex < total,
11012
- oldest_message_id: messages[0]?.id ?? null,
11013
- newest_message_id: messages.at(-1)?.id ?? null
11014
- }
11582
+ oldest_message_id: messages2[0]?.id ?? null,
11583
+ newest_message_id: messages2.at(-1)?.id ?? null
11584
+ },
11585
+ event_stream: buildConversationEventStreamState(snapshot)
11015
11586
  };
11016
11587
  }
11017
11588
  async listEvents(conversationId, after = 0) {
@@ -11024,9 +11595,9 @@ var ConversationQueryCoordinator = class {
11024
11595
  profile ?? await readConversationProfileSummary(this.deps.paths, manifest)
11025
11596
  );
11026
11597
  }
11027
- async hydrateAgentEventsForMessages(conversationId, messages) {
11028
- if (!messages.some((message) => message.role === "assistant")) {
11029
- return messages;
11598
+ async hydrateAgentEventsForMessages(conversationId, messages2) {
11599
+ if (!messages2.some((message) => message.role === "assistant")) {
11600
+ return messages2;
11030
11601
  }
11031
11602
  const eventsByMessageId = /* @__PURE__ */ new Map();
11032
11603
  const events = await this.listEvents(conversationId, 0).catch(() => []);
@@ -11046,7 +11617,7 @@ var ConversationQueryCoordinator = class {
11046
11617
  )
11047
11618
  );
11048
11619
  }
11049
- return messages.map((message) => {
11620
+ return messages2.map((message) => {
11050
11621
  if (message.role !== "assistant") {
11051
11622
  return message;
11052
11623
  }
@@ -11787,10 +12358,10 @@ async function importHermesSession(input) {
11787
12358
  );
11788
12359
  const sessionId = candidate.session.id;
11789
12360
  const hermesSessionIds = lineageSessionIds(candidate);
11790
- const messages = await readHermesLineageMessages(candidate);
12361
+ const messages2 = await readHermesLineageMessages(candidate);
11791
12362
  const now = (/* @__PURE__ */ new Date()).toISOString();
11792
12363
  const createdAt = isoFromHermesTime(candidate.session.started_at) ?? now;
11793
- const updatedAt = isoFromHermesTime(candidate.session.last_active) ?? isoFromHermesTime(messages.at(-1)?.timestamp) ?? createdAt;
12364
+ const updatedAt = isoFromHermesTime(candidate.session.last_active) ?? isoFromHermesTime(messages2.at(-1)?.timestamp) ?? createdAt;
11794
12365
  const conversationId = createConversationId();
11795
12366
  const snapshot = {
11796
12367
  schema_version: 1,
@@ -11800,7 +12371,7 @@ async function importHermesSession(input) {
11800
12371
  profileUid: profile.profileUid,
11801
12372
  profileDisplayName: profile.profileDisplayName,
11802
12373
  sessionId,
11803
- messages
12374
+ messages: messages2
11804
12375
  }),
11805
12376
  runs: []
11806
12377
  };
@@ -11918,7 +12489,7 @@ async function mergeHermesCandidateIntoConversation(input) {
11918
12489
  const pureImport = isSafeHermesImportConversation(existing);
11919
12490
  const prefix = collectImportedHermesPrefix(existing.snapshot);
11920
12491
  if (pureImport || prefix?.needsUpgrade && prefix.messages.length > 0) {
11921
- const messages = pureImport ? input.candidateMessages : prefix.messages;
12492
+ const messages2 = pureImport ? input.candidateMessages : prefix.messages;
11922
12493
  nextSnapshot = {
11923
12494
  ...existing.snapshot,
11924
12495
  messages: [
@@ -11928,7 +12499,7 @@ async function mergeHermesCandidateIntoConversation(input) {
11928
12499
  profileUid: profile.profileUid,
11929
12500
  profileDisplayName: profile.profileDisplayName,
11930
12501
  sessionId: candidate.session.id,
11931
- messages
12502
+ messages: messages2
11932
12503
  }),
11933
12504
  ...pureImport ? [] : existing.snapshot.messages.slice(prefix.endIndex)
11934
12505
  ]
@@ -12868,14 +13439,14 @@ function aggregateHermesSessionUsage(rows) {
12868
13439
  async function readHermesLineageMessages(candidate) {
12869
13440
  const rows = [];
12870
13441
  for (const sessionId of lineageSessionIds(candidate)) {
12871
- const messages = await readHermesSessionMessages({
13442
+ const messages2 = await readHermesSessionMessages({
12872
13443
  ...candidate,
12873
13444
  session: {
12874
13445
  ...candidate.session,
12875
13446
  id: sessionId
12876
13447
  }
12877
13448
  });
12878
- rows.push(...messages);
13449
+ rows.push(...messages2);
12879
13450
  }
12880
13451
  return rows;
12881
13452
  }
@@ -14119,7 +14690,7 @@ async function readHermesJsonlHistory(sessionsDir, sessionId) {
14119
14690
  return empty;
14120
14691
  }
14121
14692
  const lines = raw.split(/\r?\n/u).map((line) => line.trim()).filter(Boolean);
14122
- const messages = [];
14693
+ const messages2 = [];
14123
14694
  let skippedLineCount = 0;
14124
14695
  for (const line of lines) {
14125
14696
  try {
@@ -14127,7 +14698,7 @@ async function readHermesJsonlHistory(sessionsDir, sessionId) {
14127
14698
  JSON.parse(line)
14128
14699
  );
14129
14700
  if (message) {
14130
- messages.push(message);
14701
+ messages2.push(message);
14131
14702
  } else {
14132
14703
  skippedLineCount += 1;
14133
14704
  }
@@ -14136,7 +14707,7 @@ async function readHermesJsonlHistory(sessionsDir, sessionId) {
14136
14707
  }
14137
14708
  }
14138
14709
  return {
14139
- messages,
14710
+ messages: messages2,
14140
14711
  byteCount: Buffer.byteLength(raw, "utf8"),
14141
14712
  lineCount: lines.length,
14142
14713
  skippedLineCount
@@ -14168,7 +14739,7 @@ async function readHermesSessionJsonHistory(sessionsDir, sessionId) {
14168
14739
  };
14169
14740
  }
14170
14741
  const records = Array.isArray(payload) ? payload : isRecord2(payload) && Array.isArray(payload.messages) ? payload.messages : [];
14171
- const messages = [];
14742
+ const messages2 = [];
14172
14743
  let skippedMessageCount = 0;
14173
14744
  for (const record of records) {
14174
14745
  if (!isRecord2(record)) {
@@ -14177,13 +14748,13 @@ async function readHermesSessionJsonHistory(sessionsDir, sessionId) {
14177
14748
  }
14178
14749
  const message = normalizeHistoryRecord(record);
14179
14750
  if (message) {
14180
- messages.push(message);
14751
+ messages2.push(message);
14181
14752
  } else {
14182
14753
  skippedMessageCount += 1;
14183
14754
  }
14184
14755
  }
14185
14756
  return {
14186
- messages,
14757
+ messages: messages2,
14187
14758
  byteCount: Buffer.byteLength(raw, "utf8"),
14188
14759
  skippedMessageCount
14189
14760
  };
@@ -14276,8 +14847,8 @@ function buildLinkSnapshotHistory(snapshot, run) {
14276
14847
  (message) => Boolean(message)
14277
14848
  );
14278
14849
  }
14279
- function createHistoryDiagnostics(messages, sourceReason, counts = {}) {
14280
- const replayCounts = countReplayMetadata(messages);
14850
+ function createHistoryDiagnostics(messages2, sourceReason, counts = {}) {
14851
+ const replayCounts = countReplayMetadata(messages2);
14281
14852
  return {
14282
14853
  source_reason: sourceReason,
14283
14854
  state_db_message_count: counts.state_db_message_count ?? 0,
@@ -14285,7 +14856,7 @@ function createHistoryDiagnostics(messages, sourceReason, counts = {}) {
14285
14856
  session_json_message_count: counts.session_json_message_count ?? 0,
14286
14857
  jsonl_message_count: counts.jsonl_message_count ?? 0,
14287
14858
  snapshot_message_count: counts.snapshot_message_count ?? 0,
14288
- selected_message_count: messages.length,
14859
+ selected_message_count: messages2.length,
14289
14860
  tool_message_count: replayCounts.toolMessageCount,
14290
14861
  tool_call_message_count: replayCounts.toolCallMessageCount,
14291
14862
  reasoning_message_count: replayCounts.reasoningMessageCount,
@@ -14312,11 +14883,11 @@ function pickHermesDiagnosticCounts(diagnostics) {
14312
14883
  function isRecord2(value) {
14313
14884
  return typeof value === "object" && value !== null && !Array.isArray(value);
14314
14885
  }
14315
- function countReplayMetadata(messages) {
14886
+ function countReplayMetadata(messages2) {
14316
14887
  let toolMessageCount = 0;
14317
14888
  let toolCallMessageCount = 0;
14318
14889
  let reasoningMessageCount = 0;
14319
- for (const message of messages) {
14890
+ for (const message of messages2) {
14320
14891
  if (message.role === "tool") {
14321
14892
  toolMessageCount += 1;
14322
14893
  }
@@ -15601,9 +16172,9 @@ function extractResponseAssistantText(value) {
15601
16172
  }
15602
16173
  const output = response.output;
15603
16174
  if (Array.isArray(output)) {
15604
- const messages = output.map(readResponseOutputItemText).filter((text) => Boolean(text?.trim()));
15605
- if (messages.length > 0) {
15606
- return messages.join("\n\n");
16175
+ const messages2 = output.map(readResponseOutputItemText).filter((text) => Boolean(text?.trim()));
16176
+ if (messages2.length > 0) {
16177
+ return messages2.join("\n\n");
15607
16178
  }
15608
16179
  }
15609
16180
  const choicesText = readAssistantTextFromChoices(response);
@@ -15687,11 +16258,11 @@ function readAssistantTextFromChoices(payload) {
15687
16258
  if (!Array.isArray(choices)) {
15688
16259
  return null;
15689
16260
  }
15690
- const messages = choices.map(toRecord12).map((choice) => toRecord12(choice.message ?? choice.delta)).filter((message) => {
16261
+ const messages2 = choices.map(toRecord12).map((choice) => toRecord12(choice.message ?? choice.delta)).filter((message) => {
15691
16262
  const role = readString14(message, "role");
15692
16263
  return !role || role === "assistant";
15693
16264
  }).map(readResponseMessageText).filter((text) => Boolean(text?.trim()));
15694
- return messages.length > 0 ? messages.join("\n\n") : null;
16265
+ return messages2.length > 0 ? messages2.join("\n\n") : null;
15695
16266
  }
15696
16267
  function readInteger2(payload, key) {
15697
16268
  const value = payload[key];
@@ -30010,6 +30581,10 @@ export {
30010
30581
  LINK_VERSION,
30011
30582
  LINK_COMMAND,
30012
30583
  LinkHttpError,
30584
+ detectSystemLanguage,
30585
+ resolveLanguage,
30586
+ translate,
30587
+ localizeErrorMessage,
30013
30588
  resolveHermesProfileDir,
30014
30589
  resolveHermesConfigPath,
30015
30590
  ensureHermesApiServerConfig,