@clawos-dev/clawd 0.2.531 → 0.2.532

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.
Files changed (2) hide show
  1. package/dist/cli.cjs +63 -10
  2. package/package.json +1 -1
package/dist/cli.cjs CHANGED
@@ -67443,7 +67443,8 @@ function loadOrCreateAuthFile(opts) {
67443
67443
  token: existing.token,
67444
67444
  ownerPrincipalId: existing.ownerPrincipalId,
67445
67445
  deviceId: existing.deviceId,
67446
- createdAt: existing.createdAt ?? (/* @__PURE__ */ new Date(0)).toISOString()
67446
+ createdAt: existing.createdAt ?? (/* @__PURE__ */ new Date(0)).toISOString(),
67447
+ ...existing.tunnelDeviceKey ? { tunnelDeviceKey: existing.tunnelDeviceKey } : {}
67447
67448
  };
67448
67449
  }
67449
67450
  const token = existing?.token || generate();
@@ -67451,9 +67452,17 @@ function loadOrCreateAuthFile(opts) {
67451
67452
  const deviceId = ownerPrincipalId;
67452
67453
  const createdAt = existing?.createdAt || now().toISOString();
67453
67454
  const next = { token, ownerPrincipalId, deviceId, createdAt };
67455
+ if (existing?.tunnelDeviceKey) next.tunnelDeviceKey = existing.tunnelDeviceKey;
67454
67456
  writeAuthFile(file, next);
67455
67457
  return next;
67456
67458
  }
67459
+ function loadOrCreateTunnelDeviceKey(opts) {
67460
+ const current = loadOrCreateAuthFile(opts);
67461
+ if (current.tunnelDeviceKey) return current.tunnelDeviceKey;
67462
+ const tunnelDeviceKey = opts.derive();
67463
+ writeAuthFile(authFilePath(opts.dataDir), { ...current, tunnelDeviceKey });
67464
+ return tunnelDeviceKey;
67465
+ }
67457
67466
  function defaultGenerateToken() {
67458
67467
  return import_node_crypto15.default.randomBytes(32).toString("base64url");
67459
67468
  }
@@ -67472,6 +67481,7 @@ function readAuthFile(file) {
67472
67481
  ownerPrincipalId: typeof parsed.ownerPrincipalId === "string" && parsed.ownerPrincipalId.length > 0 ? parsed.ownerPrincipalId : void 0,
67473
67482
  deviceId: typeof parsed.deviceId === "string" && parsed.deviceId.length > 0 ? parsed.deviceId : void 0,
67474
67483
  createdAt: typeof parsed.createdAt === "string" ? parsed.createdAt : void 0,
67484
+ tunnelDeviceKey: typeof parsed.tunnelDeviceKey === "string" && parsed.tunnelDeviceKey.length > 0 ? parsed.tunnelDeviceKey : void 0,
67475
67485
  // 单 secret 合并前的旧字段:出现即触发清理写回(值无所谓,硬切不再使用)
67476
67486
  hasLegacySecrets: "signSecret" in parsed || "visitorTokenSecret" in parsed
67477
67487
  };
@@ -67806,22 +67816,51 @@ var lastPeers = [];
67806
67816
  function getCachedOrgPeers() {
67807
67817
  return lastPeers;
67808
67818
  }
67819
+ function sameOrigin(a2, b3) {
67820
+ const oa2 = toOrigin(a2);
67821
+ const ob = toOrigin(b3);
67822
+ return oa2 != null && ob != null ? oa2 === ob : a2 === b3;
67823
+ }
67824
+ function toOrigin(raw) {
67825
+ const http2 = raw.replace(/^wss:\/\//i, "https://").replace(/^ws:\/\//i, "http://");
67826
+ try {
67827
+ const origin = new URL(http2).origin;
67828
+ return origin === "null" ? null : origin;
67829
+ } catch {
67830
+ return null;
67831
+ }
67832
+ }
67809
67833
  async function syncOrgMesh(deps) {
67810
67834
  const peers = await deps.fetchPeers();
67811
67835
  lastPeers = peers;
67812
67836
  if (peers.length === 0) {
67813
67837
  deps.log("org-mesh: \u4E0D\u5728\u4EFB\u4F55\u7EC4\u7EC7\uFF08\u6216\u7EC4\u91CC\u53EA\u6709\u81EA\u5DF1\uFF09\uFF0C\u8DF3\u8FC7");
67814
67838
  deps.onProgress?.({ total: 0, done: 0, connected: 0, failed: 0, active: false });
67815
- return { peers: 0, attempted: 0, connected: 0, failed: 0 };
67839
+ return { peers: 0, attempted: 0, connected: 0, failed: 0, refreshed: 0 };
67816
67840
  }
67817
67841
  const targets = [];
67842
+ let refreshed = 0;
67818
67843
  for (const p3 of peers) {
67819
67844
  for (const d2 of p3.devices) {
67820
- if (deps.store.get(d2.deviceId)) continue;
67821
- targets.push({ deviceId: d2.deviceId, displayName: p3.displayName });
67845
+ const existing = deps.store.get(d2.deviceId);
67846
+ if (!existing) {
67847
+ targets.push({ deviceId: d2.deviceId, displayName: p3.displayName });
67848
+ continue;
67849
+ }
67850
+ if (d2.url == null || sameOrigin(existing.remoteUrl, d2.url)) continue;
67851
+ const updated = { ...existing, remoteUrl: d2.url };
67852
+ deps.store.upsert(updated);
67853
+ refreshed += 1;
67854
+ deps.log("org-mesh: \u8054\u7CFB\u4EBA\u5730\u5740\u5DF2\u5237\u65B0", {
67855
+ deviceId: d2.deviceId,
67856
+ name: p3.displayName,
67857
+ from: existing.remoteUrl,
67858
+ to: d2.url
67859
+ });
67860
+ deps.onContactUpdated?.(updated);
67822
67861
  }
67823
67862
  }
67824
- deps.log("org-mesh: \u5F00\u59CB\u540C\u6B65", { peers: peers.length, targets: targets.length });
67863
+ deps.log("org-mesh: \u5F00\u59CB\u540C\u6B65", { peers: peers.length, targets: targets.length, refreshed });
67825
67864
  let connected = 0;
67826
67865
  let failed = 0;
67827
67866
  deps.onProgress?.({
@@ -67852,8 +67891,14 @@ async function syncOrgMesh(deps) {
67852
67891
  active: connected + failed < targets.length
67853
67892
  });
67854
67893
  }
67855
- deps.log("org-mesh: \u540C\u6B65\u5B8C\u6210", { peers: peers.length, attempted: targets.length, connected, failed });
67856
- return { peers: peers.length, attempted: targets.length, connected, failed };
67894
+ deps.log("org-mesh: \u540C\u6B65\u5B8C\u6210", {
67895
+ peers: peers.length,
67896
+ attempted: targets.length,
67897
+ connected,
67898
+ failed,
67899
+ refreshed
67900
+ });
67901
+ return { peers: peers.length, attempted: targets.length, connected, failed, refreshed };
67857
67902
  }
67858
67903
 
67859
67904
  // src/handlers/device.ts
@@ -70370,7 +70415,7 @@ function computeMethodAccess(args) {
70370
70415
  }
70371
70416
 
70372
70417
  // src/version.ts
70373
- var version = "0.2.531".length > 0 ? "0.2.531" : "dev";
70418
+ var version = "0.2.532".length > 0 ? "0.2.532" : "dev";
70374
70419
 
70375
70420
  // src/cli-probe/probe.ts
70376
70421
  var fs77 = __toESM(require("fs"), 1);
@@ -73728,7 +73773,10 @@ async function startDaemon(config) {
73728
73773
  connectToDevice: createConnectToDevice(feishuDeviceDeps),
73729
73774
  log: (msg, meta) => logger.info(msg, meta),
73730
73775
  // 进度上报:串行建联 20+ 台要几十秒,UI 靠这个帧渲染进度条
73731
- onProgress: (progress) => wsServer?.broadcastToOwners({ type: "org-mesh:progress", ...progress })
73776
+ onProgress: (progress) => wsServer?.broadcastToOwners({ type: "org-mesh:progress", ...progress }),
73777
+ // 已有联系人的地址被中心最新 url 刷新 → 复用 contact:added(UI reducer 按 deviceId upsert,
73778
+ // auto-reverse 重握手也发这一帧),不新增帧
73779
+ onContactUpdated: (contact) => wsServer?.broadcastToOwners({ type: "contact:added", contact })
73732
73780
  });
73733
73781
  } catch (err) {
73734
73782
  logger.warn("org-mesh sync failed (best-effort)", { err: err.message });
@@ -74479,7 +74527,12 @@ async function startDaemon(config) {
74479
74527
  tunnelMgr = new TunnelManager({
74480
74528
  dataDir: config.dataDir,
74481
74529
  clawosApi: config.clawosApi,
74482
- deviceKey: deriveStableDeviceKey({ dataDir: config.dataDir }),
74530
+ // 子域指纹落盘于 auth.json,首次缺失才由 hostname+uid 算初值——改电脑名不再换对外地址
74531
+ // (design 2026-09-16-tunnel-address-stability §3.1)
74532
+ deviceKey: loadOrCreateTunnelDeviceKey({
74533
+ dataDir: config.dataDir,
74534
+ derive: () => deriveStableDeviceKey({ dataDir: config.dataDir })
74535
+ }),
74483
74536
  frpcBinaryOverride: config.frpcBinary,
74484
74537
  noPersist: config.noTunnelPersist,
74485
74538
  logger,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clawos-dev/clawd",
3
- "version": "0.2.531",
3
+ "version": "0.2.532",
4
4
  "description": "Standalone clawd daemon — Claude Code (and future Codex) session server over WebSocket",
5
5
  "type": "module",
6
6
  "license": "MIT",