@clawos-dev/clawd 0.2.304 → 0.2.305

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 +93 -32
  2. package/package.json +1 -1
package/dist/cli.cjs CHANGED
@@ -52240,8 +52240,18 @@ function createLarkBotCloudClient(opts) {
52240
52240
  await request("POST", "/api/lark-bot/reply", { ...args });
52241
52241
  },
52242
52242
  async claimEvents() {
52243
- const json = await request("POST", "/api/lark-bot/events/claim");
52244
- return json.items ?? [];
52243
+ const json = await request("POST", "/api/lark-bot/events/claim?v=2");
52244
+ const items = json.items ?? [];
52245
+ return items.map((it) => {
52246
+ const rec3 = it;
52247
+ if (rec3 && typeof rec3 === "object" && "payload" in rec3) {
52248
+ return {
52249
+ status: rec3.status === "forwarded" ? "forwarded" : "received",
52250
+ payload: rec3.payload
52251
+ };
52252
+ }
52253
+ return { status: "received", payload: it };
52254
+ });
52245
52255
  },
52246
52256
  async fetchResource(appId, messageId, fileKey, maxBytes, type) {
52247
52257
  const ac = new AbortController();
@@ -52285,6 +52295,8 @@ var import_node_fs27 = __toESM(require("fs"), 1);
52285
52295
  var import_node_path28 = __toESM(require("path"), 1);
52286
52296
  init_protocol();
52287
52297
  var ERROR_REPLY_TEXT = "\u5904\u7406\u51FA\u9519\u4E86\uFF0C\u8BF7\u91CD\u8BD5";
52298
+ var LOCAL_TURN_RETRIES = 2;
52299
+ var STOPPED_ERROR = "session stopped before reply";
52288
52300
  var DEBOUNCE_MS = 1e3;
52289
52301
  var MAX_IMAGE_BYTES = 8 * 1024 * 1024;
52290
52302
  var EXT_BY_MIME = {
@@ -52310,6 +52322,16 @@ function safeAttachmentName(raw) {
52310
52322
  const ext = dot > 0 && cleaned.length - dot <= 20 ? cleaned.slice(dot) : "";
52311
52323
  return cleaned.slice(0, 100 - ext.length) + ext;
52312
52324
  }
52325
+ function routeClaimedEvents(items, opts) {
52326
+ const resume = [];
52327
+ for (const it of items) {
52328
+ opts.dedupe.add(it.payload.eventId);
52329
+ const env = { ...it.payload, iat: opts.nowSec, exp: opts.nowSec + 300 };
52330
+ if (it.status === "forwarded" && it.payload.type === "message") resume.push(env);
52331
+ else opts.router.handleEnvelope(env);
52332
+ }
52333
+ if (resume.length > 0) opts.router.handleResume(resume);
52334
+ }
52313
52335
  function createLarkChatRouter(deps) {
52314
52336
  const replyDelays = deps.replyRetryDelaysMs ?? [2e3, 8e3, 3e4];
52315
52337
  const sleep2 = deps.sleepImpl ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
@@ -52385,7 +52407,15 @@ function createLarkChatRouter(deps) {
52385
52407
  if (j === i - 1) return void 0;
52386
52408
  return `[\u56DE\u590D\u7B2C${j + 1}\u6761]`;
52387
52409
  };
52388
- const runBatch = async (batchEnvs) => {
52410
+ const makeResumeText = (body, speaker) => `\u7EE7\u7EED
52411
+
52412
+ <system-reminder>\u300C\u7EE7\u7EED\u300D\u7531\u7CFB\u7EDF\u4EE3\u53D1\uFF1A\u6B64\u524D\u5904\u7406\u4EE5\u4E0B\u6D88\u606F\u65F6\u6267\u884C\u88AB\u6253\u65AD\u3002\u82E5\u4E0A\u6587\u5DF2\u6709\u5B83\u7684\u5904\u7406\u8FDB\u5EA6\uFF0C\u63A5\u7740\u5B8C\u6210\u672A\u5B8C\u6210\u7684\u90E8\u5206\uFF1B\u82E5\u4E0A\u6587\u6CA1\u6709\u76F8\u5173\u8BB0\u5F55\uFF0C\u628A\u4EE5\u4E0B\u5185\u5BB9\u5F53\u4F5C\u65B0\u6536\u5230\u7684\u6D88\u606F\u5904\u7406\u3002\u5904\u7406\u5B8C\u6309\u5E73\u5E38\u65B9\u5F0F\u56DE\u590D\uFF1A
52413
+ ---
52414
+ ${body}
52415
+ ---
52416
+ \uFF08\u6765\u81EA\u98DE\u4E66\u7FA4\u6210\u5458 ${speaker}\uFF09</system-reminder>`;
52417
+ const runBatch = async (batchEnvs, opts) => {
52418
+ if (deps.isShuttingDown?.()) return;
52389
52419
  const envs = batchEnvs.filter((e) => {
52390
52420
  if (e.messageId) return true;
52391
52421
  deps.logger?.warn(`larkBot chat-router: message envelope missing messageId, drop ${e.eventId}`);
@@ -52397,30 +52427,47 @@ function createLarkChatRouter(deps) {
52397
52427
  const idxByMessageId = new Map(envs.map((e, i) => [e.messageId, i]));
52398
52428
  const sections = [];
52399
52429
  for (const [i, env] of envs.entries()) {
52400
- const body2 = await buildSection(env);
52401
- const section = [quoteAnnotation(env, i, idxByMessageId), body2].filter(Boolean).join("\n");
52430
+ const sectionBody = await buildSection(env);
52431
+ const section = [quoteAnnotation(env, i, idxByMessageId), sectionBody].filter(Boolean).join("\n");
52402
52432
  if (section) sections.push(section);
52403
52433
  }
52404
52434
  const body = sections.join("\n") || "[\u975E\u6587\u672C\u6D88\u606F]";
52405
- const text = `${body}
52406
-
52407
- ${formatLarkSpeakerReminder(speaker)}`;
52408
- const turn = deps.manager.runLarkChatTurn({
52409
- personaId: last.personaId,
52410
- chatId: last.chatId,
52411
- chatName: last.chatName,
52412
- chatType: last.chatType ?? "group",
52413
- senderOpenId: last.senderOpenId ?? "",
52414
- senderName: last.senderName ?? last.senderOpenId ?? "\u672A\u77E5\u6210\u5458",
52415
- text
52416
- });
52417
- activity.set(last.chatId, {
52418
- chatId: last.chatId,
52419
- chatName: last.chatName,
52420
- lastActiveAt: Date.now(),
52421
- personaId: last.personaId
52422
- });
52423
- const result = await turn.ended;
52435
+ const runTurn = (text) => {
52436
+ const turn = deps.manager.runLarkChatTurn({
52437
+ personaId: last.personaId,
52438
+ chatId: last.chatId,
52439
+ chatName: last.chatName,
52440
+ chatType: last.chatType ?? "group",
52441
+ senderOpenId: last.senderOpenId ?? "",
52442
+ senderName: last.senderName ?? last.senderOpenId ?? "\u672A\u77E5\u6210\u5458",
52443
+ text
52444
+ });
52445
+ activity.set(last.chatId, {
52446
+ chatId: last.chatId,
52447
+ chatName: last.chatName,
52448
+ lastActiveAt: Date.now(),
52449
+ personaId: last.personaId
52450
+ });
52451
+ return turn.ended;
52452
+ };
52453
+ let result = await runTurn(
52454
+ opts?.resume ? makeResumeText(body, speaker) : `${body}
52455
+
52456
+ ${formatLarkSpeakerReminder(speaker)}`
52457
+ );
52458
+ for (let retry = 0; !("ok" in result); ) {
52459
+ if (deps.isShuttingDown?.()) {
52460
+ deps.logger?.info(`larkBot turn interrupted by shutdown (${last.chatId}), left for claim`);
52461
+ return;
52462
+ }
52463
+ if (result.error === STOPPED_ERROR) break;
52464
+ if (retry >= LOCAL_TURN_RETRIES) break;
52465
+ retry++;
52466
+ deps.logger?.warn(
52467
+ `larkBot turn error (${last.chatId}): ${result.error}; resume retry ${retry}/${LOCAL_TURN_RETRIES}`
52468
+ );
52469
+ result = await runTurn(makeResumeText(body, speaker));
52470
+ }
52424
52471
  const replyText = "ok" in result && result.ok ? result.replyText : ERROR_REPLY_TEXT;
52425
52472
  if (!("ok" in result)) {
52426
52473
  deps.logger?.warn(`larkBot turn error (${last.chatId}): ${result.error}`);
@@ -52445,11 +52492,11 @@ ${formatLarkSpeakerReminder(speaker)}`;
52445
52492
  }
52446
52493
  }
52447
52494
  };
52448
- const enqueueBatch = (batchEnvs) => {
52495
+ const enqueueBatch = (batchEnvs, opts) => {
52449
52496
  const chatId = batchEnvs[0].chatId;
52450
52497
  const prev = queues.get(chatId) ?? Promise.resolve();
52451
52498
  const next = prev.then(
52452
- () => runBatch(batchEnvs).catch(
52499
+ () => runBatch(batchEnvs, opts).catch(
52453
52500
  (err) => deps.logger?.warn(`larkBot chat-router runBatch failed: ${err.message}`)
52454
52501
  )
52455
52502
  );
@@ -52495,6 +52542,17 @@ ${formatLarkSpeakerReminder(speaker)}`;
52495
52542
  });
52496
52543
  }
52497
52544
  },
52545
+ handleResume(envelopes) {
52546
+ const groups = /* @__PURE__ */ new Map();
52547
+ for (const env of envelopes) {
52548
+ if (env.type !== "message") continue;
52549
+ const key = `${env.chatId}|${env.senderOpenId ?? ""}`;
52550
+ const group = groups.get(key);
52551
+ if (group) group.push(env);
52552
+ else groups.set(key, [env]);
52553
+ }
52554
+ for (const group of groups.values()) enqueueBatch(group, { resume: true });
52555
+ },
52498
52556
  listLarkSessions(personaId2) {
52499
52557
  return [...activity.values()].filter((a) => a.personaId === personaId2).map((a) => ({ chatId: a.chatId, chatName: a.chatName, lastActiveAt: a.lastActiveAt }));
52500
52558
  }
@@ -59254,7 +59312,7 @@ function computeMethodAccess(args) {
59254
59312
  }
59255
59313
 
59256
59314
  // src/version.ts
59257
- var version = "0.2.304".length > 0 ? "0.2.304" : "dev";
59315
+ var version = "0.2.305".length > 0 ? "0.2.305" : "dev";
59258
59316
 
59259
59317
  // src/cli-probe/probe.ts
59260
59318
  var fs56 = __toESM(require("fs"), 1);
@@ -63268,6 +63326,7 @@ async function startDaemon(config) {
63268
63326
  deviceId: authFile.deviceId,
63269
63327
  displayName: ownerDisplayName
63270
63328
  });
63329
+ let larkDraining = false;
63271
63330
  const larkChatRouter = createLarkChatRouter({
63272
63331
  manager,
63273
63332
  cloud: larkBotCloud,
@@ -63275,6 +63334,7 @@ async function startDaemon(config) {
63275
63334
  fetchResource: (appId, messageId, fileKey, maxBytes, type) => larkBotCloud.fetchResource(appId, messageId, fileKey, maxBytes, type),
63276
63335
  // 图片落 guest userWorkDir 下(capId = lark-<chat_id>):CC 经 --add-dir + allowRead carve 可 Read
63277
63336
  mediaRootFor: (chatId) => import_node_path65.default.join(deriveUserWorkDir(`lark-${chatId}`, usersRoot), "lark-media"),
63337
+ isShuttingDown: () => larkDraining,
63278
63338
  logger: {
63279
63339
  warn: (msg) => logger.warn(msg),
63280
63340
  info: (msg) => logger.info(msg)
@@ -63543,11 +63603,11 @@ async function startDaemon(config) {
63543
63603
  if (larkBotDeps.listBoundPersonaIds().length === 0) return;
63544
63604
  try {
63545
63605
  const items = await larkBotCloud.claimEvents();
63546
- const nowSec = Math.floor(Date.now() / 1e3);
63547
- for (const it of items) {
63548
- larkEventDedupe.add(it.eventId);
63549
- larkChatRouter.handleEnvelope({ ...it, iat: nowSec, exp: nowSec + 300 });
63550
- }
63606
+ routeClaimedEvents(items, {
63607
+ router: larkChatRouter,
63608
+ dedupe: larkEventDedupe,
63609
+ nowSec: Math.floor(Date.now() / 1e3)
63610
+ });
63551
63611
  if (items.length > 0) logger.info("larkBot pending events claimed", { count: items.length });
63552
63612
  } catch (err) {
63553
63613
  logger.warn("larkBot pending events claim failed", { err: err.message });
@@ -63623,6 +63683,7 @@ ${bar}
63623
63683
  attachmentGcInterval.unref();
63624
63684
  const shutdown = async () => {
63625
63685
  logger.info("stopping clawd");
63686
+ larkDraining = true;
63626
63687
  clearInterval(attachmentGcInterval);
63627
63688
  observer.stopAll();
63628
63689
  manager.stopAll();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clawos-dev/clawd",
3
- "version": "0.2.304",
3
+ "version": "0.2.305",
4
4
  "description": "Standalone clawd daemon — Claude Code (and future Codex) session server over WebSocket",
5
5
  "type": "module",
6
6
  "license": "MIT",