@tunnelbox/dsh-tunnelbox 0.1.29 → 0.1.32

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
@@ -98,7 +98,7 @@ Each instance appears separately on the phone by `type=dsh` + its own agentID.
98
98
 
99
99
  ## Multilingual
100
100
 
101
- User-visible output supports 8 languages (`zh-CN` / `zh-TW` / `en-US` / `ja-JP` / `ko-KR` / `fr-FR` / `de-DE` / `es-ES`). Resolution order: `TUNNELBOX_LANG` > saved `remote-state.dsh.json.lang` > system locale > `en-US`.
101
+ User-visible output supports 8 languages (`zh-CN` / `zh-TW` / `en-US` / `ja-JP` / `ko-KR` / `fr-FR` / `de-DE` / `es-ES`). Resolution order: `TUNNELBOX_LANG` > system locale > `en-US`.
102
102
 
103
103
  ## Troubleshooting
104
104
 
@@ -111,8 +111,7 @@ User-visible output supports 8 languages (`zh-CN` / `zh-TW` / `en-US` / `ja-JP`
111
111
 
112
112
  ## State files
113
113
 
114
- - `~/.tunnelbox/remote-state.dsh.json` — agentID / relay / bound state / language
115
- - `~/.tunnelbox/remote-pairing.json` — latest pairing info
114
+ - `~/.tunnelbox/remote-state.dsh.json` — agentID (+ language)
116
115
  - `~/.tunnelbox/tunnelbox.log` — plugin log
117
116
 
118
117
  ## Uninstall
package/README.zh-CN.md CHANGED
@@ -111,8 +111,7 @@ DSH_HOME=~/.dsh-b DSH_PERMISSION_MODE=danger-full-access dsh --profile tunnelbox
111
111
 
112
112
  ## 状态文件
113
113
 
114
- - `~/.tunnelbox/remote-state.dsh.json` — agentID / 中继地址 / 绑定状态 / 语言
115
- - `~/.tunnelbox/remote-pairing.json` — 最新配对信息
114
+ - `~/.tunnelbox/remote-state.dsh.json` — agentID(+ 语言)
116
115
  - `~/.tunnelbox/tunnelbox.log` — 插件日志
117
116
 
118
117
  ## 卸载
package/dist/index.mjs CHANGED
@@ -208,7 +208,6 @@ var zh_CN_default = {
208
208
  "perm.promptResource": "opencode \u8BF7\u6C42\u8BBF\u95EE\u8D44\u6E90\uFF1A{list}",
209
209
  "perm.promptTool": "opencode \u8BF7\u6C42\u6267\u884C {tool}",
210
210
  "qr.codeLabel": "\u914D\u5BF9\u7801",
211
- "qr.fileWritten": "\u914D\u5BF9\u4FE1\u606F\u5DF2\u5199\u5165: {path}",
212
211
  "qr.openHint": "\u6253\u5F00 tunnelbox App\uFF0C\u7528\u300C\u626B\u4E00\u626B\u914D\u5BF9\u300D\u626B\u63CF\u4E0A\u65B9\u4E8C\u7EF4\u7801\uFF0C\u6216\u624B\u52A8\u8F93\u5165\u914D\u5BF9\u7801\u3002",
213
212
  "qr.titleNoType": "tunnelbox \u624B\u673A\u914D\u5BF9",
214
213
  "qr.titleWithType": "tunnelbox {type} \u624B\u673A\u914D\u5BF9",
@@ -618,7 +617,6 @@ var zh_TW_default = {
618
617
  "perm.promptResource": "opencode \u8ACB\u6C42\u5B58\u53D6\u8CC7\u6E90\uFF1A{list}",
619
618
  "perm.promptTool": "opencode \u8ACB\u6C42\u57F7\u884C {tool}",
620
619
  "qr.codeLabel": "\u914D\u5C0D\u78BC",
621
- "qr.fileWritten": "\u914D\u5C0D\u8CC7\u8A0A\u5DF2\u5BEB\u5165: {path}",
622
620
  "qr.openHint": "\u958B\u555F tunnelbox App\uFF0C\u7528\u300C\u6383\u63CF\u914D\u5C0D\u300D\u6383\u63CF\u4E0A\u65B9 QR Code\uFF0C\u6216\u624B\u52D5\u8F38\u5165\u914D\u5C0D\u78BC\u3002",
623
621
  "qr.titleNoType": "tunnelbox \u624B\u6A5F\u914D\u5C0D",
624
622
  "qr.titleWithType": "tunnelbox {type} \u624B\u6A5F\u914D\u5C0D",
@@ -1028,7 +1026,6 @@ var en_US_default = {
1028
1026
  "perm.promptResource": "opencode requests access to resources: {list}",
1029
1027
  "perm.promptTool": "opencode requests to run {tool}",
1030
1028
  "qr.codeLabel": "Pairing code",
1031
- "qr.fileWritten": "Pairing info written to: {path}",
1032
1029
  "qr.openHint": "Open the tunnelbox app on your phone and scan the QR code above, or enter the pairing code manually in the app.",
1033
1030
  "qr.titleNoType": "tunnelbox phone pairing",
1034
1031
  "qr.titleWithType": "tunnelbox {type} phone pairing",
@@ -1438,7 +1435,6 @@ var ja_JP_default = {
1438
1435
  "perm.promptResource": "opencode \u304C\u30EA\u30BD\u30FC\u30B9\u3078\u306E\u30A2\u30AF\u30BB\u30B9\u3092\u8981\u6C42: {list}",
1439
1436
  "perm.promptTool": "opencode \u304C {tool} \u306E\u5B9F\u884C\u3092\u8981\u6C42",
1440
1437
  "qr.codeLabel": "\u30DA\u30A2\u30EA\u30F3\u30B0\u30B3\u30FC\u30C9",
1441
- "qr.fileWritten": "\u30DA\u30A2\u30EA\u30F3\u30B0\u60C5\u5831\u3092\u66F8\u304D\u8FBC\u307F\u307E\u3057\u305F: {path}",
1442
1438
  "qr.openHint": "tunnelbox App \u3092\u958B\u304D\u3001\u4E0A\u306E QR \u30B3\u30FC\u30C9\u3092\u30B9\u30AD\u30E3\u30F3\u3059\u308B\u304B\u3001App \u3067\u30DA\u30A2\u30EA\u30F3\u30B0\u30B3\u30FC\u30C9\u3092\u624B\u52D5\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
1443
1439
  "qr.titleNoType": "tunnelbox \u30B9\u30DE\u30DB\u30DA\u30A2\u30EA\u30F3\u30B0",
1444
1440
  "qr.titleWithType": "tunnelbox {type} \u30B9\u30DE\u30DB\u30DA\u30A2\u30EA\u30F3\u30B0",
@@ -1848,7 +1844,6 @@ var ko_KR_default = {
1848
1844
  "perm.promptResource": "opencode\uAC00 \uB9AC\uC18C\uC2A4 \uC811\uADFC\uC744 \uC694\uCCAD: {list}",
1849
1845
  "perm.promptTool": "opencode\uAC00 {tool} \uC2E4\uD589\uC744 \uC694\uCCAD",
1850
1846
  "qr.codeLabel": "\uD398\uC5B4\uB9C1 \uCF54\uB4DC",
1851
- "qr.fileWritten": "\uD398\uC5B4\uB9C1 \uC815\uBCF4\uAC00 \uAE30\uB85D\uB428: {path}",
1852
1847
  "qr.openHint": "tunnelbox \uC571\uC744 \uC5F4\uACE0 \uC704 QR \uCF54\uB4DC\uB97C \uC2A4\uCE94\uD558\uAC70\uB098, \uC571\uC5D0\uC11C \uD398\uC5B4\uB9C1 \uCF54\uB4DC\uB97C \uC9C1\uC811 \uC785\uB825\uD558\uC138\uC694.",
1853
1848
  "qr.titleNoType": "tunnelbox \uD734\uB300\uD3F0 \uD398\uC5B4\uB9C1",
1854
1849
  "qr.titleWithType": "tunnelbox {type} \uD734\uB300\uD3F0 \uD398\uC5B4\uB9C1",
@@ -2258,7 +2253,6 @@ var fr_FR_default = {
2258
2253
  "perm.promptResource": "opencode demande l'acc\xE8s aux ressources : {list}",
2259
2254
  "perm.promptTool": "opencode demande d'ex\xE9cuter {tool}",
2260
2255
  "qr.codeLabel": "Code d'appairage",
2261
- "qr.fileWritten": "Informations d'appairage \xE9crites dans : {path}",
2262
2256
  "qr.openHint": "Ouvrez l'application tunnelbox sur votre t\xE9l\xE9phone et scannez le QR ci-dessus, ou saisissez le code d'appairage manuellement dans l'application.",
2263
2257
  "qr.titleNoType": "appairage t\xE9l\xE9phone tunnelbox",
2264
2258
  "qr.titleWithType": "appairage t\xE9l\xE9phone tunnelbox {type}",
@@ -2668,7 +2662,6 @@ var de_DE_default = {
2668
2662
  "perm.promptResource": "opencode fordert Zugriff auf Ressourcen: {list}",
2669
2663
  "perm.promptTool": "opencode fordert die Ausf\xFChrung von {tool} an",
2670
2664
  "qr.codeLabel": "Pairing-Code",
2671
- "qr.fileWritten": "Pairing-Informationen geschrieben in: {path}",
2672
2665
  "qr.openHint": "\xD6ffnen Sie die tunnelbox-App auf dem Telefon und scannen Sie den QR-Code oben, oder geben Sie den Pairing-Code manuell in der App ein.",
2673
2666
  "qr.titleNoType": "tunnelbox Telefon-Pairing",
2674
2667
  "qr.titleWithType": "tunnelbox {type} Telefon-Pairing",
@@ -3078,7 +3071,6 @@ var es_ES_default = {
3078
3071
  "perm.promptResource": "opencode solicita acceso a los recursos: {list}",
3079
3072
  "perm.promptTool": "opencode solicita ejecutar {tool}",
3080
3073
  "qr.codeLabel": "C\xF3digo de emparejamiento",
3081
- "qr.fileWritten": "Informaci\xF3n de emparejamiento escrita en: {path}",
3082
3074
  "qr.openHint": "Abra la aplicaci\xF3n tunnelbox en el tel\xE9fono y escanee el c\xF3digo QR superior, o introduzca el c\xF3digo de emparejamiento manualmente en la aplicaci\xF3n.",
3083
3075
  "qr.titleNoType": "emparejamiento de tel\xE9fono tunnelbox",
3084
3076
  "qr.titleWithType": "emparejamiento de tel\xE9fono tunnelbox {type}",
@@ -3523,8 +3515,6 @@ function loadState(type) {
3523
3515
  if (parsed.agentId && parsed.agentId.length >= 16) {
3524
3516
  return {
3525
3517
  agentId: parsed.agentId,
3526
- relayUrl: parsed.relayUrl || "",
3527
- claimed: parsed.claimed === true,
3528
3518
  lang: parsed.lang ? normalizeLang(parsed.lang) : void 0
3529
3519
  };
3530
3520
  }
@@ -3535,26 +3525,6 @@ function loadState(type) {
3535
3525
  return fallback;
3536
3526
  }
3537
3527
  }
3538
- function writePairingFile(code, type, lang) {
3539
- const p = join(baseName(), `remote-pairing${suffix(type)}.txt`);
3540
- try {
3541
- mkdirSync(dirname(p), { recursive: true });
3542
- const label = t(lang ?? resolveLang(), "qr.codeLabel");
3543
- writeFileSync(p, `${label}: ${code}
3544
- `, "utf8");
3545
- } catch {
3546
- }
3547
- return p;
3548
- }
3549
- function writePairingJson(info, type) {
3550
- const p = join(baseName(), `remote-pairing${suffix(type)}.json`);
3551
- try {
3552
- mkdirSync(dirname(p), { recursive: true });
3553
- writeFileSync(p, JSON.stringify(info, null, 2), "utf8");
3554
- } catch {
3555
- }
3556
- return p;
3557
- }
3558
3528
  function injectedRelayUrl() {
3559
3529
  return "wss://relay.tunnelbox.top" ? "wss://relay.tunnelbox.top".replace(/\/+$/, "") : "";
3560
3530
  }
@@ -3604,7 +3574,6 @@ function padVisual(s, width, align = "left") {
3604
3574
  }
3605
3575
  async function printPairing(code, type, name2, lang) {
3606
3576
  const resolved = lang ? normalizeLang(lang) : resolveLang();
3607
- const file = writePairingFile(code, type, resolved);
3608
3577
  const tt = (key, vars) => t(resolved, key, vars);
3609
3578
  const title = type ? tt("qr.titleWithType", { type }) : tt("qr.titleNoType");
3610
3579
  const codeLine = `${tt("qr.codeLabel")}: ${code}`;
@@ -3632,7 +3601,6 @@ async function printPairing(code, type, name2, lang) {
3632
3601
  } catch {
3633
3602
  console.log(" " + tt("qr.unavailable"));
3634
3603
  }
3635
- console.log(" " + tt("qr.fileWritten", { path: file }));
3636
3604
  console.log("");
3637
3605
  }
3638
3606
  var DEFAULT_PAGE_SIZE = 20;
@@ -3986,8 +3954,19 @@ import { join as join2 } from "node:path";
3986
3954
  function dshHome() {
3987
3955
  return process.env.DSH_HOME || join2(homedir2(), ".dsh");
3988
3956
  }
3989
- function release(prep) {
3990
- const p = prep;
3957
+ function headerOf(s) {
3958
+ if (s.header && typeof s.header.id === "string") return s.header;
3959
+ return { id: s.id ?? "", createdAt: s.createdAt ?? 0, cwd: s.cwd };
3960
+ }
3961
+ async function release(h) {
3962
+ const p = h;
3963
+ if (typeof p?.close === "function") {
3964
+ try {
3965
+ await p.close();
3966
+ } catch {
3967
+ }
3968
+ return;
3969
+ }
3991
3970
  const d = typeof p?.dispose === "function" ? p.dispose : typeof p?.[Symbol.dispose] === "function" ? p[Symbol.dispose] : void 0;
3992
3971
  if (typeof d === "function") {
3993
3972
  try {
@@ -4008,20 +3987,36 @@ function titleOf(events) {
4008
3987
  return sessionTitle(msgs) || "";
4009
3988
  }
4010
3989
  async function readSessionEvents(sp, sessionId) {
3990
+ if (typeof sp.open === "function") {
3991
+ const handle = await sp.open(sessionId, "read");
3992
+ try {
3993
+ const result = await handle.read();
3994
+ return [...result.events];
3995
+ } finally {
3996
+ await release(handle);
3997
+ }
3998
+ }
4011
3999
  if (typeof sp.inspect === "function") {
4012
4000
  const view = await sp.inspect(sessionId);
4013
4001
  return [...view.events ?? []];
4014
4002
  }
4015
- const prep = await sp.prepare(sessionId);
4016
- try {
4017
- return [...prep.session.events];
4018
- } finally {
4019
- release(prep);
4003
+ if (typeof sp.prepare === "function") {
4004
+ const prep = await sp.prepare(sessionId);
4005
+ try {
4006
+ return [...prep.session.events];
4007
+ } finally {
4008
+ await release(prep);
4009
+ }
4020
4010
  }
4011
+ return [];
4021
4012
  }
4022
4013
  async function sessionExists(sp, sessionId) {
4014
+ if (typeof sp.stat === "function") {
4015
+ const snap = await sp.stat(sessionId).catch(() => void 0);
4016
+ return !!snap;
4017
+ }
4023
4018
  const headers = await sp.list().catch(() => []);
4024
- return headers.some((h) => h.id === sessionId);
4019
+ return headers.some((h) => headerOf(h).id === sessionId);
4025
4020
  }
4026
4021
  async function sessionInfo(sp, h, t2) {
4027
4022
  let events = [];
@@ -4044,7 +4039,9 @@ async function sessionInfo(sp, h, t2) {
4044
4039
  async function listSessions(sp, workspace, t2) {
4045
4040
  const headers = await sp.list().catch(() => []);
4046
4041
  const out = [];
4047
- for (const h of headers) {
4042
+ for (const raw of headers) {
4043
+ const h = headerOf(raw);
4044
+ if (!h.id) continue;
4048
4045
  if (workspace && h.cwd !== workspace) continue;
4049
4046
  const s = await sessionInfo(sp, h, t2);
4050
4047
  if (s) out.push(s);
@@ -4054,7 +4051,8 @@ async function listSessions(sp, workspace, t2) {
4054
4051
  async function listWorkspaces(sp, current) {
4055
4052
  const headers = await sp.list().catch(() => []);
4056
4053
  const byPath = /* @__PURE__ */ new Map();
4057
- for (const h of headers) {
4054
+ for (const raw of headers) {
4055
+ const h = headerOf(raw);
4058
4056
  const p = h.cwd;
4059
4057
  if (!p) continue;
4060
4058
  const e = byPath.get(p) ?? { count: 0, updated: 0 };
@@ -4104,7 +4102,7 @@ function findDir(dir, name2) {
4104
4102
  }
4105
4103
 
4106
4104
  // src/bridge.ts
4107
- var VERSION = true ? "0.1.29" : "0.0.0-dev";
4105
+ var VERSION = true ? "0.1.32" : "0.0.0-dev";
4108
4106
  var AGENT_TYPE = "dsh";
4109
4107
  var APPROVAL_TIMEOUT_MS = 12e4;
4110
4108
  var ADAPTER_COMMANDS = [
@@ -4122,7 +4120,7 @@ var TunnelboxBridge = class {
4122
4120
  }
4123
4121
  ws = new RelayClient();
4124
4122
  state = loadState(AGENT_TYPE);
4125
- claimed = !!this.state.claimed;
4123
+ paired = false;
4126
4124
  everConnected = false;
4127
4125
  relayBase = "";
4128
4126
  /** sessionID → 活动 AgentHandle(本进程生命周期)。 */
@@ -4240,7 +4238,6 @@ ${err.stack}` : ""));
4240
4238
  timezone: localTimezone()
4241
4239
  };
4242
4240
  this.send(envelope("agent.info", info));
4243
- if (!this.claimed) this.send(envelope("pair.create", {}));
4244
4241
  }
4245
4242
  getSessionPersistence() {
4246
4243
  return this.ctx.get("sessionPersistence");
@@ -4250,17 +4247,17 @@ ${err.stack}` : ""));
4250
4247
  switch (env.type) {
4251
4248
  case "pair.created": {
4252
4249
  const code = env.payload.code;
4253
- writePairingJson({ code, relayUrl: this.relayBase, at: Date.now() }, AGENT_TYPE);
4254
4250
  this.log(this.t("adapter.logPairCode", { code }));
4255
4251
  void printPairing(code, AGENT_TYPE, hostname(), this.lang);
4256
4252
  return;
4257
4253
  }
4258
- case "agent.claimed":
4259
- this.claimed = true;
4260
- this.state.claimed = true;
4261
- saveState(this.state, AGENT_TYPE);
4262
- this.log(this.t("adapter.logClaimed"));
4254
+ case "agent.status": {
4255
+ const status = env.payload;
4256
+ this.paired = status?.claimed === true;
4257
+ if (this.paired) this.log(this.t("adapter.logClaimed"));
4258
+ else this.send(envelope("pair.create", {}));
4263
4259
  return;
4260
+ }
4264
4261
  case "agent.revoked":
4265
4262
  this.resetIdentity();
4266
4263
  return;
@@ -4947,9 +4944,8 @@ ${err.stack}` : ""));
4947
4944
  }
4948
4945
  resetIdentity() {
4949
4946
  this.log(this.t("adapter.logResetIdentity"));
4950
- this.claimed = false;
4947
+ this.paired = false;
4951
4948
  this.state.agentId = randomBytes2(16).toString("hex");
4952
- this.state.claimed = false;
4953
4949
  saveState(this.state, AGENT_TYPE);
4954
4950
  this.ws.close();
4955
4951
  this.connect(this.relayBase);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tunnelbox/dsh-tunnelbox",
3
- "version": "0.1.29",
3
+ "version": "0.1.32",
4
4
  "description": "tunnelbox 的 dsh 原生 Cordis 插件:手机远程驱动 DeepSeek Harness(agent/session/tools/审批/中止)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.mjs",
@@ -36,7 +36,7 @@
36
36
  "@deepseek-ai/schemastery": "^3.18.1"
37
37
  },
38
38
  "devDependencies": {
39
- "@tunnelbox/core": "0.1.29",
39
+ "@tunnelbox/core": "0.1.32",
40
40
  "@types/node": "^22.0.0",
41
41
  "esbuild": "^0.24.0",
42
42
  "typescript": "^5.4.5"