@tunnelbox/core 0.1.21 → 0.1.23

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/README.md CHANGED
@@ -10,7 +10,8 @@ Shared core for tunnelbox, reused by the agent adapters:
10
10
  | `relay.ts` | `RelayClient`: outbound WS with exponential-backoff **silent** reconnect |
11
11
  | `state.ts` | State persistence (`remote-state[.type].json`, isolated per agent) + pairing files |
12
12
  | `env.ts` | `injectedRelayUrl()`: default relay injected at build time via esbuild `__TB_DEFAULT_RELAY__` (no URL literals in source) |
13
- | `qr.ts` | `printPairing`: terminal QR code + pairing code printing |
13
+ | `qr.ts` | `printPairing`: terminal QR code + pairing code printing (includes official-website download guidance) |
14
+ | `terminal.ts` | `websiteUrl()` / `hyperlink()` / `supportsHyperlinks()`: clickable OSC 8 links in supported terminals, plain URL otherwise |
14
15
 
15
16
  ## Usage
16
17
 
package/README.zh-CN.md CHANGED
@@ -10,7 +10,8 @@ tunnelbox 共享核心,供各智能体适配器复用:
10
10
  | `relay.ts` | `RelayClient`:出站 WS + 指数退避**静默**重连 |
11
11
  | `state.ts` | 状态持久化(`remote-state[.type].json`,多 agent 隔离)+ 配对文件 |
12
12
  | `env.ts` | `injectedRelayUrl()`:构建期 esbuild `__TB_DEFAULT_RELAY__` 注入的默认中继(源码无 URL 字面量) |
13
- | `qr.ts` | `printPairing`:终端二维码 + 配对码打印 |
13
+ | `qr.ts` | `printPairing`:终端二维码 + 配对码打印(含官网下载引导) |
14
+ | `terminal.ts` | `websiteUrl()` / `hyperlink()` / `supportsHyperlinks()`:支持的终端里 OSC 8 可点击链接,否则纯 URL |
14
15
 
15
16
  ## 使用
16
17
 
package/dist/index.js CHANGED
@@ -404,6 +404,7 @@ var zh_CN_default = {
404
404
  "adapter.logGatewayConnected": "\u5DF2\u8FDE\u63A5\u672C\u673A OpenClaw Gateway\uFF08{version}\uFF09",
405
405
  "adapter.logGatewayDisconnected": "\u4E0E OpenClaw Gateway \u65AD\u5F00\uFF0C\u6B63\u5728\u7531\u5B98\u65B9\u5BA2\u6237\u7AEF\u91CD\u8FDE\u2026",
406
406
  "adapter.logGatewayConnectFailed": "\u65E0\u6CD5\u8FDE\u63A5\u672C\u673A OpenClaw Gateway\uFF08\u9996\u6B21\u9700\u5728\u672C\u673A\u653E\u884C\u8BBE\u5907\uFF1A`openclaw devices list` + `openclaw devices approve <requestId>`\uFF09",
407
+ "adapter.errGatewayUnreachable": "\u65E0\u6CD5\u8FDE\u63A5\u672C\u673A OpenClaw Gateway\uFF08{url}\uFF09\uFF1A{message}\u3002\u8BF7\u786E\u8BA4 Gateway \u5DF2\u542F\u52A8\uFF08`openclaw gateway`\uFF09",
407
408
  "adapter.errGatewayNoSessionKey": "Gateway \u672A\u8FD4\u56DE\u4F1A\u8BDD key",
408
409
  "adapter.logDeleteSessionFailed": "\u5220\u9664\u4F1A\u8BDD\u5931\u8D25({session}): {message}\uFF08\u4ECD\u6309\u5DF2\u5220\u9664\u56DE\u6267\uFF09",
409
410
  "adapter.logApprovalReplyFailed": "\u5BA1\u6279\u5E94\u7B54\u5931\u8D25({id}): {message}",
@@ -458,7 +459,45 @@ var zh_CN_default = {
458
459
  "adapter.errCursorExit": "Cursor CLI \u9000\u51FA({code}): {err}",
459
460
  "adapter.errCursorSpawn": "\u65E0\u6CD5\u542F\u52A8 Cursor CLI\uFF08agent\uFF09\uFF1A\u8BF7\u786E\u8BA4\u5DF2\u5B89\u88C5\u5E76\u767B\u5F55\uFF08{message}\uFF09",
460
461
  "adapter.errCursorStart": "Cursor CLI \u542F\u52A8\u5931\u8D25: {message}",
461
- "adapter.errCursorGeneric": "Cursor \u51FA\u9519"
462
+ "adapter.errCursorGeneric": "Cursor \u51FA\u9519",
463
+ "qr.downloadApp": "\u4E0B\u8F7D tunnelbox App\uFF08Android / iOS\uFF09\uFF1A{url}",
464
+ "adapter.logLegacyHookRemoved": "\u5DF2\u79FB\u9664\u65E7\u7684 PermissionRequest hook\uFF08hooks.json\uFF09",
465
+ "adapter.errAppServerNotRunning": "codex app-server \u672A\u8FD0\u884C",
466
+ "adapter.errAppServerTimeout": "app-server \u8BF7\u6C42\u8D85\u65F6\uFF1A{method}",
467
+ "adapter.errAppServerStopped": "app-server \u5BA2\u6237\u7AEF\u5DF2\u505C\u6B62",
468
+ "adapter.errAppServerExited": "codex app-server \u9000\u51FA\uFF08code={code} signal={signal}\uFF09",
469
+ "adapter.errAppServerError": "app-server \u9519\u8BEF\uFF1A{message}",
470
+ "adapter.logAppServerStderr": "app-server\uFF1A{line}",
471
+ "adapter.logAppServerExited": "app-server \u9000\u51FA\uFF08code={code} signal={signal}\uFF09",
472
+ "adapter.errDshGenerate": "dsh \u751F\u6210\u51FA\u9519",
473
+ "adapter.unknown": "\u672A\u77E5",
474
+ "adapter.errGatewayClientMissing": "gateway client \u672A\u521B\u5EFA",
475
+ "adapter.errGatewayNotConnected": "gateway \u672A\u8FDE\u63A5",
476
+ "adapter.sessionTitleWithId": "{name} \u4F1A\u8BDD {id}",
477
+ "adapter.promptApproveTool": "{name} \u8BF7\u6C42\u6279\u51C6\u8FD0\u884C {tool}",
478
+ "index.log.serverStart": "opencode server={server} baseUrl={baseUrl} auth={auth} lang={lang}",
479
+ "agent.err.http": "HTTP {status}\uFF1A{text}",
480
+ "claude.promptUrl": "URL\uFF1A{url}",
481
+ "hermes.errBridgeNotRunning": "bridge loop \u672A\u8FD0\u884C",
482
+ "hermes.errAskNoQuestion": "\u672A\u63D0\u4F9B\u95EE\u9898\u3002\u8BF7\u4F20\u5165 questions=[{question, choices?, multi_select?}, ...]\u3002",
483
+ "hermes.toolPairDesc": "\u5411 tunnelbox \u4E2D\u7EE7\u7533\u8BF7\u4E00\u6B21\u6027\u624B\u673A\u914D\u5BF9\u7801\uFF08\u4F9B\u624B\u673A tunnelbox App \u626B\u7801/\u8F93\u7801\u914D\u5BF9\uFF09\u3002\u5F53\u7528\u6237\u8BE2\u95EE\u5982\u4F55\u7528\u624B\u673A\u8FDE\u63A5/\u914D\u5BF9/\u626B\u7801/\u8FDC\u7A0B\u63A7\u5236\u672C\u673A\u65F6\u4F7F\u7528\u3002",
484
+ "hermes.toolPairRefreshDesc": "\u662F\u5426\u5F3A\u5236\u7533\u8BF7\u65B0\u914D\u5BF9\u7801\uFF08\u9ED8\u8BA4\u590D\u7528/\u5FFD\u7565\uFF09",
485
+ "hermes.toolStatusDesc": "\u8FD4\u56DE tunnelbox \u63D2\u4EF6\u72B6\u6001\uFF1A\u4E2D\u7EE7\u5730\u5740\u3001agent \u6807\u8BC6\u3001\u662F\u5426\u5DF2\u7ED1\u5B9A\u624B\u673A\u8D26\u53F7\u3001\u6570\u636E\u76EE\u5F55\u4E0E\u6700\u8FD1\u914D\u5BF9\u4FE1\u606F\u3002\u5F53\u7528\u6237\u8BE2\u95EE\u4E0E\u624B\u673A\u7684 tunnelbox \u8FDE\u63A5\u72B6\u6001/\u662F\u5426\u7ED1\u5B9A/\u4E2D\u7EE7\u5730\u5740\u65F6\u4F7F\u7528\u3002",
486
+ "hermes.toolAskDesc": "\u628A\u4E00\u4E2A\u95EE\u9898/\u9009\u62E9\u53D1\u5230\u7528\u6237\u7684 tunnelbox \u624B\u673A\uFF08\u8FDC\u7A0B UI\uFF09\u5E76\u7B49\u5F85\u5176\u9009\u62E9\u6216\u8F93\u5165\u3002\u8FD4\u56DE JSON\uFF1A{answered: bool, user_response: string|string[]|null}\u3002\u624B\u673A\u79BB\u7EBF\u6216\u8D85\u65F6\u4F1A answered=false\u3002",
487
+ "hermes.toolAskQuestionDesc": "\u8981\u95EE\u7684\u95EE\u9898\u6587\u672C",
488
+ "hermes.toolAskChoicesDesc": "\u9884\u7F6E\u9009\u9879\uFF08\u53EF\u9009\uFF1B\u6700\u591A 4 \u4E2A\uFF09",
489
+ "hermes.toolAskMultipleDesc": "\u662F\u5426\u591A\u9009\uFF08\u9700\u63D0\u4F9B choices\uFF09",
490
+ "hermes.cmdDesc": "tunnelbox\uFF1A\u624B\u673A\u914D\u5BF9 / \u8FDE\u63A5\u72B6\u6001",
491
+ "hermes.logConfigLoadFailed": "tunnelbox: \u8BFB\u53D6\u914D\u7F6E\u5931\u8D25\uFF0C\u4F7F\u7528\u9ED8\u8BA4\u503C: {err}",
492
+ "hermes.logRegisterToolsFailed": "tunnelbox: \u6CE8\u518C\u5DE5\u5177\u5931\u8D25: {err}",
493
+ "hermes.logRegisterCommandFailed": "tunnelbox: \u6CE8\u518C\u547D\u4EE4\u5931\u8D25: {err}",
494
+ "hermes.logRegisterSkillFailed": "tunnelbox: \u6CE8\u518C\u6280\u80FD\u5931\u8D25: {err}",
495
+ "hermes.logRegisterHooksFailed": "tunnelbox: \u6CE8\u518C hooks \u5931\u8D25: {err}",
496
+ "hermes.logRegisterApprovalFailed": "tunnelbox: \u6CE8\u518C approval transport \u5931\u8D25: {err}",
497
+ "hermes.logRegisterAskFailed": "tunnelbox: \u6CE8\u518C tunnelbox_ask \u5931\u8D25: {err}",
498
+ "hermes.logRegisterSystemPromptFailed": "tunnelbox: \u6CE8\u518C system prompt \u6BB5\u5931\u8D25: {err}",
499
+ "hermes.logBackgroundBridgeFailed": "tunnelbox: \u540E\u53F0\u6865\u542F\u52A8\u5931\u8D25: {err}",
500
+ "hermes.systemPromptAsk": "\u5F53\u4F60\u9700\u8981\u7528\u6237\u505A\u51B3\u5B9A/\u6F84\u6E05/\u9009\u62E9\uFF0C\u4E14\u5DF2\u8FDE\u63A5 tunnelbox \u624B\u673A\u65F6\uFF0C\u8BF7\u7528 `tunnelbox_ask` \u5DE5\u5177\u5728\u624B\u673A\u4E0A\u63D0\u95EE\uFF0C\u800C\u4E0D\u662F\u81EA\u884C\u731C\u6D4B\uFF1B\u7B49\u5230\u7528\u6237\u4F5C\u7B54\u540E\u518D\u7EE7\u7EED\u3002"
462
501
  };
463
502
 
464
503
  // locales/zh-TW.json
@@ -713,6 +752,7 @@ var zh_TW_default = {
713
752
  "adapter.logGatewayConnected": "\u5DF2\u9023\u63A5\u672C\u6A5F OpenClaw Gateway\uFF08{version}\uFF09",
714
753
  "adapter.logGatewayDisconnected": "\u8207 OpenClaw Gateway \u65B7\u958B\uFF0C\u6B63\u5728\u7531\u5B98\u65B9\u5BA2\u6236\u7AEF\u91CD\u9023\u2026",
715
754
  "adapter.logGatewayConnectFailed": "\u7121\u6CD5\u9023\u63A5\u672C\u6A5F OpenClaw Gateway\uFF08\u9996\u6B21\u9700\u5728\u672C\u6A5F\u653E\u884C\u88DD\u7F6E\uFF1A`openclaw devices list` + `openclaw devices approve <requestId>`\uFF09",
755
+ "adapter.errGatewayUnreachable": "\u7121\u6CD5\u9023\u63A5\u672C\u6A5F OpenClaw Gateway\uFF08{url}\uFF09\uFF1A{message}\u3002\u8ACB\u78BA\u8A8D Gateway \u5DF2\u555F\u52D5\uFF08`openclaw gateway`\uFF09",
716
756
  "adapter.errGatewayNoSessionKey": "Gateway \u672A\u8FD4\u56DE\u5DE5\u4F5C\u968E\u6BB5 key",
717
757
  "adapter.logDeleteSessionFailed": "\u522A\u9664\u5DE5\u4F5C\u968E\u6BB5\u5931\u6557({session}): {message}\uFF08\u4ECD\u6309\u5DF2\u522A\u9664\u56DE\u57F7\uFF09",
718
758
  "adapter.logApprovalReplyFailed": "\u5BE9\u6279\u61C9\u7B54\u5931\u6557({id}): {message}",
@@ -767,7 +807,45 @@ var zh_TW_default = {
767
807
  "adapter.errCursorExit": "Cursor CLI \u9000\u51FA({code}): {err}",
768
808
  "adapter.errCursorSpawn": "\u7121\u6CD5\u555F\u52D5 Cursor CLI\uFF08agent\uFF09\uFF1A\u8ACB\u78BA\u8A8D\u5DF2\u5B89\u88DD\u4E26\u767B\u5165\uFF08{message}\uFF09",
769
809
  "adapter.errCursorStart": "Cursor CLI \u555F\u52D5\u5931\u6557: {message}",
770
- "adapter.errCursorGeneric": "Cursor \u51FA\u932F"
810
+ "adapter.errCursorGeneric": "Cursor \u51FA\u932F",
811
+ "qr.downloadApp": "\u4E0B\u8F09 tunnelbox App\uFF08Android / iOS\uFF09\uFF1A{url}",
812
+ "adapter.logLegacyHookRemoved": "\u5DF2\u79FB\u9664\u820A\u7684 PermissionRequest hook\uFF08hooks.json\uFF09",
813
+ "adapter.errAppServerNotRunning": "codex app-server \u672A\u57F7\u884C",
814
+ "adapter.errAppServerTimeout": "app-server \u8ACB\u6C42\u903E\u6642\uFF1A{method}",
815
+ "adapter.errAppServerStopped": "app-server \u7528\u6236\u7AEF\u5DF2\u505C\u6B62",
816
+ "adapter.errAppServerExited": "codex app-server \u7D50\u675F\uFF08code={code} signal={signal}\uFF09",
817
+ "adapter.errAppServerError": "app-server \u932F\u8AA4\uFF1A{message}",
818
+ "adapter.logAppServerStderr": "app-server\uFF1A{line}",
819
+ "adapter.logAppServerExited": "app-server \u7D50\u675F\uFF08code={code} signal={signal}\uFF09",
820
+ "adapter.errDshGenerate": "dsh \u7522\u751F\u932F\u8AA4",
821
+ "adapter.unknown": "\u672A\u77E5",
822
+ "adapter.errGatewayClientMissing": "gateway client \u672A\u5EFA\u7ACB",
823
+ "adapter.errGatewayNotConnected": "gateway \u672A\u9023\u7DDA",
824
+ "adapter.sessionTitleWithId": "{name} \u5DE5\u4F5C\u968E\u6BB5 {id}",
825
+ "adapter.promptApproveTool": "{name} \u8ACB\u6C42\u6279\u51C6\u57F7\u884C {tool}",
826
+ "index.log.serverStart": "opencode server={server} baseUrl={baseUrl} auth={auth} lang={lang}",
827
+ "agent.err.http": "HTTP {status}\uFF1A{text}",
828
+ "claude.promptUrl": "URL\uFF1A{url}",
829
+ "hermes.errBridgeNotRunning": "bridge loop \u672A\u57F7\u884C",
830
+ "hermes.errAskNoQuestion": "\u672A\u63D0\u4F9B\u554F\u984C\u3002\u8ACB\u50B3\u5165 questions=[{question, choices?, multi_select?}, ...]\u3002",
831
+ "hermes.toolPairDesc": "\u5411 tunnelbox \u4E2D\u7E7C\u7533\u8ACB\u4E00\u6B21\u6027\u624B\u6A5F\u914D\u5C0D\u78BC\uFF08\u4F9B\u624B\u6A5F tunnelbox App \u6383\u78BC/\u8F38\u78BC\u914D\u5C0D\uFF09\u3002\u7576\u4F7F\u7528\u8005\u8A62\u554F\u5982\u4F55\u7528\u624B\u6A5F\u9023\u7DDA/\u914D\u5C0D/\u6383\u78BC/\u9060\u7AEF\u63A7\u5236\u672C\u6A5F\u6642\u4F7F\u7528\u3002",
832
+ "hermes.toolPairRefreshDesc": "\u662F\u5426\u5F37\u5236\u7533\u8ACB\u65B0\u914D\u5C0D\u78BC\uFF08\u9810\u8A2D\u91CD\u7528/\u5FFD\u7565\uFF09",
833
+ "hermes.toolStatusDesc": "\u8FD4\u56DE tunnelbox \u5916\u639B\u72C0\u614B\uFF1A\u4E2D\u7E7C\u4F4D\u5740\u3001agent \u6A19\u8B58\u3001\u662F\u5426\u5DF2\u7D81\u5B9A\u624B\u6A5F\u5E33\u865F\u3001\u8CC7\u6599\u76EE\u9304\u8207\u6700\u8FD1\u914D\u5C0D\u8CC7\u8A0A\u3002\u7576\u4F7F\u7528\u8005\u8A62\u554F\u8207\u624B\u6A5F\u7684 tunnelbox \u9023\u7DDA\u72C0\u614B/\u662F\u5426\u7D81\u5B9A/\u4E2D\u7E7C\u4F4D\u5740\u6642\u4F7F\u7528\u3002",
834
+ "hermes.toolAskDesc": "\u628A\u4E00\u500B\u554F\u984C/\u9078\u64C7\u767C\u5230\u4F7F\u7528\u8005\u7684 tunnelbox \u624B\u6A5F\uFF08\u9060\u7AEF UI\uFF09\u4E26\u7B49\u5F85\u5176\u9078\u64C7\u6216\u8F38\u5165\u3002\u8FD4\u56DE JSON\uFF1A{answered: bool, user_response: string|string[]|null}\u3002\u624B\u6A5F\u96E2\u7DDA\u6216\u903E\u6642\u6703 answered=false\u3002",
835
+ "hermes.toolAskQuestionDesc": "\u8981\u554F\u7684\u554F\u984C\u6587\u5B57",
836
+ "hermes.toolAskChoicesDesc": "\u9810\u7F6E\u9078\u9805\uFF08\u53EF\u9078\uFF1B\u6700\u591A 4 \u500B\uFF09",
837
+ "hermes.toolAskMultipleDesc": "\u662F\u5426\u591A\u9078\uFF08\u9700\u63D0\u4F9B choices\uFF09",
838
+ "hermes.cmdDesc": "tunnelbox\uFF1A\u624B\u6A5F\u914D\u5C0D / \u9023\u7DDA\u72C0\u614B",
839
+ "hermes.logConfigLoadFailed": "tunnelbox: \u8B80\u53D6\u8A2D\u5B9A\u5931\u6557\uFF0C\u4F7F\u7528\u9810\u8A2D\u503C: {err}",
840
+ "hermes.logRegisterToolsFailed": "tunnelbox: \u8A3B\u518A\u5DE5\u5177\u5931\u6557: {err}",
841
+ "hermes.logRegisterCommandFailed": "tunnelbox: \u8A3B\u518A\u547D\u4EE4\u5931\u6557: {err}",
842
+ "hermes.logRegisterSkillFailed": "tunnelbox: \u8A3B\u518A\u6280\u80FD\u5931\u6557: {err}",
843
+ "hermes.logRegisterHooksFailed": "tunnelbox: \u8A3B\u518A hooks \u5931\u6557: {err}",
844
+ "hermes.logRegisterApprovalFailed": "tunnelbox: \u8A3B\u518A approval transport \u5931\u6557: {err}",
845
+ "hermes.logRegisterAskFailed": "tunnelbox: \u8A3B\u518A tunnelbox_ask \u5931\u6557: {err}",
846
+ "hermes.logRegisterSystemPromptFailed": "tunnelbox: \u8A3B\u518A system prompt \u6BB5\u5931\u6557: {err}",
847
+ "hermes.logBackgroundBridgeFailed": "tunnelbox: \u80CC\u666F\u6A4B\u555F\u52D5\u5931\u6557: {err}",
848
+ "hermes.systemPromptAsk": "\u7576\u4F60\u9700\u8981\u4F7F\u7528\u8005\u505A\u6C7A\u5B9A/\u6F84\u6E05/\u9078\u64C7\uFF0C\u4E14\u5DF2\u9023\u63A5 tunnelbox \u624B\u6A5F\u6642\uFF0C\u8ACB\u7528 `tunnelbox_ask` \u5DE5\u5177\u5728\u624B\u6A5F\u4E0A\u63D0\u554F\uFF0C\u800C\u4E0D\u662F\u81EA\u884C\u731C\u6E2C\uFF1B\u7B49\u5230\u4F7F\u7528\u8005\u4F5C\u7B54\u5F8C\u518D\u7E7C\u7E8C\u3002"
771
849
  };
772
850
 
773
851
  // locales/en-US.json
@@ -1022,6 +1100,7 @@ var en_US_default = {
1022
1100
  "adapter.logGatewayConnected": "Connected to local OpenClaw Gateway ({version})",
1023
1101
  "adapter.logGatewayDisconnected": "Disconnected from OpenClaw Gateway; the official client is reconnecting\u2026",
1024
1102
  "adapter.logGatewayConnectFailed": "Cannot connect to local OpenClaw Gateway (first time, approve the device locally: `openclaw devices list` + `openclaw devices approve <requestId>`)",
1103
+ "adapter.errGatewayUnreachable": "Cannot reach the local OpenClaw Gateway ({url}): {message}. Make sure it is running (`openclaw gateway`)",
1025
1104
  "adapter.errGatewayNoSessionKey": "Gateway did not return a session key",
1026
1105
  "adapter.logDeleteSessionFailed": "Failed to delete session ({session}): {message} (still acking as deleted)",
1027
1106
  "adapter.logApprovalReplyFailed": "Approval reply failed ({id}): {message}",
@@ -1076,7 +1155,45 @@ var en_US_default = {
1076
1155
  "adapter.errCursorExit": "Cursor CLI exited ({code}): {err}",
1077
1156
  "adapter.errCursorSpawn": "Cannot start Cursor CLI (agent): make sure it is installed and logged in ({message})",
1078
1157
  "adapter.errCursorStart": "Cursor CLI failed to start: {message}",
1079
- "adapter.errCursorGeneric": "Cursor error"
1158
+ "adapter.errCursorGeneric": "Cursor error",
1159
+ "qr.downloadApp": "Download the tunnelbox App (Android / iOS): {url}",
1160
+ "adapter.logLegacyHookRemoved": "Removed the legacy PermissionRequest hook (hooks.json)",
1161
+ "adapter.errAppServerNotRunning": "codex app-server is not running",
1162
+ "adapter.errAppServerTimeout": "app-server request timed out: {method}",
1163
+ "adapter.errAppServerStopped": "app-server client stopped",
1164
+ "adapter.errAppServerExited": "codex app-server exited (code={code} signal={signal})",
1165
+ "adapter.errAppServerError": "app-server error: {message}",
1166
+ "adapter.logAppServerStderr": "app-server: {line}",
1167
+ "adapter.logAppServerExited": "app-server exited (code={code} signal={signal})",
1168
+ "adapter.errDshGenerate": "dsh generation error",
1169
+ "adapter.unknown": "unknown",
1170
+ "adapter.errGatewayClientMissing": "gateway client not created",
1171
+ "adapter.errGatewayNotConnected": "gateway not connected",
1172
+ "adapter.sessionTitleWithId": "{name} session {id}",
1173
+ "adapter.promptApproveTool": "{name} requests approval to run {tool}",
1174
+ "index.log.serverStart": "opencode server={server} baseUrl={baseUrl} auth={auth} lang={lang}",
1175
+ "agent.err.http": "HTTP {status}: {text}",
1176
+ "claude.promptUrl": "URL: {url}",
1177
+ "hermes.errBridgeNotRunning": "bridge loop is not running",
1178
+ "hermes.errAskNoQuestion": "No question provided. Pass questions=[{question, choices?, multi_select?}, ...].",
1179
+ "hermes.toolPairDesc": "Request a one-time phone pairing code from the tunnelbox relay (for scanning/entering in the tunnelbox app). Use when the user asks how to connect/pair/scan or remotely control this machine from their phone.",
1180
+ "hermes.toolPairRefreshDesc": "Force requesting a new pairing code (default: reuse/ignore)",
1181
+ "hermes.toolStatusDesc": "Return tunnelbox plugin status: relay address, agent id, whether bound to a phone account, data directory, and latest pairing info. Use when the user asks about the phone connection status/binding/relay address.",
1182
+ "hermes.toolAskDesc": "Send a question/choice to the user's tunnelbox phone (remote UI) and wait for their selection or input. Returns JSON: {answered: bool, user_response: string|string[]|null}. If the phone is offline or times out, answered=false.",
1183
+ "hermes.toolAskQuestionDesc": "The question text to ask",
1184
+ "hermes.toolAskChoicesDesc": "Preset options (optional; up to 4)",
1185
+ "hermes.toolAskMultipleDesc": "Allow multiple selection (requires choices)",
1186
+ "hermes.cmdDesc": "tunnelbox: phone pairing / connection status",
1187
+ "hermes.logConfigLoadFailed": "tunnelbox: failed to read config, using defaults: {err}",
1188
+ "hermes.logRegisterToolsFailed": "tunnelbox: failed to register tools: {err}",
1189
+ "hermes.logRegisterCommandFailed": "tunnelbox: failed to register command: {err}",
1190
+ "hermes.logRegisterSkillFailed": "tunnelbox: failed to register skill: {err}",
1191
+ "hermes.logRegisterHooksFailed": "tunnelbox: failed to register hooks: {err}",
1192
+ "hermes.logRegisterApprovalFailed": "tunnelbox: failed to register approval transport: {err}",
1193
+ "hermes.logRegisterAskFailed": "tunnelbox: failed to register tunnelbox_ask: {err}",
1194
+ "hermes.logRegisterSystemPromptFailed": "tunnelbox: failed to register system prompt section: {err}",
1195
+ "hermes.logBackgroundBridgeFailed": "tunnelbox: background bridge failed to start: {err}",
1196
+ "hermes.systemPromptAsk": "When you need a decision, clarification, or choice from the user and a tunnelbox phone is attached, use the `tunnelbox_ask` tool to ask on their phone instead of guessing. Wait for their answer before proceeding."
1080
1197
  };
1081
1198
 
1082
1199
  // locales/ja-JP.json
@@ -1331,6 +1448,7 @@ var ja_JP_default = {
1331
1448
  "adapter.logGatewayConnected": "\u30ED\u30FC\u30AB\u30EB OpenClaw Gateway \u306B\u63A5\u7D9A\u3057\u307E\u3057\u305F\uFF08{version}\uFF09",
1332
1449
  "adapter.logGatewayDisconnected": "OpenClaw Gateway \u304B\u3089\u5207\u65AD\u3055\u308C\u307E\u3057\u305F\u3002\u516C\u5F0F\u30AF\u30E9\u30A4\u30A2\u30F3\u30C8\u304C\u518D\u63A5\u7D9A\u3057\u3066\u3044\u307E\u3059\u2026",
1333
1450
  "adapter.logGatewayConnectFailed": "\u30ED\u30FC\u30AB\u30EB OpenClaw Gateway \u306B\u63A5\u7D9A\u3067\u304D\u307E\u305B\u3093\uFF08\u521D\u56DE\u306F\u672C\u6A5F\u3067\u30C7\u30D0\u30A4\u30B9\u3092\u627F\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044: `openclaw devices list` + `openclaw devices approve <requestId>`\uFF09",
1451
+ "adapter.errGatewayUnreachable": "\u30ED\u30FC\u30AB\u30EB\u306E OpenClaw Gateway\uFF08{url}\uFF09\u306B\u63A5\u7D9A\u3067\u304D\u307E\u305B\u3093: {message}\u3002Gateway \u304C\u8D77\u52D5\u3057\u3066\u3044\u308B\u3053\u3068\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\uFF08`openclaw gateway`\uFF09",
1334
1452
  "adapter.errGatewayNoSessionKey": "Gateway \u304C\u30BB\u30C3\u30B7\u30E7\u30F3 key \u3092\u8FD4\u3057\u307E\u305B\u3093\u3067\u3057\u305F",
1335
1453
  "adapter.logDeleteSessionFailed": "\u30BB\u30C3\u30B7\u30E7\u30F3\u306E\u524A\u9664\u306B\u5931\u6557\u3057\u307E\u3057\u305F ({session}): {message}\uFF08\u524A\u9664\u6E08\u307F\u3068\u3057\u3066\u5FDC\u7B54\uFF09",
1336
1454
  "adapter.logApprovalReplyFailed": "\u627F\u8A8D\u5FDC\u7B54\u306B\u5931\u6557\u3057\u307E\u3057\u305F ({id}): {message}",
@@ -1385,7 +1503,45 @@ var ja_JP_default = {
1385
1503
  "adapter.errCursorExit": "Cursor CLI \u304C\u7D42\u4E86\u3057\u307E\u3057\u305F\uFF08{code}\uFF09: {err}",
1386
1504
  "adapter.errCursorSpawn": "Cursor CLI\uFF08agent\uFF09\u3092\u8D77\u52D5\u3067\u304D\u307E\u305B\u3093\u3002\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB\u3068\u30ED\u30B0\u30A4\u30F3\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\uFF08{message}\uFF09",
1387
1505
  "adapter.errCursorStart": "Cursor CLI \u306E\u8D77\u52D5\u306B\u5931\u6557\u3057\u307E\u3057\u305F: {message}",
1388
- "adapter.errCursorGeneric": "Cursor \u30A8\u30E9\u30FC"
1506
+ "adapter.errCursorGeneric": "Cursor \u30A8\u30E9\u30FC",
1507
+ "qr.downloadApp": "tunnelbox App\uFF08Android / iOS\uFF09\u3092\u30C0\u30A6\u30F3\u30ED\u30FC\u30C9: {url}",
1508
+ "adapter.logLegacyHookRemoved": "\u65E7 PermissionRequest hook\uFF08hooks.json\uFF09\u3092\u524A\u9664\u3057\u307E\u3057\u305F",
1509
+ "adapter.errAppServerNotRunning": "codex app-server \u304C\u5B9F\u884C\u3055\u308C\u3066\u3044\u307E\u305B\u3093",
1510
+ "adapter.errAppServerTimeout": "app-server \u30EA\u30AF\u30A8\u30B9\u30C8\u304C\u30BF\u30A4\u30E0\u30A2\u30A6\u30C8\u3057\u307E\u3057\u305F: {method}",
1511
+ "adapter.errAppServerStopped": "app-server \u30AF\u30E9\u30A4\u30A2\u30F3\u30C8\u304C\u505C\u6B62\u3057\u307E\u3057\u305F",
1512
+ "adapter.errAppServerExited": "codex app-server \u304C\u7D42\u4E86\u3057\u307E\u3057\u305F\uFF08code={code} signal={signal}\uFF09",
1513
+ "adapter.errAppServerError": "app-server \u30A8\u30E9\u30FC: {message}",
1514
+ "adapter.logAppServerStderr": "app-server: {line}",
1515
+ "adapter.logAppServerExited": "app-server \u304C\u7D42\u4E86\u3057\u307E\u3057\u305F\uFF08code={code} signal={signal}\uFF09",
1516
+ "adapter.errDshGenerate": "dsh \u306E\u751F\u6210\u30A8\u30E9\u30FC",
1517
+ "adapter.unknown": "\u4E0D\u660E",
1518
+ "adapter.errGatewayClientMissing": "gateway \u30AF\u30E9\u30A4\u30A2\u30F3\u30C8\u304C\u4F5C\u6210\u3055\u308C\u3066\u3044\u307E\u305B\u3093",
1519
+ "adapter.errGatewayNotConnected": "gateway \u306B\u63A5\u7D9A\u3055\u308C\u3066\u3044\u307E\u305B\u3093",
1520
+ "adapter.sessionTitleWithId": "{name} \u30BB\u30C3\u30B7\u30E7\u30F3 {id}",
1521
+ "adapter.promptApproveTool": "{name} \u304C {tool} \u306E\u5B9F\u884C\u627F\u8A8D\u3092\u8981\u6C42\u3057\u3066\u3044\u307E\u3059",
1522
+ "index.log.serverStart": "opencode server={server} baseUrl={baseUrl} auth={auth} lang={lang}",
1523
+ "agent.err.http": "HTTP {status}: {text}",
1524
+ "claude.promptUrl": "URL: {url}",
1525
+ "hermes.errBridgeNotRunning": "bridge \u30EB\u30FC\u30D7\u304C\u5B9F\u884C\u3055\u308C\u3066\u3044\u307E\u305B\u3093",
1526
+ "hermes.errAskNoQuestion": "\u8CEA\u554F\u304C\u6307\u5B9A\u3055\u308C\u3066\u3044\u307E\u305B\u3093\u3002questions=[{question, choices?, multi_select?}, ...] \u3092\u6E21\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
1527
+ "hermes.toolPairDesc": "tunnelbox \u30EA\u30EC\u30FC\u304B\u3089\u4E00\u5EA6\u9650\u308A\u306E\u30B9\u30DE\u30DB\u30DA\u30A2\u30EA\u30F3\u30B0\u30B3\u30FC\u30C9\u3092\u53D6\u5F97\u3057\u307E\u3059\uFF08tunnelbox App \u3067\u306E\u30B9\u30AD\u30E3\u30F3/\u5165\u529B\u7528\uFF09\u3002\u30B9\u30DE\u30DB\u304B\u3089\u306E\u63A5\u7D9A/\u30DA\u30A2\u30EA\u30F3\u30B0/\u30B9\u30AD\u30E3\u30F3\u65B9\u6CD5\u3084\u672C\u6A5F\u306E\u30EA\u30E2\u30FC\u30C8\u64CD\u4F5C\u306B\u3064\u3044\u3066\u5C0B\u306D\u3089\u308C\u305F\u3068\u304D\u306B\u4F7F\u7528\u3057\u307E\u3059\u3002",
1528
+ "hermes.toolPairRefreshDesc": "\u65B0\u3057\u3044\u30DA\u30A2\u30EA\u30F3\u30B0\u30B3\u30FC\u30C9\u3092\u5F37\u5236\u7684\u306B\u8981\u6C42\u3059\u308B\u304B\uFF08\u65E2\u5B9A: \u518D\u5229\u7528/\u7121\u8996\uFF09",
1529
+ "hermes.toolStatusDesc": "tunnelbox \u30D7\u30E9\u30B0\u30A4\u30F3\u306E\u72B6\u614B\u3092\u8FD4\u3057\u307E\u3059: \u30EA\u30EC\u30FC\u30A2\u30C9\u30EC\u30B9\u3001agent id\u3001\u30B9\u30DE\u30DB\u30A2\u30AB\u30A6\u30F3\u30C8\u3078\u306E\u30D0\u30A4\u30F3\u30C9\u6709\u7121\u3001\u30C7\u30FC\u30BF\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u3001\u6700\u65B0\u306E\u30DA\u30A2\u30EA\u30F3\u30B0\u60C5\u5831\u3002\u30B9\u30DE\u30DB\u63A5\u7D9A\u72B6\u614B/\u30D0\u30A4\u30F3\u30C9/\u30EA\u30EC\u30FC\u30A2\u30C9\u30EC\u30B9\u306B\u3064\u3044\u3066\u5C0B\u306D\u3089\u308C\u305F\u3068\u304D\u306B\u4F7F\u7528\u3057\u307E\u3059\u3002",
1530
+ "hermes.toolAskDesc": "\u8CEA\u554F/\u9078\u629E\u3092\u30E6\u30FC\u30B6\u30FC\u306E tunnelbox \u30B9\u30DE\u30DB\uFF08\u30EA\u30E2\u30FC\u30C8 UI\uFF09\u306B\u9001\u308A\u3001\u9078\u629E\u307E\u305F\u306F\u5165\u529B\u304C\u3042\u308B\u307E\u3067\u5F85\u3061\u307E\u3059\u3002JSON \u3092\u8FD4\u3057\u307E\u3059: {answered: bool, user_response: string|string[]|null}\u3002\u30B9\u30DE\u30DB\u304C\u30AA\u30D5\u30E9\u30A4\u30F3\u307E\u305F\u306F\u30BF\u30A4\u30E0\u30A2\u30A6\u30C8\u306E\u5834\u5408\u306F answered=false\u3002",
1531
+ "hermes.toolAskQuestionDesc": "\u5C0B\u306D\u308B\u8CEA\u554F\u30C6\u30AD\u30B9\u30C8",
1532
+ "hermes.toolAskChoicesDesc": "\u30D7\u30EA\u30BB\u30C3\u30C8\u9078\u629E\u80A2\uFF08\u4EFB\u610F\u3001\u6700\u5927 4 \u3064\uFF09",
1533
+ "hermes.toolAskMultipleDesc": "\u8907\u6570\u9078\u629E\u3092\u8A31\u53EF\uFF08choices \u304C\u5FC5\u8981\uFF09",
1534
+ "hermes.cmdDesc": "tunnelbox: \u30B9\u30DE\u30DB\u30DA\u30A2\u30EA\u30F3\u30B0 / \u63A5\u7D9A\u72B6\u614B",
1535
+ "hermes.logConfigLoadFailed": "tunnelbox: \u8A2D\u5B9A\u306E\u8AAD\u307F\u8FBC\u307F\u306B\u5931\u6557\u3001\u65E2\u5B9A\u5024\u3092\u4F7F\u7528: {err}",
1536
+ "hermes.logRegisterToolsFailed": "tunnelbox: \u30C4\u30FC\u30EB\u306E\u767B\u9332\u306B\u5931\u6557: {err}",
1537
+ "hermes.logRegisterCommandFailed": "tunnelbox: \u30B3\u30DE\u30F3\u30C9\u306E\u767B\u9332\u306B\u5931\u6557: {err}",
1538
+ "hermes.logRegisterSkillFailed": "tunnelbox: \u30B9\u30AD\u30EB\u306E\u767B\u9332\u306B\u5931\u6557: {err}",
1539
+ "hermes.logRegisterHooksFailed": "tunnelbox: hooks \u306E\u767B\u9332\u306B\u5931\u6557: {err}",
1540
+ "hermes.logRegisterApprovalFailed": "tunnelbox: approval transport \u306E\u767B\u9332\u306B\u5931\u6557: {err}",
1541
+ "hermes.logRegisterAskFailed": "tunnelbox: tunnelbox_ask \u306E\u767B\u9332\u306B\u5931\u6557: {err}",
1542
+ "hermes.logRegisterSystemPromptFailed": "tunnelbox: system prompt \u30BB\u30AF\u30B7\u30E7\u30F3\u306E\u767B\u9332\u306B\u5931\u6557: {err}",
1543
+ "hermes.logBackgroundBridgeFailed": "tunnelbox: \u30D0\u30C3\u30AF\u30B0\u30E9\u30A6\u30F3\u30C9\u30D6\u30EA\u30C3\u30B8\u306E\u8D77\u52D5\u306B\u5931\u6557: {err}",
1544
+ "hermes.systemPromptAsk": "\u30E6\u30FC\u30B6\u30FC\u306B\u6C7A\u5B9A/\u78BA\u8A8D/\u9078\u629E\u3092\u6C42\u3081\u308B\u5FC5\u8981\u304C\u3042\u308A\u3001tunnelbox \u30B9\u30DE\u30DB\u304C\u63A5\u7D9A\u3055\u308C\u3066\u3044\u308B\u5834\u5408\u306F\u3001\u63A8\u6E2C\u305B\u305A `tunnelbox_ask` \u30C4\u30FC\u30EB\u3067\u30B9\u30DE\u30DB\u306B\u8CEA\u554F\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u56DE\u7B54\u304C\u3042\u308B\u307E\u3067\u5F85\u3063\u3066\u304B\u3089\u7D9A\u884C\u3057\u307E\u3059\u3002"
1389
1545
  };
1390
1546
 
1391
1547
  // locales/ko-KR.json
@@ -1640,6 +1796,7 @@ var ko_KR_default = {
1640
1796
  "adapter.logGatewayConnected": "\uB85C\uCEEC OpenClaw Gateway\uC5D0 \uC5F0\uACB0\uB428({version})",
1641
1797
  "adapter.logGatewayDisconnected": "OpenClaw Gateway\uC640 \uC5F0\uACB0\uC774 \uB04A\uC5B4\uC84C\uC2B5\uB2C8\uB2E4. \uACF5\uC2DD \uD074\uB77C\uC774\uC5B8\uD2B8\uAC00 \uC7AC\uC5F0\uACB0 \uC911\u2026",
1642
1798
  "adapter.logGatewayConnectFailed": "\uB85C\uCEEC OpenClaw Gateway\uC5D0 \uC5F0\uACB0\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4(\uCD5C\uCD08\uC5D0\uB294 \uB85C\uCEEC\uC5D0\uC11C \uC7A5\uCE58\uB97C \uC2B9\uC778\uD558\uC138\uC694: `openclaw devices list` + `openclaw devices approve <requestId>`)",
1799
+ "adapter.errGatewayUnreachable": "\uB85C\uCEEC OpenClaw Gateway({url})\uC5D0 \uC5F0\uACB0\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: {message}. Gateway\uAC00 \uC2E4\uD589 \uC911\uC778\uC9C0 \uD655\uC778\uD558\uC138\uC694(`openclaw gateway`)",
1643
1800
  "adapter.errGatewayNoSessionKey": "Gateway\uAC00 \uC138\uC158 key\uB97C \uBC18\uD658\uD558\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4",
1644
1801
  "adapter.logDeleteSessionFailed": "\uC138\uC158 \uC0AD\uC81C \uC2E4\uD328({session}): {message}(\uC0AD\uC81C\uB428\uC73C\uB85C \uC751\uB2F5)",
1645
1802
  "adapter.logApprovalReplyFailed": "\uC2B9\uC778 \uC751\uB2F5 \uC2E4\uD328({id}): {message}",
@@ -1694,7 +1851,45 @@ var ko_KR_default = {
1694
1851
  "adapter.errCursorExit": "Cursor CLI \uC885\uB8CC({code}): {err}",
1695
1852
  "adapter.errCursorSpawn": "Cursor CLI(agent)\uB97C \uC2DC\uC791\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \uC124\uCE58 \uBC0F \uB85C\uADF8\uC778\uC744 \uD655\uC778\uD558\uC138\uC694({message})",
1696
1853
  "adapter.errCursorStart": "Cursor CLI \uC2DC\uC791 \uC2E4\uD328: {message}",
1697
- "adapter.errCursorGeneric": "Cursor \uC624\uB958"
1854
+ "adapter.errCursorGeneric": "Cursor \uC624\uB958",
1855
+ "qr.downloadApp": "tunnelbox \uC571(Android / iOS) \uB2E4\uC6B4\uB85C\uB4DC: {url}",
1856
+ "adapter.logLegacyHookRemoved": "\uC774\uC804 PermissionRequest hook(hooks.json)\uC744 \uC81C\uAC70\uD588\uC2B5\uB2C8\uB2E4",
1857
+ "adapter.errAppServerNotRunning": "codex app-server\uAC00 \uC2E4\uD589 \uC911\uC774 \uC544\uB2D9\uB2C8\uB2E4",
1858
+ "adapter.errAppServerTimeout": "app-server \uC694\uCCAD \uC2DC\uAC04 \uCD08\uACFC: {method}",
1859
+ "adapter.errAppServerStopped": "app-server \uD074\uB77C\uC774\uC5B8\uD2B8\uAC00 \uC911\uC9C0\uB418\uC5C8\uC2B5\uB2C8\uB2E4",
1860
+ "adapter.errAppServerExited": "codex app-server \uC885\uB8CC(code={code} signal={signal})",
1861
+ "adapter.errAppServerError": "app-server \uC624\uB958: {message}",
1862
+ "adapter.logAppServerStderr": "app-server: {line}",
1863
+ "adapter.logAppServerExited": "app-server \uC885\uB8CC(code={code} signal={signal})",
1864
+ "adapter.errDshGenerate": "dsh \uC0DD\uC131 \uC624\uB958",
1865
+ "adapter.unknown": "\uC54C \uC218 \uC5C6\uC74C",
1866
+ "adapter.errGatewayClientMissing": "gateway \uD074\uB77C\uC774\uC5B8\uD2B8\uAC00 \uC0DD\uC131\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4",
1867
+ "adapter.errGatewayNotConnected": "gateway\uC5D0 \uC5F0\uACB0\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4",
1868
+ "adapter.sessionTitleWithId": "{name} \uC138\uC158 {id}",
1869
+ "adapter.promptApproveTool": "{name}\uC774(\uAC00) {tool} \uC2E4\uD589 \uC2B9\uC778\uC744 \uC694\uCCAD\uD569\uB2C8\uB2E4",
1870
+ "index.log.serverStart": "opencode server={server} baseUrl={baseUrl} auth={auth} lang={lang}",
1871
+ "agent.err.http": "HTTP {status}: {text}",
1872
+ "claude.promptUrl": "URL: {url}",
1873
+ "hermes.errBridgeNotRunning": "bridge \uB8E8\uD504\uAC00 \uC2E4\uD589 \uC911\uC774 \uC544\uB2D9\uB2C8\uB2E4",
1874
+ "hermes.errAskNoQuestion": "\uC9C8\uBB38\uC774 \uC81C\uACF5\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. questions=[{question, choices?, multi_select?}, ...]\uB97C \uC804\uB2EC\uD558\uC138\uC694.",
1875
+ "hermes.toolPairDesc": "tunnelbox \uB9B4\uB808\uC774\uC5D0\uC11C \uC77C\uD68C\uC6A9 \uD734\uB300\uD3F0 \uD398\uC5B4\uB9C1 \uCF54\uB4DC\uB97C \uC694\uCCAD\uD569\uB2C8\uB2E4(tunnelbox \uC571\uC5D0\uC11C \uC2A4\uCE94/\uC785\uB825\uC6A9). \uC0AC\uC6A9\uC790\uAC00 \uD734\uB300\uD3F0\uC73C\uB85C \uC5F0\uACB0/\uD398\uC5B4\uB9C1/\uC2A4\uCE94 \uBC29\uBC95\uC774\uB098 \uC774 \uCEF4\uD4E8\uD130\uC758 \uC6D0\uACA9 \uC81C\uC5B4\uB97C \uBB3C\uC744 \uB54C \uC0AC\uC6A9\uD558\uC138\uC694.",
1876
+ "hermes.toolPairRefreshDesc": "\uC0C8 \uD398\uC5B4\uB9C1 \uCF54\uB4DC\uB97C \uAC15\uC81C\uB85C \uC694\uCCAD\uD560\uC9C0 \uC5EC\uBD80(\uAE30\uBCF8: \uC7AC\uC0AC\uC6A9/\uBB34\uC2DC)",
1877
+ "hermes.toolStatusDesc": "tunnelbox \uD50C\uB7EC\uADF8\uC778 \uC0C1\uD0DC\uB97C \uBC18\uD658\uD569\uB2C8\uB2E4: \uB9B4\uB808\uC774 \uC8FC\uC18C, agent id, \uD734\uB300\uD3F0 \uACC4\uC815 \uBC14\uC778\uB529 \uC5EC\uBD80, \uB370\uC774\uD130 \uB514\uB809\uD130\uB9AC, \uCD5C\uADFC \uD398\uC5B4\uB9C1 \uC815\uBCF4. \uD734\uB300\uD3F0 \uC5F0\uACB0 \uC0C1\uD0DC/\uBC14\uC778\uB529/\uB9B4\uB808\uC774 \uC8FC\uC18C\uB97C \uBB3C\uC744 \uB54C \uC0AC\uC6A9\uD558\uC138\uC694.",
1878
+ "hermes.toolAskDesc": "\uC9C8\uBB38/\uC120\uD0DD\uC744 \uC0AC\uC6A9\uC790\uC758 tunnelbox \uD734\uB300\uD3F0(\uC6D0\uACA9 UI)\uC73C\uB85C \uBCF4\uB0B4\uACE0 \uC120\uD0DD \uB610\uB294 \uC785\uB825\uC744 \uAE30\uB2E4\uB9BD\uB2C8\uB2E4. JSON \uBC18\uD658: {answered: bool, user_response: string|string[]|null}. \uD734\uB300\uD3F0\uC774 \uC624\uD504\uB77C\uC778\uC774\uAC70\uB098 \uC2DC\uAC04 \uCD08\uACFC\uBA74 answered=false.",
1879
+ "hermes.toolAskQuestionDesc": "\uC9C8\uBB38 \uD14D\uC2A4\uD2B8",
1880
+ "hermes.toolAskChoicesDesc": "\uC0AC\uC804 \uC124\uC815 \uC120\uD0DD\uC9C0(\uC120\uD0DD, \uCD5C\uB300 4\uAC1C)",
1881
+ "hermes.toolAskMultipleDesc": "\uB2E4\uC911 \uC120\uD0DD \uD5C8\uC6A9(choices \uD544\uC694)",
1882
+ "hermes.cmdDesc": "tunnelbox: \uD734\uB300\uD3F0 \uD398\uC5B4\uB9C1 / \uC5F0\uACB0 \uC0C1\uD0DC",
1883
+ "hermes.logConfigLoadFailed": "tunnelbox: \uC124\uC815 \uC77D\uAE30 \uC2E4\uD328, \uAE30\uBCF8\uAC12 \uC0AC\uC6A9: {err}",
1884
+ "hermes.logRegisterToolsFailed": "tunnelbox: \uB3C4\uAD6C \uB4F1\uB85D \uC2E4\uD328: {err}",
1885
+ "hermes.logRegisterCommandFailed": "tunnelbox: \uBA85\uB839 \uB4F1\uB85D \uC2E4\uD328: {err}",
1886
+ "hermes.logRegisterSkillFailed": "tunnelbox: \uC2A4\uD0AC \uB4F1\uB85D \uC2E4\uD328: {err}",
1887
+ "hermes.logRegisterHooksFailed": "tunnelbox: hooks \uB4F1\uB85D \uC2E4\uD328: {err}",
1888
+ "hermes.logRegisterApprovalFailed": "tunnelbox: approval transport \uB4F1\uB85D \uC2E4\uD328: {err}",
1889
+ "hermes.logRegisterAskFailed": "tunnelbox: tunnelbox_ask \uB4F1\uB85D \uC2E4\uD328: {err}",
1890
+ "hermes.logRegisterSystemPromptFailed": "tunnelbox: system prompt \uC139\uC158 \uB4F1\uB85D \uC2E4\uD328: {err}",
1891
+ "hermes.logBackgroundBridgeFailed": "tunnelbox: \uBC31\uADF8\uB77C\uC6B4\uB4DC \uBE0C\uB9AC\uC9C0 \uC2DC\uC791 \uC2E4\uD328: {err}",
1892
+ "hermes.systemPromptAsk": "\uC0AC\uC6A9\uC790\uC5D0\uAC8C \uACB0\uC815/\uD655\uC778/\uC120\uD0DD\uC774 \uD544\uC694\uD558\uACE0 tunnelbox \uD734\uB300\uD3F0\uC774 \uC5F0\uACB0\uB418\uC5B4 \uC788\uC73C\uBA74 \uCD94\uCE21\uD558\uC9C0 \uB9D0\uACE0 `tunnelbox_ask` \uB3C4\uAD6C\uB85C \uD734\uB300\uD3F0\uC5D0\uC11C \uC9C8\uBB38\uD558\uC138\uC694. \uC0AC\uC6A9\uC790\uAC00 \uB2F5\uD560 \uB54C\uAE4C\uC9C0 \uAE30\uB2E4\uB9B0 \uD6C4 \uC9C4\uD589\uD558\uC138\uC694."
1698
1893
  };
1699
1894
 
1700
1895
  // locales/fr-FR.json
@@ -1949,6 +2144,7 @@ var fr_FR_default = {
1949
2144
  "adapter.logGatewayConnected": "Connect\xE9 au Gateway OpenClaw local ({version})",
1950
2145
  "adapter.logGatewayDisconnected": "D\xE9connect\xE9 du Gateway OpenClaw ; le client officiel se reconnecte\u2026",
1951
2146
  "adapter.logGatewayConnectFailed": "Impossible de se connecter au Gateway OpenClaw local (la premi\xE8re fois, approuvez l'appareil en local : `openclaw devices list` + `openclaw devices approve <requestId>`)",
2147
+ "adapter.errGatewayUnreachable": "Impossible de joindre le Gateway OpenClaw local ({url}) : {message}. V\xE9rifiez qu'il est d\xE9marr\xE9 (`openclaw gateway`)",
1952
2148
  "adapter.errGatewayNoSessionKey": "Le Gateway n'a pas renvoy\xE9 de cl\xE9 de session",
1953
2149
  "adapter.logDeleteSessionFailed": "\xC9chec de suppression de session ({session}) : {message} (accus\xE9 de suppression tout de m\xEAme)",
1954
2150
  "adapter.logApprovalReplyFailed": "\xC9chec de la r\xE9ponse d'approbation ({id}) : {message}",
@@ -2003,7 +2199,45 @@ var fr_FR_default = {
2003
2199
  "adapter.errCursorExit": "Cursor CLI arr\xEAt\xE9 ({code}) : {err}",
2004
2200
  "adapter.errCursorSpawn": "Impossible de d\xE9marrer Cursor CLI (agent) : v\xE9rifiez qu'il est install\xE9 et connect\xE9 ({message})",
2005
2201
  "adapter.errCursorStart": "\xC9chec du d\xE9marrage de Cursor CLI : {message}",
2006
- "adapter.errCursorGeneric": "Erreur Cursor"
2202
+ "adapter.errCursorGeneric": "Erreur Cursor",
2203
+ "qr.downloadApp": "T\xE9l\xE9charger l'application tunnelbox (Android / iOS) : {url}",
2204
+ "adapter.logLegacyHookRemoved": "Ancien hook PermissionRequest supprim\xE9 (hooks.json)",
2205
+ "adapter.errAppServerNotRunning": "codex app-server n'est pas en cours d'ex\xE9cution",
2206
+ "adapter.errAppServerTimeout": "D\xE9lai d\xE9pass\xE9 pour la requ\xEAte app-server : {method}",
2207
+ "adapter.errAppServerStopped": "Client app-server arr\xEAt\xE9",
2208
+ "adapter.errAppServerExited": "codex app-server arr\xEAt\xE9 (code={code} signal={signal})",
2209
+ "adapter.errAppServerError": "Erreur app-server : {message}",
2210
+ "adapter.logAppServerStderr": "app-server : {line}",
2211
+ "adapter.logAppServerExited": "app-server arr\xEAt\xE9 (code={code} signal={signal})",
2212
+ "adapter.errDshGenerate": "Erreur de g\xE9n\xE9ration dsh",
2213
+ "adapter.unknown": "inconnu",
2214
+ "adapter.errGatewayClientMissing": "Client gateway non cr\xE9\xE9",
2215
+ "adapter.errGatewayNotConnected": "Gateway non connect\xE9",
2216
+ "adapter.sessionTitleWithId": "session {name} {id}",
2217
+ "adapter.promptApproveTool": "{name} demande l'approbation d'ex\xE9cuter {tool}",
2218
+ "index.log.serverStart": "opencode server={server} baseUrl={baseUrl} auth={auth} lang={lang}",
2219
+ "agent.err.http": "HTTP {status} : {text}",
2220
+ "claude.promptUrl": "URL : {url}",
2221
+ "hermes.errBridgeNotRunning": "La boucle bridge n'est pas en cours d'ex\xE9cution",
2222
+ "hermes.errAskNoQuestion": "Aucune question fournie. Passez questions=[{question, choices?, multi_select?}, ...].",
2223
+ "hermes.toolPairDesc": "Demande un code d'appairage t\xE9l\xE9phone \xE0 usage unique au relais tunnelbox (pour le scan/la saisie dans l'app tunnelbox). \xC0 utiliser quand l'utilisateur demande comment se connecter/s'appairer/scanner ou contr\xF4ler cet ordinateur depuis son t\xE9l\xE9phone.",
2224
+ "hermes.toolPairRefreshDesc": "Forcer la demande d'un nouveau code d'appairage (par d\xE9faut : r\xE9utiliser/ignorer)",
2225
+ "hermes.toolStatusDesc": "Renvoie l'\xE9tat du plugin tunnelbox : adresse du relais, id de l'agent, liaison \xE0 un compte t\xE9l\xE9phone, r\xE9pertoire de donn\xE9es et derni\xE8res infos d'appairage. \xC0 utiliser quand l'utilisateur demande l'\xE9tat de connexion/la liaison/l'adresse du relais.",
2226
+ "hermes.toolAskDesc": "Envoie une question/un choix au t\xE9l\xE9phone tunnelbox de l'utilisateur (UI distante) et attend sa s\xE9lection ou saisie. Renvoie un JSON : {answered: bool, user_response: string|string[]|null}. Si le t\xE9l\xE9phone est hors ligne ou d\xE9passe le d\xE9lai, answered=false.",
2227
+ "hermes.toolAskQuestionDesc": "Le texte de la question \xE0 poser",
2228
+ "hermes.toolAskChoicesDesc": "Options pr\xE9d\xE9finies (facultatif ; jusqu'\xE0 4)",
2229
+ "hermes.toolAskMultipleDesc": "Autoriser la s\xE9lection multiple (n\xE9cessite choices)",
2230
+ "hermes.cmdDesc": "tunnelbox : appairage t\xE9l\xE9phone / \xE9tat de connexion",
2231
+ "hermes.logConfigLoadFailed": "tunnelbox : \xE9chec de lecture de la config, valeurs par d\xE9faut : {err}",
2232
+ "hermes.logRegisterToolsFailed": "tunnelbox : \xE9chec d'enregistrement des outils : {err}",
2233
+ "hermes.logRegisterCommandFailed": "tunnelbox : \xE9chec d'enregistrement de la commande : {err}",
2234
+ "hermes.logRegisterSkillFailed": "tunnelbox : \xE9chec d'enregistrement de la comp\xE9tence : {err}",
2235
+ "hermes.logRegisterHooksFailed": "tunnelbox : \xE9chec d'enregistrement des hooks : {err}",
2236
+ "hermes.logRegisterApprovalFailed": "tunnelbox : \xE9chec d'enregistrement du transport d'approbation : {err}",
2237
+ "hermes.logRegisterAskFailed": "tunnelbox : \xE9chec d'enregistrement de tunnelbox_ask : {err}",
2238
+ "hermes.logRegisterSystemPromptFailed": "tunnelbox : \xE9chec d'enregistrement de la section du prompt syst\xE8me : {err}",
2239
+ "hermes.logBackgroundBridgeFailed": "tunnelbox : \xE9chec du d\xE9marrage du pont en arri\xE8re-plan : {err}",
2240
+ "hermes.systemPromptAsk": "Lorsque vous avez besoin d'une d\xE9cision, d'une clarification ou d'un choix de l'utilisateur et qu'un t\xE9l\xE9phone tunnelbox est associ\xE9, utilisez l'outil `tunnelbox_ask` pour poser la question sur son t\xE9l\xE9phone au lieu de deviner. Attendez sa r\xE9ponse avant de continuer."
2007
2241
  };
2008
2242
 
2009
2243
  // locales/de-DE.json
@@ -2258,6 +2492,7 @@ var de_DE_default = {
2258
2492
  "adapter.logGatewayConnected": "Mit lokalem OpenClaw Gateway verbunden ({version})",
2259
2493
  "adapter.logGatewayDisconnected": "Vom OpenClaw Gateway getrennt; der offizielle Client verbindet sich neu\u2026",
2260
2494
  "adapter.logGatewayConnectFailed": "Verbindung zum lokalen OpenClaw Gateway nicht m\xF6glich (beim ersten Mal das Ger\xE4t lokal freigeben: `openclaw devices list` + `openclaw devices approve <requestId>`)",
2495
+ "adapter.errGatewayUnreachable": "Lokales OpenClaw Gateway ({url}) nicht erreichbar: {message}. Stelle sicher, dass es l\xE4uft (`openclaw gateway`)",
2261
2496
  "adapter.errGatewayNoSessionKey": "Gateway hat keinen Sitzungsschl\xFCssel zur\xFCckgegeben",
2262
2497
  "adapter.logDeleteSessionFailed": "Sitzung l\xF6schen fehlgeschlagen ({session}): {message} (wird dennoch als gel\xF6scht best\xE4tigt)",
2263
2498
  "adapter.logApprovalReplyFailed": "Genehmigungsantwort fehlgeschlagen ({id}): {message}",
@@ -2312,7 +2547,45 @@ var de_DE_default = {
2312
2547
  "adapter.errCursorExit": "Cursor CLI beendet ({code}): {err}",
2313
2548
  "adapter.errCursorSpawn": "Cursor CLI (agent) kann nicht gestartet werden: Stellen Sie sicher, dass es installiert und angemeldet ist ({message})",
2314
2549
  "adapter.errCursorStart": "Start von Cursor CLI fehlgeschlagen: {message}",
2315
- "adapter.errCursorGeneric": "Cursor-Fehler"
2550
+ "adapter.errCursorGeneric": "Cursor-Fehler",
2551
+ "qr.downloadApp": "tunnelbox-App herunterladen (Android / iOS): {url}",
2552
+ "adapter.logLegacyHookRemoved": "Alter PermissionRequest-Hook entfernt (hooks.json)",
2553
+ "adapter.errAppServerNotRunning": "codex app-server l\xE4uft nicht",
2554
+ "adapter.errAppServerTimeout": "Zeit\xFCberschreitung bei app-server-Anfrage: {method}",
2555
+ "adapter.errAppServerStopped": "app-server-Client gestoppt",
2556
+ "adapter.errAppServerExited": "codex app-server beendet (code={code} signal={signal})",
2557
+ "adapter.errAppServerError": "app-server-Fehler: {message}",
2558
+ "adapter.logAppServerStderr": "app-server: {line}",
2559
+ "adapter.logAppServerExited": "app-server beendet (code={code} signal={signal})",
2560
+ "adapter.errDshGenerate": "dsh-Generierungsfehler",
2561
+ "adapter.unknown": "unbekannt",
2562
+ "adapter.errGatewayClientMissing": "Gateway-Client nicht erstellt",
2563
+ "adapter.errGatewayNotConnected": "Gateway nicht verbunden",
2564
+ "adapter.sessionTitleWithId": "{name}-Sitzung {id}",
2565
+ "adapter.promptApproveTool": "{name} fordert die Genehmigung zur Ausf\xFChrung von {tool} an",
2566
+ "index.log.serverStart": "opencode server={server} baseUrl={baseUrl} auth={auth} lang={lang}",
2567
+ "agent.err.http": "HTTP {status}: {text}",
2568
+ "claude.promptUrl": "URL: {url}",
2569
+ "hermes.errBridgeNotRunning": "Bridge-Schleife l\xE4uft nicht",
2570
+ "hermes.errAskNoQuestion": "Keine Frage angegeben. \xDCbergeben Sie questions=[{question, choices?, multi_select?}, ...].",
2571
+ "hermes.toolPairDesc": "Fordert einen einmaligen Telefon-Kopplungscode vom tunnelbox-Relay an (zum Scannen/Eingeben in der tunnelbox-App). Verwenden, wenn der Nutzer fragt, wie er sich verbindet/koppelt/scannt oder diesen Computer vom Telefon aus steuert.",
2572
+ "hermes.toolPairRefreshDesc": "Erzwingt die Anforderung eines neuen Kopplungscodes (Standard: wiederverwenden/ignorieren)",
2573
+ "hermes.toolStatusDesc": "Gibt den tunnelbox-Plugin-Status zur\xFCck: Relay-Adresse, Agent-ID, Bindung an ein Telefonkonto, Datenverzeichnis und letzte Kopplungsinfos. Verwenden, wenn der Nutzer nach Verbindungsstatus/Bindung/Relay-Adresse fragt.",
2574
+ "hermes.toolAskDesc": "Sendet eine Frage/Auswahl an das tunnelbox-Telefon des Nutzers (Remote-UI) und wartet auf Auswahl oder Eingabe. Gibt JSON zur\xFCck: {answered: bool, user_response: string|string[]|null}. Ist das Telefon offline oder tritt eine Zeit\xFCberschreitung auf, ist answered=false.",
2575
+ "hermes.toolAskQuestionDesc": "Der zu stellende Fragetext",
2576
+ "hermes.toolAskChoicesDesc": "Voreingestellte Optionen (optional; bis zu 4)",
2577
+ "hermes.toolAskMultipleDesc": "Mehrfachauswahl zulassen (erfordert choices)",
2578
+ "hermes.cmdDesc": "tunnelbox: Telefon-Kopplung / Verbindungsstatus",
2579
+ "hermes.logConfigLoadFailed": "tunnelbox: Konfiguration konnte nicht gelesen werden, Standardwerte werden verwendet: {err}",
2580
+ "hermes.logRegisterToolsFailed": "tunnelbox: Registrierung der Tools fehlgeschlagen: {err}",
2581
+ "hermes.logRegisterCommandFailed": "tunnelbox: Registrierung des Befehls fehlgeschlagen: {err}",
2582
+ "hermes.logRegisterSkillFailed": "tunnelbox: Registrierung der Skill fehlgeschlagen: {err}",
2583
+ "hermes.logRegisterHooksFailed": "tunnelbox: Registrierung der Hooks fehlgeschlagen: {err}",
2584
+ "hermes.logRegisterApprovalFailed": "tunnelbox: Registrierung des Approval-Transports fehlgeschlagen: {err}",
2585
+ "hermes.logRegisterAskFailed": "tunnelbox: Registrierung von tunnelbox_ask fehlgeschlagen: {err}",
2586
+ "hermes.logRegisterSystemPromptFailed": "tunnelbox: Registrierung des System-Prompt-Abschnitts fehlgeschlagen: {err}",
2587
+ "hermes.logBackgroundBridgeFailed": "tunnelbox: Start der Hintergrund-Bridge fehlgeschlagen: {err}",
2588
+ "hermes.systemPromptAsk": "Wenn Sie eine Entscheidung, Kl\xE4rung oder Auswahl vom Nutzer ben\xF6tigen und ein tunnelbox-Telefon verbunden ist, verwenden Sie das Tool `tunnelbox_ask`, um auf dessen Telefon zu fragen, statt zu raten. Warten Sie auf die Antwort, bevor Sie fortfahren."
2316
2589
  };
2317
2590
 
2318
2591
  // locales/es-ES.json
@@ -2567,6 +2840,7 @@ var es_ES_default = {
2567
2840
  "adapter.logGatewayConnected": "Conectado al Gateway OpenClaw local ({version})",
2568
2841
  "adapter.logGatewayDisconnected": "Desconectado del Gateway OpenClaw; el cliente oficial se est\xE1 reconectando\u2026",
2569
2842
  "adapter.logGatewayConnectFailed": "No se puede conectar al Gateway OpenClaw local (la primera vez, apruebe el dispositivo localmente: `openclaw devices list` + `openclaw devices approve <requestId>`)",
2843
+ "adapter.errGatewayUnreachable": "No se puede conectar con el Gateway local de OpenClaw ({url}): {message}. Comprueba que est\xE9 en ejecuci\xF3n (`openclaw gateway`)",
2570
2844
  "adapter.errGatewayNoSessionKey": "El Gateway no devolvi\xF3 una clave de sesi\xF3n",
2571
2845
  "adapter.logDeleteSessionFailed": "Error al eliminar la sesi\xF3n ({session}): {message} (se confirma como eliminada igualmente)",
2572
2846
  "adapter.logApprovalReplyFailed": "Error en la respuesta de aprobaci\xF3n ({id}): {message}",
@@ -2621,7 +2895,45 @@ var es_ES_default = {
2621
2895
  "adapter.errCursorExit": "Cursor CLI finaliz\xF3 ({code}): {err}",
2622
2896
  "adapter.errCursorSpawn": "No se puede iniciar Cursor CLI (agent): comprueba que est\xE9 instalado y con sesi\xF3n iniciada ({message})",
2623
2897
  "adapter.errCursorStart": "Fall\xF3 el inicio de Cursor CLI: {message}",
2624
- "adapter.errCursorGeneric": "Error de Cursor"
2898
+ "adapter.errCursorGeneric": "Error de Cursor",
2899
+ "qr.downloadApp": "Descarga la app tunnelbox (Android / iOS): {url}",
2900
+ "adapter.logLegacyHookRemoved": "Se elimin\xF3 el hook PermissionRequest antiguo (hooks.json)",
2901
+ "adapter.errAppServerNotRunning": "codex app-server no est\xE1 en ejecuci\xF3n",
2902
+ "adapter.errAppServerTimeout": "Se agot\xF3 el tiempo de la solicitud a app-server: {method}",
2903
+ "adapter.errAppServerStopped": "Cliente app-server detenido",
2904
+ "adapter.errAppServerExited": "codex app-server finaliz\xF3 (code={code} signal={signal})",
2905
+ "adapter.errAppServerError": "Error de app-server: {message}",
2906
+ "adapter.logAppServerStderr": "app-server: {line}",
2907
+ "adapter.logAppServerExited": "app-server finaliz\xF3 (code={code} signal={signal})",
2908
+ "adapter.errDshGenerate": "Error de generaci\xF3n de dsh",
2909
+ "adapter.unknown": "desconocido",
2910
+ "adapter.errGatewayClientMissing": "Cliente de gateway no creado",
2911
+ "adapter.errGatewayNotConnected": "Gateway no conectado",
2912
+ "adapter.sessionTitleWithId": "sesi\xF3n de {name} {id}",
2913
+ "adapter.promptApproveTool": "{name} solicita aprobaci\xF3n para ejecutar {tool}",
2914
+ "index.log.serverStart": "opencode server={server} baseUrl={baseUrl} auth={auth} lang={lang}",
2915
+ "agent.err.http": "HTTP {status}: {text}",
2916
+ "claude.promptUrl": "URL: {url}",
2917
+ "hermes.errBridgeNotRunning": "El bucle de bridge no est\xE1 en ejecuci\xF3n",
2918
+ "hermes.errAskNoQuestion": "No se proporcion\xF3 ninguna pregunta. Pasa questions=[{question, choices?, multi_select?}, ...].",
2919
+ "hermes.toolPairDesc": "Solicita un c\xF3digo de emparejamiento telef\xF3nico de un solo uso al rel\xE9 tunnelbox (para escanear/introducir en la app tunnelbox). \xDAsalo cuando el usuario pregunte c\xF3mo conectar/emparejar/escanear o controlar este equipo desde el tel\xE9fono.",
2920
+ "hermes.toolPairRefreshDesc": "Forzar la solicitud de un nuevo c\xF3digo de emparejamiento (por defecto: reutilizar/ignorar)",
2921
+ "hermes.toolStatusDesc": "Devuelve el estado del plugin tunnelbox: direcci\xF3n del rel\xE9, id del agente, si est\xE1 vinculado a una cuenta de tel\xE9fono, directorio de datos e informaci\xF3n de emparejamiento reciente. \xDAsalo cuando el usuario pregunte por el estado de conexi\xF3n/vinculaci\xF3n/direcci\xF3n del rel\xE9.",
2922
+ "hermes.toolAskDesc": "Env\xEDa una pregunta/opci\xF3n al tel\xE9fono tunnelbox del usuario (UI remota) y espera su selecci\xF3n o entrada. Devuelve JSON: {answered: bool, user_response: string|string[]|null}. Si el tel\xE9fono est\xE1 desconectado o se agota el tiempo, answered=false.",
2923
+ "hermes.toolAskQuestionDesc": "El texto de la pregunta a realizar",
2924
+ "hermes.toolAskChoicesDesc": "Opciones predefinidas (opcional; hasta 4)",
2925
+ "hermes.toolAskMultipleDesc": "Permitir selecci\xF3n m\xFAltiple (requiere choices)",
2926
+ "hermes.cmdDesc": "tunnelbox: emparejamiento telef\xF3nico / estado de conexi\xF3n",
2927
+ "hermes.logConfigLoadFailed": "tunnelbox: no se pudo leer la configuraci\xF3n, usando valores por defecto: {err}",
2928
+ "hermes.logRegisterToolsFailed": "tunnelbox: fall\xF3 el registro de herramientas: {err}",
2929
+ "hermes.logRegisterCommandFailed": "tunnelbox: fall\xF3 el registro del comando: {err}",
2930
+ "hermes.logRegisterSkillFailed": "tunnelbox: fall\xF3 el registro de la skill: {err}",
2931
+ "hermes.logRegisterHooksFailed": "tunnelbox: fall\xF3 el registro de los hooks: {err}",
2932
+ "hermes.logRegisterApprovalFailed": "tunnelbox: fall\xF3 el registro del transporte de aprobaci\xF3n: {err}",
2933
+ "hermes.logRegisterAskFailed": "tunnelbox: fall\xF3 el registro de tunnelbox_ask: {err}",
2934
+ "hermes.logRegisterSystemPromptFailed": "tunnelbox: fall\xF3 el registro de la secci\xF3n del prompt del sistema: {err}",
2935
+ "hermes.logBackgroundBridgeFailed": "tunnelbox: fall\xF3 el inicio del puente en segundo plano: {err}",
2936
+ "hermes.systemPromptAsk": "Cuando necesites una decisi\xF3n, aclaraci\xF3n o elecci\xF3n del usuario y haya un tel\xE9fono tunnelbox vinculado, usa la herramienta `tunnelbox_ask` para preguntar en su tel\xE9fono en lugar de adivinar. Espera su respuesta antes de continuar."
2625
2937
  };
2626
2938
 
2627
2939
  // src/i18n.ts
@@ -2670,6 +2982,11 @@ function detectSystemLang() {
2670
2982
  const v = process.env[k];
2671
2983
  if (v && v.trim()) return v.trim().split(".")[0];
2672
2984
  }
2985
+ try {
2986
+ const loc = Intl.DateTimeFormat().resolvedOptions().locale;
2987
+ if (loc && loc.trim()) return loc.trim();
2988
+ } catch {
2989
+ }
2673
2990
  return null;
2674
2991
  }
2675
2992
  function resolveLang(opts = {}) {
@@ -2763,6 +3080,37 @@ function injectedRelayUrl() {
2763
3080
  return typeof __TB_DEFAULT_RELAY__ === "string" && __TB_DEFAULT_RELAY__ ? __TB_DEFAULT_RELAY__.replace(/\/+$/, "") : "";
2764
3081
  }
2765
3082
 
3083
+ // src/terminal.ts
3084
+ function websiteUrl() {
3085
+ return (process.env.TUNNELBOX_WEBSITE_URL || "https://www.tunnelbox.top").trim();
3086
+ }
3087
+ function envFlag(raw) {
3088
+ const s = (raw || "").trim().toLowerCase();
3089
+ if (["1", "true", "yes", "on"].includes(s)) return true;
3090
+ if (["0", "false", "no", "off"].includes(s)) return false;
3091
+ return null;
3092
+ }
3093
+ function supportsHyperlinks() {
3094
+ const override = envFlag(process.env.TUNNELBOX_HYPERLINK);
3095
+ if (override !== null) return override;
3096
+ if (!process.stdout || !process.stdout.isTTY) return false;
3097
+ const env = process.env;
3098
+ if (env.WT_SESSION) return true;
3099
+ if (env.WEZTERM_PANE) return true;
3100
+ if (env.KITTY_WINDOW_ID) return true;
3101
+ if (env.VTE_VERSION) return true;
3102
+ if (env.KONSOLE_VERSION) return true;
3103
+ const tp = env.TERM_PROGRAM || "";
3104
+ return /^(iTerm\.app|WezTerm|vscode|Hyper|Apple_Terminal|Tabby|WarpTerminal)$/i.test(tp);
3105
+ }
3106
+ function hyperlink(url, text) {
3107
+ const label = text ?? url;
3108
+ if (!supportsHyperlinks()) return label;
3109
+ const OSC = "\x1B]8;;";
3110
+ const ST = "\x1B\\";
3111
+ return `${OSC}${url}${ST}${label}${OSC}${ST}`;
3112
+ }
3113
+
2766
3114
  // src/qr.ts
2767
3115
  async function loadQrcode() {
2768
3116
  try {
@@ -2821,6 +3169,7 @@ async function printPairing(code, type, name, lang) {
2821
3169
  console.log("\u2502 " + padVisual(codeLine, W - 2) + " \u2502");
2822
3170
  console.log("\u2514" + bar + "\u2518");
2823
3171
  console.log(" " + hint);
3172
+ console.log(" " + tt("qr.downloadApp", { url: hyperlink(websiteUrl()) }));
2824
3173
  console.log(" " + tt("qr.validFor"));
2825
3174
  try {
2826
3175
  const mod = await import("qrcode");
@@ -3033,6 +3382,7 @@ export {
3033
3382
  detectSystemLang,
3034
3383
  envelope,
3035
3384
  findWinShim,
3385
+ hyperlink,
3036
3386
  injectedRelayUrl,
3037
3387
  killCliTree,
3038
3388
  loadState,
@@ -3047,7 +3397,9 @@ export {
3047
3397
  saveState,
3048
3398
  sliceWindow,
3049
3399
  statePath,
3400
+ supportsHyperlinks,
3050
3401
  t,
3402
+ websiteUrl,
3051
3403
  writePairingFile,
3052
3404
  writePairingJson
3053
3405
  };
@@ -249,6 +249,7 @@
249
249
  "adapter.logGatewayConnected": "Mit lokalem OpenClaw Gateway verbunden ({version})",
250
250
  "adapter.logGatewayDisconnected": "Vom OpenClaw Gateway getrennt; der offizielle Client verbindet sich neu…",
251
251
  "adapter.logGatewayConnectFailed": "Verbindung zum lokalen OpenClaw Gateway nicht möglich (beim ersten Mal das Gerät lokal freigeben: `openclaw devices list` + `openclaw devices approve <requestId>`)",
252
+ "adapter.errGatewayUnreachable": "Lokales OpenClaw Gateway ({url}) nicht erreichbar: {message}. Stelle sicher, dass es läuft (`openclaw gateway`)",
252
253
  "adapter.errGatewayNoSessionKey": "Gateway hat keinen Sitzungsschlüssel zurückgegeben",
253
254
  "adapter.logDeleteSessionFailed": "Sitzung löschen fehlgeschlagen ({session}): {message} (wird dennoch als gelöscht bestätigt)",
254
255
  "adapter.logApprovalReplyFailed": "Genehmigungsantwort fehlgeschlagen ({id}): {message}",
@@ -303,5 +304,43 @@
303
304
  "adapter.errCursorExit": "Cursor CLI beendet ({code}): {err}",
304
305
  "adapter.errCursorSpawn": "Cursor CLI (agent) kann nicht gestartet werden: Stellen Sie sicher, dass es installiert und angemeldet ist ({message})",
305
306
  "adapter.errCursorStart": "Start von Cursor CLI fehlgeschlagen: {message}",
306
- "adapter.errCursorGeneric": "Cursor-Fehler"
307
+ "adapter.errCursorGeneric": "Cursor-Fehler",
308
+ "qr.downloadApp": "tunnelbox-App herunterladen (Android / iOS): {url}",
309
+ "adapter.logLegacyHookRemoved": "Alter PermissionRequest-Hook entfernt (hooks.json)",
310
+ "adapter.errAppServerNotRunning": "codex app-server läuft nicht",
311
+ "adapter.errAppServerTimeout": "Zeitüberschreitung bei app-server-Anfrage: {method}",
312
+ "adapter.errAppServerStopped": "app-server-Client gestoppt",
313
+ "adapter.errAppServerExited": "codex app-server beendet (code={code} signal={signal})",
314
+ "adapter.errAppServerError": "app-server-Fehler: {message}",
315
+ "adapter.logAppServerStderr": "app-server: {line}",
316
+ "adapter.logAppServerExited": "app-server beendet (code={code} signal={signal})",
317
+ "adapter.errDshGenerate": "dsh-Generierungsfehler",
318
+ "adapter.unknown": "unbekannt",
319
+ "adapter.errGatewayClientMissing": "Gateway-Client nicht erstellt",
320
+ "adapter.errGatewayNotConnected": "Gateway nicht verbunden",
321
+ "adapter.sessionTitleWithId": "{name}-Sitzung {id}",
322
+ "adapter.promptApproveTool": "{name} fordert die Genehmigung zur Ausführung von {tool} an",
323
+ "index.log.serverStart": "opencode server={server} baseUrl={baseUrl} auth={auth} lang={lang}",
324
+ "agent.err.http": "HTTP {status}: {text}",
325
+ "claude.promptUrl": "URL: {url}",
326
+ "hermes.errBridgeNotRunning": "Bridge-Schleife läuft nicht",
327
+ "hermes.errAskNoQuestion": "Keine Frage angegeben. Übergeben Sie questions=[{question, choices?, multi_select?}, ...].",
328
+ "hermes.toolPairDesc": "Fordert einen einmaligen Telefon-Kopplungscode vom tunnelbox-Relay an (zum Scannen/Eingeben in der tunnelbox-App). Verwenden, wenn der Nutzer fragt, wie er sich verbindet/koppelt/scannt oder diesen Computer vom Telefon aus steuert.",
329
+ "hermes.toolPairRefreshDesc": "Erzwingt die Anforderung eines neuen Kopplungscodes (Standard: wiederverwenden/ignorieren)",
330
+ "hermes.toolStatusDesc": "Gibt den tunnelbox-Plugin-Status zurück: Relay-Adresse, Agent-ID, Bindung an ein Telefonkonto, Datenverzeichnis und letzte Kopplungsinfos. Verwenden, wenn der Nutzer nach Verbindungsstatus/Bindung/Relay-Adresse fragt.",
331
+ "hermes.toolAskDesc": "Sendet eine Frage/Auswahl an das tunnelbox-Telefon des Nutzers (Remote-UI) und wartet auf Auswahl oder Eingabe. Gibt JSON zurück: {answered: bool, user_response: string|string[]|null}. Ist das Telefon offline oder tritt eine Zeitüberschreitung auf, ist answered=false.",
332
+ "hermes.toolAskQuestionDesc": "Der zu stellende Fragetext",
333
+ "hermes.toolAskChoicesDesc": "Voreingestellte Optionen (optional; bis zu 4)",
334
+ "hermes.toolAskMultipleDesc": "Mehrfachauswahl zulassen (erfordert choices)",
335
+ "hermes.cmdDesc": "tunnelbox: Telefon-Kopplung / Verbindungsstatus",
336
+ "hermes.logConfigLoadFailed": "tunnelbox: Konfiguration konnte nicht gelesen werden, Standardwerte werden verwendet: {err}",
337
+ "hermes.logRegisterToolsFailed": "tunnelbox: Registrierung der Tools fehlgeschlagen: {err}",
338
+ "hermes.logRegisterCommandFailed": "tunnelbox: Registrierung des Befehls fehlgeschlagen: {err}",
339
+ "hermes.logRegisterSkillFailed": "tunnelbox: Registrierung der Skill fehlgeschlagen: {err}",
340
+ "hermes.logRegisterHooksFailed": "tunnelbox: Registrierung der Hooks fehlgeschlagen: {err}",
341
+ "hermes.logRegisterApprovalFailed": "tunnelbox: Registrierung des Approval-Transports fehlgeschlagen: {err}",
342
+ "hermes.logRegisterAskFailed": "tunnelbox: Registrierung von tunnelbox_ask fehlgeschlagen: {err}",
343
+ "hermes.logRegisterSystemPromptFailed": "tunnelbox: Registrierung des System-Prompt-Abschnitts fehlgeschlagen: {err}",
344
+ "hermes.logBackgroundBridgeFailed": "tunnelbox: Start der Hintergrund-Bridge fehlgeschlagen: {err}",
345
+ "hermes.systemPromptAsk": "Wenn Sie eine Entscheidung, Klärung oder Auswahl vom Nutzer benötigen und ein tunnelbox-Telefon verbunden ist, verwenden Sie das Tool `tunnelbox_ask`, um auf dessen Telefon zu fragen, statt zu raten. Warten Sie auf die Antwort, bevor Sie fortfahren."
307
346
  }
@@ -249,6 +249,7 @@
249
249
  "adapter.logGatewayConnected": "Connected to local OpenClaw Gateway ({version})",
250
250
  "adapter.logGatewayDisconnected": "Disconnected from OpenClaw Gateway; the official client is reconnecting…",
251
251
  "adapter.logGatewayConnectFailed": "Cannot connect to local OpenClaw Gateway (first time, approve the device locally: `openclaw devices list` + `openclaw devices approve <requestId>`)",
252
+ "adapter.errGatewayUnreachable": "Cannot reach the local OpenClaw Gateway ({url}): {message}. Make sure it is running (`openclaw gateway`)",
252
253
  "adapter.errGatewayNoSessionKey": "Gateway did not return a session key",
253
254
  "adapter.logDeleteSessionFailed": "Failed to delete session ({session}): {message} (still acking as deleted)",
254
255
  "adapter.logApprovalReplyFailed": "Approval reply failed ({id}): {message}",
@@ -303,5 +304,43 @@
303
304
  "adapter.errCursorExit": "Cursor CLI exited ({code}): {err}",
304
305
  "adapter.errCursorSpawn": "Cannot start Cursor CLI (agent): make sure it is installed and logged in ({message})",
305
306
  "adapter.errCursorStart": "Cursor CLI failed to start: {message}",
306
- "adapter.errCursorGeneric": "Cursor error"
307
+ "adapter.errCursorGeneric": "Cursor error",
308
+ "qr.downloadApp": "Download the tunnelbox App (Android / iOS): {url}",
309
+ "adapter.logLegacyHookRemoved": "Removed the legacy PermissionRequest hook (hooks.json)",
310
+ "adapter.errAppServerNotRunning": "codex app-server is not running",
311
+ "adapter.errAppServerTimeout": "app-server request timed out: {method}",
312
+ "adapter.errAppServerStopped": "app-server client stopped",
313
+ "adapter.errAppServerExited": "codex app-server exited (code={code} signal={signal})",
314
+ "adapter.errAppServerError": "app-server error: {message}",
315
+ "adapter.logAppServerStderr": "app-server: {line}",
316
+ "adapter.logAppServerExited": "app-server exited (code={code} signal={signal})",
317
+ "adapter.errDshGenerate": "dsh generation error",
318
+ "adapter.unknown": "unknown",
319
+ "adapter.errGatewayClientMissing": "gateway client not created",
320
+ "adapter.errGatewayNotConnected": "gateway not connected",
321
+ "adapter.sessionTitleWithId": "{name} session {id}",
322
+ "adapter.promptApproveTool": "{name} requests approval to run {tool}",
323
+ "index.log.serverStart": "opencode server={server} baseUrl={baseUrl} auth={auth} lang={lang}",
324
+ "agent.err.http": "HTTP {status}: {text}",
325
+ "claude.promptUrl": "URL: {url}",
326
+ "hermes.errBridgeNotRunning": "bridge loop is not running",
327
+ "hermes.errAskNoQuestion": "No question provided. Pass questions=[{question, choices?, multi_select?}, ...].",
328
+ "hermes.toolPairDesc": "Request a one-time phone pairing code from the tunnelbox relay (for scanning/entering in the tunnelbox app). Use when the user asks how to connect/pair/scan or remotely control this machine from their phone.",
329
+ "hermes.toolPairRefreshDesc": "Force requesting a new pairing code (default: reuse/ignore)",
330
+ "hermes.toolStatusDesc": "Return tunnelbox plugin status: relay address, agent id, whether bound to a phone account, data directory, and latest pairing info. Use when the user asks about the phone connection status/binding/relay address.",
331
+ "hermes.toolAskDesc": "Send a question/choice to the user's tunnelbox phone (remote UI) and wait for their selection or input. Returns JSON: {answered: bool, user_response: string|string[]|null}. If the phone is offline or times out, answered=false.",
332
+ "hermes.toolAskQuestionDesc": "The question text to ask",
333
+ "hermes.toolAskChoicesDesc": "Preset options (optional; up to 4)",
334
+ "hermes.toolAskMultipleDesc": "Allow multiple selection (requires choices)",
335
+ "hermes.cmdDesc": "tunnelbox: phone pairing / connection status",
336
+ "hermes.logConfigLoadFailed": "tunnelbox: failed to read config, using defaults: {err}",
337
+ "hermes.logRegisterToolsFailed": "tunnelbox: failed to register tools: {err}",
338
+ "hermes.logRegisterCommandFailed": "tunnelbox: failed to register command: {err}",
339
+ "hermes.logRegisterSkillFailed": "tunnelbox: failed to register skill: {err}",
340
+ "hermes.logRegisterHooksFailed": "tunnelbox: failed to register hooks: {err}",
341
+ "hermes.logRegisterApprovalFailed": "tunnelbox: failed to register approval transport: {err}",
342
+ "hermes.logRegisterAskFailed": "tunnelbox: failed to register tunnelbox_ask: {err}",
343
+ "hermes.logRegisterSystemPromptFailed": "tunnelbox: failed to register system prompt section: {err}",
344
+ "hermes.logBackgroundBridgeFailed": "tunnelbox: background bridge failed to start: {err}",
345
+ "hermes.systemPromptAsk": "When you need a decision, clarification, or choice from the user and a tunnelbox phone is attached, use the `tunnelbox_ask` tool to ask on their phone instead of guessing. Wait for their answer before proceeding."
307
346
  }
@@ -249,6 +249,7 @@
249
249
  "adapter.logGatewayConnected": "Conectado al Gateway OpenClaw local ({version})",
250
250
  "adapter.logGatewayDisconnected": "Desconectado del Gateway OpenClaw; el cliente oficial se está reconectando…",
251
251
  "adapter.logGatewayConnectFailed": "No se puede conectar al Gateway OpenClaw local (la primera vez, apruebe el dispositivo localmente: `openclaw devices list` + `openclaw devices approve <requestId>`)",
252
+ "adapter.errGatewayUnreachable": "No se puede conectar con el Gateway local de OpenClaw ({url}): {message}. Comprueba que esté en ejecución (`openclaw gateway`)",
252
253
  "adapter.errGatewayNoSessionKey": "El Gateway no devolvió una clave de sesión",
253
254
  "adapter.logDeleteSessionFailed": "Error al eliminar la sesión ({session}): {message} (se confirma como eliminada igualmente)",
254
255
  "adapter.logApprovalReplyFailed": "Error en la respuesta de aprobación ({id}): {message}",
@@ -303,5 +304,43 @@
303
304
  "adapter.errCursorExit": "Cursor CLI finalizó ({code}): {err}",
304
305
  "adapter.errCursorSpawn": "No se puede iniciar Cursor CLI (agent): comprueba que esté instalado y con sesión iniciada ({message})",
305
306
  "adapter.errCursorStart": "Falló el inicio de Cursor CLI: {message}",
306
- "adapter.errCursorGeneric": "Error de Cursor"
307
+ "adapter.errCursorGeneric": "Error de Cursor",
308
+ "qr.downloadApp": "Descarga la app tunnelbox (Android / iOS): {url}",
309
+ "adapter.logLegacyHookRemoved": "Se eliminó el hook PermissionRequest antiguo (hooks.json)",
310
+ "adapter.errAppServerNotRunning": "codex app-server no está en ejecución",
311
+ "adapter.errAppServerTimeout": "Se agotó el tiempo de la solicitud a app-server: {method}",
312
+ "adapter.errAppServerStopped": "Cliente app-server detenido",
313
+ "adapter.errAppServerExited": "codex app-server finalizó (code={code} signal={signal})",
314
+ "adapter.errAppServerError": "Error de app-server: {message}",
315
+ "adapter.logAppServerStderr": "app-server: {line}",
316
+ "adapter.logAppServerExited": "app-server finalizó (code={code} signal={signal})",
317
+ "adapter.errDshGenerate": "Error de generación de dsh",
318
+ "adapter.unknown": "desconocido",
319
+ "adapter.errGatewayClientMissing": "Cliente de gateway no creado",
320
+ "adapter.errGatewayNotConnected": "Gateway no conectado",
321
+ "adapter.sessionTitleWithId": "sesión de {name} {id}",
322
+ "adapter.promptApproveTool": "{name} solicita aprobación para ejecutar {tool}",
323
+ "index.log.serverStart": "opencode server={server} baseUrl={baseUrl} auth={auth} lang={lang}",
324
+ "agent.err.http": "HTTP {status}: {text}",
325
+ "claude.promptUrl": "URL: {url}",
326
+ "hermes.errBridgeNotRunning": "El bucle de bridge no está en ejecución",
327
+ "hermes.errAskNoQuestion": "No se proporcionó ninguna pregunta. Pasa questions=[{question, choices?, multi_select?}, ...].",
328
+ "hermes.toolPairDesc": "Solicita un código de emparejamiento telefónico de un solo uso al relé tunnelbox (para escanear/introducir en la app tunnelbox). Úsalo cuando el usuario pregunte cómo conectar/emparejar/escanear o controlar este equipo desde el teléfono.",
329
+ "hermes.toolPairRefreshDesc": "Forzar la solicitud de un nuevo código de emparejamiento (por defecto: reutilizar/ignorar)",
330
+ "hermes.toolStatusDesc": "Devuelve el estado del plugin tunnelbox: dirección del relé, id del agente, si está vinculado a una cuenta de teléfono, directorio de datos e información de emparejamiento reciente. Úsalo cuando el usuario pregunte por el estado de conexión/vinculación/dirección del relé.",
331
+ "hermes.toolAskDesc": "Envía una pregunta/opción al teléfono tunnelbox del usuario (UI remota) y espera su selección o entrada. Devuelve JSON: {answered: bool, user_response: string|string[]|null}. Si el teléfono está desconectado o se agota el tiempo, answered=false.",
332
+ "hermes.toolAskQuestionDesc": "El texto de la pregunta a realizar",
333
+ "hermes.toolAskChoicesDesc": "Opciones predefinidas (opcional; hasta 4)",
334
+ "hermes.toolAskMultipleDesc": "Permitir selección múltiple (requiere choices)",
335
+ "hermes.cmdDesc": "tunnelbox: emparejamiento telefónico / estado de conexión",
336
+ "hermes.logConfigLoadFailed": "tunnelbox: no se pudo leer la configuración, usando valores por defecto: {err}",
337
+ "hermes.logRegisterToolsFailed": "tunnelbox: falló el registro de herramientas: {err}",
338
+ "hermes.logRegisterCommandFailed": "tunnelbox: falló el registro del comando: {err}",
339
+ "hermes.logRegisterSkillFailed": "tunnelbox: falló el registro de la skill: {err}",
340
+ "hermes.logRegisterHooksFailed": "tunnelbox: falló el registro de los hooks: {err}",
341
+ "hermes.logRegisterApprovalFailed": "tunnelbox: falló el registro del transporte de aprobación: {err}",
342
+ "hermes.logRegisterAskFailed": "tunnelbox: falló el registro de tunnelbox_ask: {err}",
343
+ "hermes.logRegisterSystemPromptFailed": "tunnelbox: falló el registro de la sección del prompt del sistema: {err}",
344
+ "hermes.logBackgroundBridgeFailed": "tunnelbox: falló el inicio del puente en segundo plano: {err}",
345
+ "hermes.systemPromptAsk": "Cuando necesites una decisión, aclaración o elección del usuario y haya un teléfono tunnelbox vinculado, usa la herramienta `tunnelbox_ask` para preguntar en su teléfono en lugar de adivinar. Espera su respuesta antes de continuar."
307
346
  }
@@ -249,6 +249,7 @@
249
249
  "adapter.logGatewayConnected": "Connecté au Gateway OpenClaw local ({version})",
250
250
  "adapter.logGatewayDisconnected": "Déconnecté du Gateway OpenClaw ; le client officiel se reconnecte…",
251
251
  "adapter.logGatewayConnectFailed": "Impossible de se connecter au Gateway OpenClaw local (la première fois, approuvez l'appareil en local : `openclaw devices list` + `openclaw devices approve <requestId>`)",
252
+ "adapter.errGatewayUnreachable": "Impossible de joindre le Gateway OpenClaw local ({url}) : {message}. Vérifiez qu'il est démarré (`openclaw gateway`)",
252
253
  "adapter.errGatewayNoSessionKey": "Le Gateway n'a pas renvoyé de clé de session",
253
254
  "adapter.logDeleteSessionFailed": "Échec de suppression de session ({session}) : {message} (accusé de suppression tout de même)",
254
255
  "adapter.logApprovalReplyFailed": "Échec de la réponse d'approbation ({id}) : {message}",
@@ -303,5 +304,43 @@
303
304
  "adapter.errCursorExit": "Cursor CLI arrêté ({code}) : {err}",
304
305
  "adapter.errCursorSpawn": "Impossible de démarrer Cursor CLI (agent) : vérifiez qu'il est installé et connecté ({message})",
305
306
  "adapter.errCursorStart": "Échec du démarrage de Cursor CLI : {message}",
306
- "adapter.errCursorGeneric": "Erreur Cursor"
307
+ "adapter.errCursorGeneric": "Erreur Cursor",
308
+ "qr.downloadApp": "Télécharger l'application tunnelbox (Android / iOS) : {url}",
309
+ "adapter.logLegacyHookRemoved": "Ancien hook PermissionRequest supprimé (hooks.json)",
310
+ "adapter.errAppServerNotRunning": "codex app-server n'est pas en cours d'exécution",
311
+ "adapter.errAppServerTimeout": "Délai dépassé pour la requête app-server : {method}",
312
+ "adapter.errAppServerStopped": "Client app-server arrêté",
313
+ "adapter.errAppServerExited": "codex app-server arrêté (code={code} signal={signal})",
314
+ "adapter.errAppServerError": "Erreur app-server : {message}",
315
+ "adapter.logAppServerStderr": "app-server : {line}",
316
+ "adapter.logAppServerExited": "app-server arrêté (code={code} signal={signal})",
317
+ "adapter.errDshGenerate": "Erreur de génération dsh",
318
+ "adapter.unknown": "inconnu",
319
+ "adapter.errGatewayClientMissing": "Client gateway non créé",
320
+ "adapter.errGatewayNotConnected": "Gateway non connecté",
321
+ "adapter.sessionTitleWithId": "session {name} {id}",
322
+ "adapter.promptApproveTool": "{name} demande l'approbation d'exécuter {tool}",
323
+ "index.log.serverStart": "opencode server={server} baseUrl={baseUrl} auth={auth} lang={lang}",
324
+ "agent.err.http": "HTTP {status} : {text}",
325
+ "claude.promptUrl": "URL : {url}",
326
+ "hermes.errBridgeNotRunning": "La boucle bridge n'est pas en cours d'exécution",
327
+ "hermes.errAskNoQuestion": "Aucune question fournie. Passez questions=[{question, choices?, multi_select?}, ...].",
328
+ "hermes.toolPairDesc": "Demande un code d'appairage téléphone à usage unique au relais tunnelbox (pour le scan/la saisie dans l'app tunnelbox). À utiliser quand l'utilisateur demande comment se connecter/s'appairer/scanner ou contrôler cet ordinateur depuis son téléphone.",
329
+ "hermes.toolPairRefreshDesc": "Forcer la demande d'un nouveau code d'appairage (par défaut : réutiliser/ignorer)",
330
+ "hermes.toolStatusDesc": "Renvoie l'état du plugin tunnelbox : adresse du relais, id de l'agent, liaison à un compte téléphone, répertoire de données et dernières infos d'appairage. À utiliser quand l'utilisateur demande l'état de connexion/la liaison/l'adresse du relais.",
331
+ "hermes.toolAskDesc": "Envoie une question/un choix au téléphone tunnelbox de l'utilisateur (UI distante) et attend sa sélection ou saisie. Renvoie un JSON : {answered: bool, user_response: string|string[]|null}. Si le téléphone est hors ligne ou dépasse le délai, answered=false.",
332
+ "hermes.toolAskQuestionDesc": "Le texte de la question à poser",
333
+ "hermes.toolAskChoicesDesc": "Options prédéfinies (facultatif ; jusqu'à 4)",
334
+ "hermes.toolAskMultipleDesc": "Autoriser la sélection multiple (nécessite choices)",
335
+ "hermes.cmdDesc": "tunnelbox : appairage téléphone / état de connexion",
336
+ "hermes.logConfigLoadFailed": "tunnelbox : échec de lecture de la config, valeurs par défaut : {err}",
337
+ "hermes.logRegisterToolsFailed": "tunnelbox : échec d'enregistrement des outils : {err}",
338
+ "hermes.logRegisterCommandFailed": "tunnelbox : échec d'enregistrement de la commande : {err}",
339
+ "hermes.logRegisterSkillFailed": "tunnelbox : échec d'enregistrement de la compétence : {err}",
340
+ "hermes.logRegisterHooksFailed": "tunnelbox : échec d'enregistrement des hooks : {err}",
341
+ "hermes.logRegisterApprovalFailed": "tunnelbox : échec d'enregistrement du transport d'approbation : {err}",
342
+ "hermes.logRegisterAskFailed": "tunnelbox : échec d'enregistrement de tunnelbox_ask : {err}",
343
+ "hermes.logRegisterSystemPromptFailed": "tunnelbox : échec d'enregistrement de la section du prompt système : {err}",
344
+ "hermes.logBackgroundBridgeFailed": "tunnelbox : échec du démarrage du pont en arrière-plan : {err}",
345
+ "hermes.systemPromptAsk": "Lorsque vous avez besoin d'une décision, d'une clarification ou d'un choix de l'utilisateur et qu'un téléphone tunnelbox est associé, utilisez l'outil `tunnelbox_ask` pour poser la question sur son téléphone au lieu de deviner. Attendez sa réponse avant de continuer."
307
346
  }
@@ -249,6 +249,7 @@
249
249
  "adapter.logGatewayConnected": "ローカル OpenClaw Gateway に接続しました({version})",
250
250
  "adapter.logGatewayDisconnected": "OpenClaw Gateway から切断されました。公式クライアントが再接続しています…",
251
251
  "adapter.logGatewayConnectFailed": "ローカル OpenClaw Gateway に接続できません(初回は本機でデバイスを承認してください: `openclaw devices list` + `openclaw devices approve <requestId>`)",
252
+ "adapter.errGatewayUnreachable": "ローカルの OpenClaw Gateway({url})に接続できません: {message}。Gateway が起動していることを確認してください(`openclaw gateway`)",
252
253
  "adapter.errGatewayNoSessionKey": "Gateway がセッション key を返しませんでした",
253
254
  "adapter.logDeleteSessionFailed": "セッションの削除に失敗しました ({session}): {message}(削除済みとして応答)",
254
255
  "adapter.logApprovalReplyFailed": "承認応答に失敗しました ({id}): {message}",
@@ -303,5 +304,43 @@
303
304
  "adapter.errCursorExit": "Cursor CLI が終了しました({code}): {err}",
304
305
  "adapter.errCursorSpawn": "Cursor CLI(agent)を起動できません。インストールとログインを確認してください({message})",
305
306
  "adapter.errCursorStart": "Cursor CLI の起動に失敗しました: {message}",
306
- "adapter.errCursorGeneric": "Cursor エラー"
307
+ "adapter.errCursorGeneric": "Cursor エラー",
308
+ "qr.downloadApp": "tunnelbox App(Android / iOS)をダウンロード: {url}",
309
+ "adapter.logLegacyHookRemoved": "旧 PermissionRequest hook(hooks.json)を削除しました",
310
+ "adapter.errAppServerNotRunning": "codex app-server が実行されていません",
311
+ "adapter.errAppServerTimeout": "app-server リクエストがタイムアウトしました: {method}",
312
+ "adapter.errAppServerStopped": "app-server クライアントが停止しました",
313
+ "adapter.errAppServerExited": "codex app-server が終了しました(code={code} signal={signal})",
314
+ "adapter.errAppServerError": "app-server エラー: {message}",
315
+ "adapter.logAppServerStderr": "app-server: {line}",
316
+ "adapter.logAppServerExited": "app-server が終了しました(code={code} signal={signal})",
317
+ "adapter.errDshGenerate": "dsh の生成エラー",
318
+ "adapter.unknown": "不明",
319
+ "adapter.errGatewayClientMissing": "gateway クライアントが作成されていません",
320
+ "adapter.errGatewayNotConnected": "gateway に接続されていません",
321
+ "adapter.sessionTitleWithId": "{name} セッション {id}",
322
+ "adapter.promptApproveTool": "{name} が {tool} の実行承認を要求しています",
323
+ "index.log.serverStart": "opencode server={server} baseUrl={baseUrl} auth={auth} lang={lang}",
324
+ "agent.err.http": "HTTP {status}: {text}",
325
+ "claude.promptUrl": "URL: {url}",
326
+ "hermes.errBridgeNotRunning": "bridge ループが実行されていません",
327
+ "hermes.errAskNoQuestion": "質問が指定されていません。questions=[{question, choices?, multi_select?}, ...] を渡してください。",
328
+ "hermes.toolPairDesc": "tunnelbox リレーから一度限りのスマホペアリングコードを取得します(tunnelbox App でのスキャン/入力用)。スマホからの接続/ペアリング/スキャン方法や本機のリモート操作について尋ねられたときに使用します。",
329
+ "hermes.toolPairRefreshDesc": "新しいペアリングコードを強制的に要求するか(既定: 再利用/無視)",
330
+ "hermes.toolStatusDesc": "tunnelbox プラグインの状態を返します: リレーアドレス、agent id、スマホアカウントへのバインド有無、データディレクトリ、最新のペアリング情報。スマホ接続状態/バインド/リレーアドレスについて尋ねられたときに使用します。",
331
+ "hermes.toolAskDesc": "質問/選択をユーザーの tunnelbox スマホ(リモート UI)に送り、選択または入力があるまで待ちます。JSON を返します: {answered: bool, user_response: string|string[]|null}。スマホがオフラインまたはタイムアウトの場合は answered=false。",
332
+ "hermes.toolAskQuestionDesc": "尋ねる質問テキスト",
333
+ "hermes.toolAskChoicesDesc": "プリセット選択肢(任意、最大 4 つ)",
334
+ "hermes.toolAskMultipleDesc": "複数選択を許可(choices が必要)",
335
+ "hermes.cmdDesc": "tunnelbox: スマホペアリング / 接続状態",
336
+ "hermes.logConfigLoadFailed": "tunnelbox: 設定の読み込みに失敗、既定値を使用: {err}",
337
+ "hermes.logRegisterToolsFailed": "tunnelbox: ツールの登録に失敗: {err}",
338
+ "hermes.logRegisterCommandFailed": "tunnelbox: コマンドの登録に失敗: {err}",
339
+ "hermes.logRegisterSkillFailed": "tunnelbox: スキルの登録に失敗: {err}",
340
+ "hermes.logRegisterHooksFailed": "tunnelbox: hooks の登録に失敗: {err}",
341
+ "hermes.logRegisterApprovalFailed": "tunnelbox: approval transport の登録に失敗: {err}",
342
+ "hermes.logRegisterAskFailed": "tunnelbox: tunnelbox_ask の登録に失敗: {err}",
343
+ "hermes.logRegisterSystemPromptFailed": "tunnelbox: system prompt セクションの登録に失敗: {err}",
344
+ "hermes.logBackgroundBridgeFailed": "tunnelbox: バックグラウンドブリッジの起動に失敗: {err}",
345
+ "hermes.systemPromptAsk": "ユーザーに決定/確認/選択を求める必要があり、tunnelbox スマホが接続されている場合は、推測せず `tunnelbox_ask` ツールでスマホに質問してください。回答があるまで待ってから続行します。"
307
346
  }
@@ -249,6 +249,7 @@
249
249
  "adapter.logGatewayConnected": "로컬 OpenClaw Gateway에 연결됨({version})",
250
250
  "adapter.logGatewayDisconnected": "OpenClaw Gateway와 연결이 끊어졌습니다. 공식 클라이언트가 재연결 중…",
251
251
  "adapter.logGatewayConnectFailed": "로컬 OpenClaw Gateway에 연결할 수 없습니다(최초에는 로컬에서 장치를 승인하세요: `openclaw devices list` + `openclaw devices approve <requestId>`)",
252
+ "adapter.errGatewayUnreachable": "로컬 OpenClaw Gateway({url})에 연결할 수 없습니다: {message}. Gateway가 실행 중인지 확인하세요(`openclaw gateway`)",
252
253
  "adapter.errGatewayNoSessionKey": "Gateway가 세션 key를 반환하지 않았습니다",
253
254
  "adapter.logDeleteSessionFailed": "세션 삭제 실패({session}): {message}(삭제됨으로 응답)",
254
255
  "adapter.logApprovalReplyFailed": "승인 응답 실패({id}): {message}",
@@ -303,5 +304,43 @@
303
304
  "adapter.errCursorExit": "Cursor CLI 종료({code}): {err}",
304
305
  "adapter.errCursorSpawn": "Cursor CLI(agent)를 시작할 수 없습니다. 설치 및 로그인을 확인하세요({message})",
305
306
  "adapter.errCursorStart": "Cursor CLI 시작 실패: {message}",
306
- "adapter.errCursorGeneric": "Cursor 오류"
307
+ "adapter.errCursorGeneric": "Cursor 오류",
308
+ "qr.downloadApp": "tunnelbox 앱(Android / iOS) 다운로드: {url}",
309
+ "adapter.logLegacyHookRemoved": "이전 PermissionRequest hook(hooks.json)을 제거했습니다",
310
+ "adapter.errAppServerNotRunning": "codex app-server가 실행 중이 아닙니다",
311
+ "adapter.errAppServerTimeout": "app-server 요청 시간 초과: {method}",
312
+ "adapter.errAppServerStopped": "app-server 클라이언트가 중지되었습니다",
313
+ "adapter.errAppServerExited": "codex app-server 종료(code={code} signal={signal})",
314
+ "adapter.errAppServerError": "app-server 오류: {message}",
315
+ "adapter.logAppServerStderr": "app-server: {line}",
316
+ "adapter.logAppServerExited": "app-server 종료(code={code} signal={signal})",
317
+ "adapter.errDshGenerate": "dsh 생성 오류",
318
+ "adapter.unknown": "알 수 없음",
319
+ "adapter.errGatewayClientMissing": "gateway 클라이언트가 생성되지 않았습니다",
320
+ "adapter.errGatewayNotConnected": "gateway에 연결되지 않았습니다",
321
+ "adapter.sessionTitleWithId": "{name} 세션 {id}",
322
+ "adapter.promptApproveTool": "{name}이(가) {tool} 실행 승인을 요청합니다",
323
+ "index.log.serverStart": "opencode server={server} baseUrl={baseUrl} auth={auth} lang={lang}",
324
+ "agent.err.http": "HTTP {status}: {text}",
325
+ "claude.promptUrl": "URL: {url}",
326
+ "hermes.errBridgeNotRunning": "bridge 루프가 실행 중이 아닙니다",
327
+ "hermes.errAskNoQuestion": "질문이 제공되지 않았습니다. questions=[{question, choices?, multi_select?}, ...]를 전달하세요.",
328
+ "hermes.toolPairDesc": "tunnelbox 릴레이에서 일회용 휴대폰 페어링 코드를 요청합니다(tunnelbox 앱에서 스캔/입력용). 사용자가 휴대폰으로 연결/페어링/스캔 방법이나 이 컴퓨터의 원격 제어를 물을 때 사용하세요.",
329
+ "hermes.toolPairRefreshDesc": "새 페어링 코드를 강제로 요청할지 여부(기본: 재사용/무시)",
330
+ "hermes.toolStatusDesc": "tunnelbox 플러그인 상태를 반환합니다: 릴레이 주소, agent id, 휴대폰 계정 바인딩 여부, 데이터 디렉터리, 최근 페어링 정보. 휴대폰 연결 상태/바인딩/릴레이 주소를 물을 때 사용하세요.",
331
+ "hermes.toolAskDesc": "질문/선택을 사용자의 tunnelbox 휴대폰(원격 UI)으로 보내고 선택 또는 입력을 기다립니다. JSON 반환: {answered: bool, user_response: string|string[]|null}. 휴대폰이 오프라인이거나 시간 초과면 answered=false.",
332
+ "hermes.toolAskQuestionDesc": "질문 텍스트",
333
+ "hermes.toolAskChoicesDesc": "사전 설정 선택지(선택, 최대 4개)",
334
+ "hermes.toolAskMultipleDesc": "다중 선택 허용(choices 필요)",
335
+ "hermes.cmdDesc": "tunnelbox: 휴대폰 페어링 / 연결 상태",
336
+ "hermes.logConfigLoadFailed": "tunnelbox: 설정 읽기 실패, 기본값 사용: {err}",
337
+ "hermes.logRegisterToolsFailed": "tunnelbox: 도구 등록 실패: {err}",
338
+ "hermes.logRegisterCommandFailed": "tunnelbox: 명령 등록 실패: {err}",
339
+ "hermes.logRegisterSkillFailed": "tunnelbox: 스킬 등록 실패: {err}",
340
+ "hermes.logRegisterHooksFailed": "tunnelbox: hooks 등록 실패: {err}",
341
+ "hermes.logRegisterApprovalFailed": "tunnelbox: approval transport 등록 실패: {err}",
342
+ "hermes.logRegisterAskFailed": "tunnelbox: tunnelbox_ask 등록 실패: {err}",
343
+ "hermes.logRegisterSystemPromptFailed": "tunnelbox: system prompt 섹션 등록 실패: {err}",
344
+ "hermes.logBackgroundBridgeFailed": "tunnelbox: 백그라운드 브리지 시작 실패: {err}",
345
+ "hermes.systemPromptAsk": "사용자에게 결정/확인/선택이 필요하고 tunnelbox 휴대폰이 연결되어 있으면 추측하지 말고 `tunnelbox_ask` 도구로 휴대폰에서 질문하세요. 사용자가 답할 때까지 기다린 후 진행하세요."
307
346
  }
@@ -249,6 +249,7 @@
249
249
  "adapter.logGatewayConnected": "已连接本机 OpenClaw Gateway({version})",
250
250
  "adapter.logGatewayDisconnected": "与 OpenClaw Gateway 断开,正在由官方客户端重连…",
251
251
  "adapter.logGatewayConnectFailed": "无法连接本机 OpenClaw Gateway(首次需在本机放行设备:`openclaw devices list` + `openclaw devices approve <requestId>`)",
252
+ "adapter.errGatewayUnreachable": "无法连接本机 OpenClaw Gateway({url}):{message}。请确认 Gateway 已启动(`openclaw gateway`)",
252
253
  "adapter.errGatewayNoSessionKey": "Gateway 未返回会话 key",
253
254
  "adapter.logDeleteSessionFailed": "删除会话失败({session}): {message}(仍按已删除回执)",
254
255
  "adapter.logApprovalReplyFailed": "审批应答失败({id}): {message}",
@@ -303,5 +304,43 @@
303
304
  "adapter.errCursorExit": "Cursor CLI 退出({code}): {err}",
304
305
  "adapter.errCursorSpawn": "无法启动 Cursor CLI(agent):请确认已安装并登录({message})",
305
306
  "adapter.errCursorStart": "Cursor CLI 启动失败: {message}",
306
- "adapter.errCursorGeneric": "Cursor 出错"
307
+ "adapter.errCursorGeneric": "Cursor 出错",
308
+ "qr.downloadApp": "下载 tunnelbox App(Android / iOS):{url}",
309
+ "adapter.logLegacyHookRemoved": "已移除旧的 PermissionRequest hook(hooks.json)",
310
+ "adapter.errAppServerNotRunning": "codex app-server 未运行",
311
+ "adapter.errAppServerTimeout": "app-server 请求超时:{method}",
312
+ "adapter.errAppServerStopped": "app-server 客户端已停止",
313
+ "adapter.errAppServerExited": "codex app-server 退出(code={code} signal={signal})",
314
+ "adapter.errAppServerError": "app-server 错误:{message}",
315
+ "adapter.logAppServerStderr": "app-server:{line}",
316
+ "adapter.logAppServerExited": "app-server 退出(code={code} signal={signal})",
317
+ "adapter.errDshGenerate": "dsh 生成出错",
318
+ "adapter.unknown": "未知",
319
+ "adapter.errGatewayClientMissing": "gateway client 未创建",
320
+ "adapter.errGatewayNotConnected": "gateway 未连接",
321
+ "adapter.sessionTitleWithId": "{name} 会话 {id}",
322
+ "adapter.promptApproveTool": "{name} 请求批准运行 {tool}",
323
+ "index.log.serverStart": "opencode server={server} baseUrl={baseUrl} auth={auth} lang={lang}",
324
+ "agent.err.http": "HTTP {status}:{text}",
325
+ "claude.promptUrl": "URL:{url}",
326
+ "hermes.errBridgeNotRunning": "bridge loop 未运行",
327
+ "hermes.errAskNoQuestion": "未提供问题。请传入 questions=[{question, choices?, multi_select?}, ...]。",
328
+ "hermes.toolPairDesc": "向 tunnelbox 中继申请一次性手机配对码(供手机 tunnelbox App 扫码/输码配对)。当用户询问如何用手机连接/配对/扫码/远程控制本机时使用。",
329
+ "hermes.toolPairRefreshDesc": "是否强制申请新配对码(默认复用/忽略)",
330
+ "hermes.toolStatusDesc": "返回 tunnelbox 插件状态:中继地址、agent 标识、是否已绑定手机账号、数据目录与最近配对信息。当用户询问与手机的 tunnelbox 连接状态/是否绑定/中继地址时使用。",
331
+ "hermes.toolAskDesc": "把一个问题/选择发到用户的 tunnelbox 手机(远程 UI)并等待其选择或输入。返回 JSON:{answered: bool, user_response: string|string[]|null}。手机离线或超时会 answered=false。",
332
+ "hermes.toolAskQuestionDesc": "要问的问题文本",
333
+ "hermes.toolAskChoicesDesc": "预置选项(可选;最多 4 个)",
334
+ "hermes.toolAskMultipleDesc": "是否多选(需提供 choices)",
335
+ "hermes.cmdDesc": "tunnelbox:手机配对 / 连接状态",
336
+ "hermes.logConfigLoadFailed": "tunnelbox: 读取配置失败,使用默认值: {err}",
337
+ "hermes.logRegisterToolsFailed": "tunnelbox: 注册工具失败: {err}",
338
+ "hermes.logRegisterCommandFailed": "tunnelbox: 注册命令失败: {err}",
339
+ "hermes.logRegisterSkillFailed": "tunnelbox: 注册技能失败: {err}",
340
+ "hermes.logRegisterHooksFailed": "tunnelbox: 注册 hooks 失败: {err}",
341
+ "hermes.logRegisterApprovalFailed": "tunnelbox: 注册 approval transport 失败: {err}",
342
+ "hermes.logRegisterAskFailed": "tunnelbox: 注册 tunnelbox_ask 失败: {err}",
343
+ "hermes.logRegisterSystemPromptFailed": "tunnelbox: 注册 system prompt 段失败: {err}",
344
+ "hermes.logBackgroundBridgeFailed": "tunnelbox: 后台桥启动失败: {err}",
345
+ "hermes.systemPromptAsk": "当你需要用户做决定/澄清/选择,且已连接 tunnelbox 手机时,请用 `tunnelbox_ask` 工具在手机上提问,而不是自行猜测;等到用户作答后再继续。"
307
346
  }
@@ -249,6 +249,7 @@
249
249
  "adapter.logGatewayConnected": "已連接本機 OpenClaw Gateway({version})",
250
250
  "adapter.logGatewayDisconnected": "與 OpenClaw Gateway 斷開,正在由官方客戶端重連…",
251
251
  "adapter.logGatewayConnectFailed": "無法連接本機 OpenClaw Gateway(首次需在本機放行裝置:`openclaw devices list` + `openclaw devices approve <requestId>`)",
252
+ "adapter.errGatewayUnreachable": "無法連接本機 OpenClaw Gateway({url}):{message}。請確認 Gateway 已啟動(`openclaw gateway`)",
252
253
  "adapter.errGatewayNoSessionKey": "Gateway 未返回工作階段 key",
253
254
  "adapter.logDeleteSessionFailed": "刪除工作階段失敗({session}): {message}(仍按已刪除回執)",
254
255
  "adapter.logApprovalReplyFailed": "審批應答失敗({id}): {message}",
@@ -303,5 +304,43 @@
303
304
  "adapter.errCursorExit": "Cursor CLI 退出({code}): {err}",
304
305
  "adapter.errCursorSpawn": "無法啟動 Cursor CLI(agent):請確認已安裝並登入({message})",
305
306
  "adapter.errCursorStart": "Cursor CLI 啟動失敗: {message}",
306
- "adapter.errCursorGeneric": "Cursor 出錯"
307
+ "adapter.errCursorGeneric": "Cursor 出錯",
308
+ "qr.downloadApp": "下載 tunnelbox App(Android / iOS):{url}",
309
+ "adapter.logLegacyHookRemoved": "已移除舊的 PermissionRequest hook(hooks.json)",
310
+ "adapter.errAppServerNotRunning": "codex app-server 未執行",
311
+ "adapter.errAppServerTimeout": "app-server 請求逾時:{method}",
312
+ "adapter.errAppServerStopped": "app-server 用戶端已停止",
313
+ "adapter.errAppServerExited": "codex app-server 結束(code={code} signal={signal})",
314
+ "adapter.errAppServerError": "app-server 錯誤:{message}",
315
+ "adapter.logAppServerStderr": "app-server:{line}",
316
+ "adapter.logAppServerExited": "app-server 結束(code={code} signal={signal})",
317
+ "adapter.errDshGenerate": "dsh 產生錯誤",
318
+ "adapter.unknown": "未知",
319
+ "adapter.errGatewayClientMissing": "gateway client 未建立",
320
+ "adapter.errGatewayNotConnected": "gateway 未連線",
321
+ "adapter.sessionTitleWithId": "{name} 工作階段 {id}",
322
+ "adapter.promptApproveTool": "{name} 請求批准執行 {tool}",
323
+ "index.log.serverStart": "opencode server={server} baseUrl={baseUrl} auth={auth} lang={lang}",
324
+ "agent.err.http": "HTTP {status}:{text}",
325
+ "claude.promptUrl": "URL:{url}",
326
+ "hermes.errBridgeNotRunning": "bridge loop 未執行",
327
+ "hermes.errAskNoQuestion": "未提供問題。請傳入 questions=[{question, choices?, multi_select?}, ...]。",
328
+ "hermes.toolPairDesc": "向 tunnelbox 中繼申請一次性手機配對碼(供手機 tunnelbox App 掃碼/輸碼配對)。當使用者詢問如何用手機連線/配對/掃碼/遠端控制本機時使用。",
329
+ "hermes.toolPairRefreshDesc": "是否強制申請新配對碼(預設重用/忽略)",
330
+ "hermes.toolStatusDesc": "返回 tunnelbox 外掛狀態:中繼位址、agent 標識、是否已綁定手機帳號、資料目錄與最近配對資訊。當使用者詢問與手機的 tunnelbox 連線狀態/是否綁定/中繼位址時使用。",
331
+ "hermes.toolAskDesc": "把一個問題/選擇發到使用者的 tunnelbox 手機(遠端 UI)並等待其選擇或輸入。返回 JSON:{answered: bool, user_response: string|string[]|null}。手機離線或逾時會 answered=false。",
332
+ "hermes.toolAskQuestionDesc": "要問的問題文字",
333
+ "hermes.toolAskChoicesDesc": "預置選項(可選;最多 4 個)",
334
+ "hermes.toolAskMultipleDesc": "是否多選(需提供 choices)",
335
+ "hermes.cmdDesc": "tunnelbox:手機配對 / 連線狀態",
336
+ "hermes.logConfigLoadFailed": "tunnelbox: 讀取設定失敗,使用預設值: {err}",
337
+ "hermes.logRegisterToolsFailed": "tunnelbox: 註冊工具失敗: {err}",
338
+ "hermes.logRegisterCommandFailed": "tunnelbox: 註冊命令失敗: {err}",
339
+ "hermes.logRegisterSkillFailed": "tunnelbox: 註冊技能失敗: {err}",
340
+ "hermes.logRegisterHooksFailed": "tunnelbox: 註冊 hooks 失敗: {err}",
341
+ "hermes.logRegisterApprovalFailed": "tunnelbox: 註冊 approval transport 失敗: {err}",
342
+ "hermes.logRegisterAskFailed": "tunnelbox: 註冊 tunnelbox_ask 失敗: {err}",
343
+ "hermes.logRegisterSystemPromptFailed": "tunnelbox: 註冊 system prompt 段失敗: {err}",
344
+ "hermes.logBackgroundBridgeFailed": "tunnelbox: 背景橋啟動失敗: {err}",
345
+ "hermes.systemPromptAsk": "當你需要使用者做決定/澄清/選擇,且已連接 tunnelbox 手機時,請用 `tunnelbox_ask` 工具在手機上提問,而不是自行猜測;等到使用者作答後再繼續。"
307
346
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tunnelbox/core",
3
- "version": "0.1.21",
3
+ "version": "0.1.23",
4
4
  "description": "tunnelbox 共享核心:协议类型、中继客户端、状态持久化、二维码配对",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
package/src/i18n.ts CHANGED
@@ -71,12 +71,18 @@ export function normalizeLang(raw?: string | null): Lang {
71
71
  return map[base] ?? DEFAULT_LANG;
72
72
  }
73
73
 
74
- /** 从系统环境变量(LANG/LC_ALL/LC_MESSAGES)探测语言;拿不到返回 null。 */
74
+ /** 从系统环境变量(LANG/LC_ALL/LC_MESSAGES)探测语言;拿不到则用运行时默认 locale(跨平台,含 Windows);仍拿不到返回 null。 */
75
75
  export function detectSystemLang(): string | null {
76
76
  for (const k of ["LC_ALL", "LC_MESSAGES", "LANG"]) {
77
77
  const v = process.env[k];
78
78
  if (v && v.trim()) return v.trim().split(".")[0];
79
79
  }
80
+ try {
81
+ const loc = Intl.DateTimeFormat().resolvedOptions().locale;
82
+ if (loc && loc.trim()) return loc.trim();
83
+ } catch {
84
+ /* ignore */
85
+ }
80
86
  return null;
81
87
  }
82
88
 
package/src/index.ts CHANGED
@@ -11,3 +11,4 @@ export * from "./qr";
11
11
  export * from "./i18n";
12
12
  export * from "./messages";
13
13
  export * from "./cli";
14
+ export * from "./terminal";
package/src/qr.ts CHANGED
@@ -4,6 +4,7 @@
4
4
  */
5
5
  import { writePairingFile } from "./state";
6
6
  import { normalizeLang, resolveLang, t, type Lang } from "./i18n";
7
+ import { hyperlink, websiteUrl } from "./terminal";
7
8
 
8
9
  /** 加载 qrcode 渲染器(可选依赖,加载失败返回 null)。 */
9
10
  async function loadQrcode(): Promise<{
@@ -90,6 +91,7 @@ export async function printPairing(
90
91
  console.log("│ " + padVisual(codeLine, W - 2) + " │");
91
92
  console.log("└" + bar + "┘");
92
93
  console.log(" " + hint);
94
+ console.log(" " + tt("qr.downloadApp", { url: hyperlink(websiteUrl()) }));
93
95
  console.log(" " + tt("qr.validFor"));
94
96
 
95
97
  try {
@@ -0,0 +1,46 @@
1
+ /**
2
+ * 终端链接辅助:在支持的终端把 URL 渲染为**可点击超链接**(OSC 8),否则回退纯文本。
3
+ * 供各适配器配对输出复用(官网下载引导)。默认自动探测,可用环境变量覆盖:
4
+ * - TUNNELBOX_HYPERLINK=1|0 强制开启/关闭
5
+ * - TUNNELBOX_WEBSITE_URL 覆盖官网地址
6
+ */
7
+
8
+ /** 官网默认地址(可用 TUNNELBOX_WEBSITE_URL 覆盖)。 */
9
+ export function websiteUrl(): string {
10
+ return (process.env.TUNNELBOX_WEBSITE_URL || "https://www.tunnelbox.top").trim();
11
+ }
12
+
13
+ function envFlag(raw: string | undefined): boolean | null {
14
+ const s = (raw || "").trim().toLowerCase();
15
+ if (["1", "true", "yes", "on"].includes(s)) return true;
16
+ if (["0", "false", "no", "off"].includes(s)) return false;
17
+ return null;
18
+ }
19
+
20
+ /**
21
+ * 是否支持 OSC 8 超链接:仅 TTY + 已知终端;可用 TUNNELBOX_HYPERLINK 强制。
22
+ * 覆盖的终端:Windows Terminal、iTerm2、WezTerm、VS Code、Hyper、Tabby、Warp、
23
+ * VTE 系(GNOME Terminal 等)、Konsole、kitty。
24
+ */
25
+ export function supportsHyperlinks(): boolean {
26
+ const override = envFlag(process.env.TUNNELBOX_HYPERLINK);
27
+ if (override !== null) return override;
28
+ if (!process.stdout || !process.stdout.isTTY) return false;
29
+ const env = process.env;
30
+ if (env.WT_SESSION) return true; // Windows Terminal
31
+ if (env.WEZTERM_PANE) return true;
32
+ if (env.KITTY_WINDOW_ID) return true;
33
+ if (env.VTE_VERSION) return true; // GNOME Terminal 等 VTE
34
+ if (env.KONSOLE_VERSION) return true;
35
+ const tp = env.TERM_PROGRAM || "";
36
+ return /^(iTerm\.app|WezTerm|vscode|Hyper|Apple_Terminal|Tabby|WarpTerminal)$/i.test(tp);
37
+ }
38
+
39
+ /** OSC 8 超链接;不支持时返回纯文本(默认显示 URL 本身,仍可复制)。 */
40
+ export function hyperlink(url: string, text?: string): string {
41
+ const label = text ?? url;
42
+ if (!supportsHyperlinks()) return label;
43
+ const OSC = "\u001B]8;;";
44
+ const ST = "\u001B\\";
45
+ return `${OSC}${url}${ST}${label}${OSC}${ST}`;
46
+ }