@clawos-dev/clawd 0.2.771 → 0.2.772

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 +45 -5
  2. package/package.json +1 -1
package/dist/cli.cjs CHANGED
@@ -57754,6 +57754,8 @@ var import_node_crypto12 = require("crypto");
57754
57754
  init_protocol();
57755
57755
  var A2A_SYNC_INTERVAL_MS = 3e3;
57756
57756
  var isDeliverable = (v3) => A2A_DELIVERABLE_STATES.includes(v3.state);
57757
+ var CLOUD_WAKE_REFRESH_DELAYS_MS = [1e4, 3e4, 9e4];
57758
+ var CLOUD_WAKE_RECENT_MS = 10 * 6e4;
57757
57759
  function createA2aHost(deps) {
57758
57760
  const cache2 = /* @__PURE__ */ new Map();
57759
57761
  const pending = /* @__PURE__ */ new Map();
@@ -57835,10 +57837,30 @@ function createA2aHost(deps) {
57835
57837
  }
57836
57838
  if (worker && v3.executorThreadId) deps.attachCloudWorkerThread?.(worker, v3.executorThreadId);
57837
57839
  }
57838
- if (v3.initiator.host === "cloud") return;
57840
+ if (v3.initiator.host === "cloud") {
57841
+ if (isDeliverable(v3)) scheduleWakeHistoryRefresh(session.sessionId, v3);
57842
+ return;
57843
+ }
57839
57844
  if (!isDeliverable(v3) || v3.deliveredAt) return;
57840
57845
  enqueue(session.sessionId, v3, String(changeSeq));
57841
57846
  }
57847
+ const refreshScheduled = /* @__PURE__ */ new Set();
57848
+ function scheduleWakeHistoryRefresh(sessionId, v3) {
57849
+ if (!deps.refreshCloudHistory) return;
57850
+ if (v3.finishedAt && Date.now() - Date.parse(v3.finishedAt) > CLOUD_WAKE_RECENT_MS) return;
57851
+ const key = `${v3.taskId}:${v3.state}:${v3.round}:${v3.finishedAt}`;
57852
+ if (refreshScheduled.has(key)) return;
57853
+ refreshScheduled.add(key);
57854
+ const after = deps.after ?? ((ms, fn) => {
57855
+ setTimeout(fn, ms).unref?.();
57856
+ });
57857
+ CLOUD_WAKE_REFRESH_DELAYS_MS.forEach((ms, i2) => {
57858
+ after(ms, () => {
57859
+ if (i2 === CLOUD_WAKE_REFRESH_DELAYS_MS.length - 1) refreshScheduled.delete(key);
57860
+ if (!deps.isBusy(sessionId)) deps.refreshCloudHistory(sessionId);
57861
+ });
57862
+ });
57863
+ }
57842
57864
  function enqueue(sessionId, v3, revision) {
57843
57865
  const bucket = pending.get(sessionId) ?? /* @__PURE__ */ new Map();
57844
57866
  bucket.set(v3.taskId, { view: v3, revision });
@@ -59229,7 +59251,7 @@ var CloudGatewayClient = class {
59229
59251
  }
59230
59252
  async openTurn(personaId2, opts) {
59231
59253
  const { apiKey, gatewayUrl } = await this.credentials();
59232
- const health = await this.fetchImpl(gatewayUrl + GATEWAY_ROUTES.healthz());
59254
+ const health = await this.fetchImpl(gatewayUrl + GATEWAY_ROUTES.healthz(), { signal: AbortSignal.timeout(TURN_HEALTHZ_TIMEOUT_MS) });
59233
59255
  if (!health.ok || (await health.json()).turnProtocolVersion !== 1) {
59234
59256
  throw new Error("\u4E91 gateway \u4E0D\u652F\u6301\u6309\u8F6E SSE\uFF0C\u8BF7\u5148\u5347\u7EA7 gateway");
59235
59257
  }
@@ -59339,6 +59361,8 @@ var CloudGatewayClient = class {
59339
59361
  var TURN_RETRY_BASE_MS = 250;
59340
59362
  var TURN_RETRY_MAX_MS = 3e4;
59341
59363
  var TURN_RETRY_MAX_FAILURES = 12;
59364
+ var TURN_IDLE_TIMEOUT_MS = 6e4;
59365
+ var TURN_HEALTHZ_TIMEOUT_MS = 1e4;
59342
59366
  function openHttpTurn(opts) {
59343
59367
  const { fetchImpl, gatewayUrl, apiKey, personaId: personaId2, conversationId, turnId, text, expectedEngine, engineSessionId, instructions, effort, serviceTier, personaMode, purpose, logger } = opts;
59344
59368
  const body = JSON.stringify({
@@ -59399,8 +59423,19 @@ function openHttpTurn(opts) {
59399
59423
  });
59400
59424
  void (async () => {
59401
59425
  while (!closed) {
59402
- abort = new AbortController();
59426
+ const attempt = abort = new AbortController();
59427
+ let idleTimedOut = false;
59428
+ let idleTimer;
59429
+ const armIdle = () => {
59430
+ clearTimeout(idleTimer);
59431
+ idleTimer = setTimeout(() => {
59432
+ idleTimedOut = true;
59433
+ attempt.abort();
59434
+ }, TURN_IDLE_TIMEOUT_MS);
59435
+ idleTimer.unref?.();
59436
+ };
59403
59437
  try {
59438
+ armIdle();
59404
59439
  const res = await fetchImpl(gatewayUrl + GATEWAY_ROUTES.turn(personaId2), {
59405
59440
  method: "POST",
59406
59441
  headers: {
@@ -59432,6 +59467,7 @@ function openHttpTurn(opts) {
59432
59467
  for (; ; ) {
59433
59468
  const { value, done } = await reader.read();
59434
59469
  if (done || closed) break;
59470
+ armIdle();
59435
59471
  if (value.byteLength) failures = 0;
59436
59472
  pending += decoder.decode(value, { stream: true });
59437
59473
  let delimiter2;
@@ -59467,8 +59503,11 @@ function openHttpTurn(opts) {
59467
59503
  state({ conversationId, turnId, status: "failed", errorCode: "INVALID_TURN_STREAM" });
59468
59504
  return;
59469
59505
  }
59470
- logger?.warn("cloud turn SSE disconnected; reconnecting", { message: error.message, turnId });
59506
+ logger?.warn("cloud turn SSE disconnected; reconnecting", { message: idleTimedOut ? `no data for ${TURN_IDLE_TIMEOUT_MS} ms` : error.message, turnId });
59507
+ } finally {
59508
+ clearTimeout(idleTimer);
59471
59509
  }
59510
+ if (idleTimedOut) abort = new AbortController();
59472
59511
  if (closed) return;
59473
59512
  if (++failures > TURN_RETRY_MAX_FAILURES) {
59474
59513
  state({ conversationId, turnId, status: "failed", errorCode: "GATEWAY_UNREACHABLE" });
@@ -76704,7 +76743,7 @@ function computeMethodAccess(args) {
76704
76743
  }
76705
76744
 
76706
76745
  // src/version.ts
76707
- var version = "0.2.771".length > 0 ? "0.2.771" : "dev";
76746
+ var version = "0.2.772".length > 0 ? "0.2.772" : "dev";
76708
76747
 
76709
76748
  // src/cli-probe/probe.ts
76710
76749
  var fs87 = __toESM(require("fs"), 1);
@@ -80560,6 +80599,7 @@ async function startDaemon(config) {
80560
80599
  listSessions: () => manager.list().response.sessions,
80561
80600
  isBusy: (sid) => manager.isBusy(sid),
80562
80601
  injectResult: (sid, text) => manager.injectIntoSession(sid, text, "a2a-result"),
80602
+ refreshCloudHistory: (sid) => broadcastManagerFrame({ type: "session:control", sessionId: sid, kind: CLOUD_HISTORY_REFRESH_KIND, synchronized: true }, "broadcast"),
80563
80603
  // 云 worker 会话挂到发起会话下面:本机要有这个云 persona 的镜像(会话 cwd / 引擎从它来),没有就只留在台账里
80564
80604
  mountCloudWorker: (view, initiator) => {
80565
80605
  const mirror = pickCloudMirror(personaRegistry.list(), view.targetPersonaId);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clawos-dev/clawd",
3
- "version": "0.2.771",
3
+ "version": "0.2.772",
4
4
  "description": "Standalone clawd daemon — Claude Code (and future Codex) session server over WebSocket",
5
5
  "type": "module",
6
6
  "license": "MIT",