@clawos-dev/clawd 0.2.297 → 0.2.298

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 +42 -128
  2. package/package.json +1 -1
package/dist/cli.cjs CHANGED
@@ -52021,15 +52021,14 @@ function createLarkBotCloudClient(opts) {
52021
52021
  const json = await request("POST", "/api/lark-bot/events/claim");
52022
52022
  return json.items ?? [];
52023
52023
  },
52024
- async fetchResource(appId, messageId, fileKey, maxBytes, type) {
52024
+ async fetchResource(appId, messageId, fileKey, maxBytes) {
52025
52025
  const ac = new AbortController();
52026
52026
  const timer = setTimeout(() => ac.abort(), opts.timeoutMs ?? 15e3);
52027
52027
  const qs = new URLSearchParams({
52028
52028
  appId,
52029
52029
  messageId,
52030
52030
  fileKey,
52031
- ...maxBytes ? { maxBytes: String(maxBytes) } : {},
52032
- ...type ? { type } : {}
52031
+ ...maxBytes ? { maxBytes: String(maxBytes) } : {}
52033
52032
  }).toString();
52034
52033
  let res;
52035
52034
  try {
@@ -52064,7 +52063,6 @@ var import_node_path28 = __toESM(require("path"), 1);
52064
52063
  init_protocol();
52065
52064
  var ERROR_REPLY_TEXT = "\u5904\u7406\u51FA\u9519\u4E86\uFF0C\u8BF7\u91CD\u8BD5";
52066
52065
  var DEFAULT_TURN_TIMEOUT_MS = 10 * 60 * 1e3;
52067
- var DEBOUNCE_MS = 1e3;
52068
52066
  var MAX_IMAGE_BYTES = 8 * 1024 * 1024;
52069
52067
  var EXT_BY_MIME = {
52070
52068
  "image/png": "png",
@@ -52074,35 +52072,27 @@ var EXT_BY_MIME = {
52074
52072
  };
52075
52073
  var IMAGE_OVERSIZE_TEXT = "[\u56FE\u7247\u6D88\u606F\uFF0C\u8D85\u51FA\u5927\u5C0F\u9650\u5236]";
52076
52074
  var IMAGE_UNAVAILABLE_TEXT = "[\u56FE\u7247\u6D88\u606F\uFF0C\u6682\u4E0D\u652F\u6301\u67E5\u770B]";
52077
- var MAX_FILE_BYTES = 20 * 1024 * 1024;
52078
- var FILE_OVERSIZE_TEXT = (name) => `[\u6587\u4EF6: ${name}\uFF0C\u8D85\u51FA\u5927\u5C0F\u9650\u5236]`;
52079
- var FILE_UNAVAILABLE_TEXT = (name) => `[\u6587\u4EF6: ${name}\uFF0C\u62C9\u53D6\u5931\u8D25]`;
52080
52075
  function safeMediaName(raw) {
52081
52076
  const cleaned = raw.replace(/[^a-zA-Z0-9_\-.]/g, "_").replace(/^\.+/, (d) => "_".repeat(d.length));
52082
52077
  return (cleaned || "msg").replace(/\.\./g, "__");
52083
52078
  }
52084
- function safeAttachmentName(raw) {
52085
- const cleaned = raw.replace(/[/\\\u0000-\u001f]/g, "_").replace(/\.\./g, "__").replace(/^\.+/, (d) => "_".repeat(d.length));
52086
- if (!cleaned) return "file";
52087
- if (cleaned.length <= 100) return cleaned;
52088
- const dot = cleaned.lastIndexOf(".");
52089
- const ext = dot > 0 && cleaned.length - dot <= 20 ? cleaned.slice(dot) : "";
52090
- return cleaned.slice(0, 100 - ext.length) + ext;
52091
- }
52092
52079
  function createLarkChatRouter(deps) {
52093
52080
  const timeoutMs = deps.turnTimeoutMs ?? DEFAULT_TURN_TIMEOUT_MS;
52094
52081
  const replyDelays = deps.replyRetryDelaysMs ?? [2e3, 8e3, 3e4];
52095
52082
  const sleep2 = deps.sleepImpl ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
52096
- const debounceMs = deps.debounceMs ?? DEBOUNCE_MS;
52097
52083
  const queues = /* @__PURE__ */ new Map();
52098
52084
  const activity = /* @__PURE__ */ new Map();
52099
- const pending = /* @__PURE__ */ new Map();
52100
- const buildSection = async (env) => {
52085
+ const runOne = async (env) => {
52086
+ if (!env.messageId) {
52087
+ deps.logger?.warn(`larkBot chat-router: message envelope missing messageId, drop ${env.eventId}`);
52088
+ return;
52089
+ }
52090
+ const speaker = env.senderName || env.senderOpenId || "\u672A\u77E5\u6210\u5458";
52101
52091
  const imageLines = [];
52102
52092
  for (const [i, key] of (env.imageKeys ?? []).entries()) {
52103
52093
  try {
52104
52094
  if (!deps.fetchResource || !deps.mediaRootFor) throw new Error("resource pipeline not wired");
52105
- const r = await deps.fetchResource(env.appId, env.messageId, key, MAX_IMAGE_BYTES, "image");
52095
+ const r = await deps.fetchResource(env.appId, env.messageId, key, MAX_IMAGE_BYTES);
52106
52096
  if (r.data.byteLength > MAX_IMAGE_BYTES) {
52107
52097
  deps.logger?.warn(`larkBot image oversize ${key}: ${r.data.byteLength}B`);
52108
52098
  imageLines.push(IMAGE_OVERSIZE_TEXT);
@@ -52124,69 +52114,25 @@ function createLarkChatRouter(deps) {
52124
52114
  imageLines.push(IMAGE_UNAVAILABLE_TEXT);
52125
52115
  }
52126
52116
  }
52127
- const fileLines = [];
52128
- for (const [i, f] of (env.files ?? []).entries()) {
52129
- try {
52130
- if (!deps.fetchResource || !deps.mediaRootFor) throw new Error("resource pipeline not wired");
52131
- const r = await deps.fetchResource(env.appId, env.messageId, f.key, MAX_FILE_BYTES, "file");
52132
- if (r.data.byteLength > MAX_FILE_BYTES) {
52133
- deps.logger?.warn(`larkBot file oversize ${f.key}: ${r.data.byteLength}B`);
52134
- fileLines.push(FILE_OVERSIZE_TEXT(f.name));
52135
- continue;
52136
- }
52137
- const dir = deps.mediaRootFor(env.chatId);
52138
- import_node_fs27.default.mkdirSync(dir, { recursive: true });
52139
- const p2 = import_node_path28.default.join(dir, `${safeMediaName(env.messageId)}-${i}-${safeAttachmentName(f.name)}`);
52140
- import_node_fs27.default.writeFileSync(p2, r.data);
52141
- fileLines.push(`[\u6587\u4EF6: ${p2}]\uFF08\u7528 Read \u5DE5\u5177\u67E5\u770B\uFF09`);
52142
- } catch (err) {
52143
- deps.logger?.warn(`larkBot file fetch failed ${f.key}: ${err.message}`);
52144
- fileLines.push(FILE_UNAVAILABLE_TEXT(f.name));
52145
- }
52146
- }
52147
- return [env.text?.trim(), ...imageLines, ...fileLines].filter(Boolean).join("\n");
52148
- };
52149
- const quoteAnnotation = (env, i, idxByMessageId) => {
52150
- if (!env.parentMessageId) return void 0;
52151
- const j = idxByMessageId.get(env.parentMessageId);
52152
- if (j === void 0) return "[\u56DE\u590D\u66F4\u65E9\u7684\u4E00\u6761\u6D88\u606F]";
52153
- if (j === i - 1) return void 0;
52154
- return `[\u56DE\u590D\u7B2C${j + 1}\u6761]`;
52155
- };
52156
- const runBatch = async (batchEnvs) => {
52157
- const envs = batchEnvs.filter((e) => {
52158
- if (e.messageId) return true;
52159
- deps.logger?.warn(`larkBot chat-router: message envelope missing messageId, drop ${e.eventId}`);
52160
- return false;
52161
- });
52162
- if (envs.length === 0) return;
52163
- const last = envs[envs.length - 1];
52164
- const speaker = last.senderName || last.senderOpenId || "\u672A\u77E5\u6210\u5458";
52165
- const idxByMessageId = new Map(envs.map((e, i) => [e.messageId, i]));
52166
- const sections = [];
52167
- for (const [i, env] of envs.entries()) {
52168
- const body2 = await buildSection(env);
52169
- const section = [quoteAnnotation(env, i, idxByMessageId), body2].filter(Boolean).join("\n");
52170
- if (section) sections.push(section);
52171
- }
52172
- const body = sections.join("\n") || "[\u975E\u6587\u672C\u6D88\u606F]";
52117
+ const rawBody = [env.text?.trim(), ...imageLines].filter(Boolean).join("\n");
52118
+ const body = rawBody || "[\u975E\u6587\u672C\u6D88\u606F]";
52173
52119
  const text = `${body}
52174
52120
 
52175
52121
  ${formatLarkSpeakerReminder(speaker)}`;
52176
52122
  const turn = deps.manager.runLarkChatTurn({
52177
- personaId: last.personaId,
52178
- chatId: last.chatId,
52179
- chatName: last.chatName,
52180
- chatType: last.chatType ?? "group",
52181
- senderOpenId: last.senderOpenId ?? "",
52182
- senderName: last.senderName ?? last.senderOpenId ?? "\u672A\u77E5\u6210\u5458",
52123
+ personaId: env.personaId,
52124
+ chatId: env.chatId,
52125
+ chatName: env.chatName,
52126
+ chatType: env.chatType ?? "group",
52127
+ senderOpenId: env.senderOpenId ?? "",
52128
+ senderName: env.senderName ?? env.senderOpenId ?? "\u672A\u77E5\u6210\u5458",
52183
52129
  text
52184
52130
  });
52185
- activity.set(last.chatId, {
52186
- chatId: last.chatId,
52187
- chatName: last.chatName,
52131
+ activity.set(env.chatId, {
52132
+ chatId: env.chatId,
52133
+ chatName: env.chatName,
52188
52134
  lastActiveAt: Date.now(),
52189
- personaId: last.personaId
52135
+ personaId: env.personaId
52190
52136
  });
52191
52137
  let timedOut = false;
52192
52138
  let timer;
@@ -52206,78 +52152,46 @@ ${formatLarkSpeakerReminder(speaker)}`;
52206
52152
  const replyText = "ok" in result && result.ok ? result.replyText : ERROR_REPLY_TEXT;
52207
52153
  if (!("ok" in result)) {
52208
52154
  deps.logger?.warn(
52209
- `larkBot turn ${timedOut ? "timeout" : "error"} (${last.chatId}): ${result.error}`
52155
+ `larkBot turn ${timedOut ? "timeout" : "error"} (${env.chatId}): ${result.error}`
52210
52156
  );
52211
52157
  }
52212
- const absorbed = envs.slice(0, -1).map((e) => e.eventId);
52213
52158
  for (let attempt = 0; attempt <= replyDelays.length; attempt++) {
52214
52159
  if (attempt > 0) await sleep2(replyDelays[attempt - 1]);
52215
52160
  try {
52216
52161
  await deps.cloud.reply({
52217
- appId: last.appId,
52218
- chatId: last.chatId,
52219
- replyToMessageId: last.messageId,
52162
+ appId: env.appId,
52163
+ chatId: env.chatId,
52164
+ replyToMessageId: env.messageId,
52220
52165
  text: replyText,
52221
- eventId: last.eventId,
52222
- ...absorbed.length > 0 ? { absorbedEventIds: absorbed } : {}
52166
+ eventId: env.eventId
52223
52167
  });
52224
52168
  return;
52225
52169
  } catch (err) {
52226
52170
  deps.logger?.warn(
52227
- `larkBot reply attempt ${attempt + 1} failed (${last.chatId}): ${err.message}`
52171
+ `larkBot reply attempt ${attempt + 1} failed (${env.chatId}): ${err.message}`
52228
52172
  );
52229
52173
  }
52230
52174
  }
52231
52175
  };
52232
- const enqueueBatch = (batchEnvs) => {
52233
- const chatId = batchEnvs[0].chatId;
52234
- const prev = queues.get(chatId) ?? Promise.resolve();
52235
- const next = prev.then(
52236
- () => runBatch(batchEnvs).catch(
52237
- (err) => deps.logger?.warn(`larkBot chat-router runBatch failed: ${err.message}`)
52238
- )
52239
- );
52240
- queues.set(chatId, next);
52241
- void next.finally(() => {
52242
- if (queues.get(chatId) === next) queues.delete(chatId);
52243
- });
52244
- };
52245
- const flushPending = (chatId) => {
52246
- const batch = pending.get(chatId);
52247
- if (!batch) return;
52248
- clearTimeout(batch.timer);
52249
- pending.delete(chatId);
52250
- enqueueBatch(batch.envelopes);
52251
- };
52252
52176
  return {
52253
52177
  handleEnvelope(env) {
52254
52178
  if (env.type === "bot_removed") {
52255
52179
  deps.store.addRemovedChat(env.personaId, env.chatId);
52256
52180
  activity.delete(env.chatId);
52257
52181
  queues.delete(env.chatId);
52258
- const p2 = pending.get(env.chatId);
52259
- if (p2) {
52260
- clearTimeout(p2.timer);
52261
- pending.delete(env.chatId);
52262
- }
52263
52182
  deps.logger?.info(`larkBot removed from chat ${env.chatId} (persona ${env.personaId})`);
52264
52183
  return;
52265
52184
  }
52266
- const sender = env.senderOpenId ?? "";
52267
- const cur = pending.get(env.chatId);
52268
- if (cur && cur.senderOpenId !== sender) flushPending(env.chatId);
52269
- const batch = pending.get(env.chatId);
52270
- if (batch) {
52271
- batch.envelopes.push(env);
52272
- clearTimeout(batch.timer);
52273
- batch.timer = setTimeout(() => flushPending(env.chatId), debounceMs);
52274
- } else {
52275
- pending.set(env.chatId, {
52276
- envelopes: [env],
52277
- senderOpenId: sender,
52278
- timer: setTimeout(() => flushPending(env.chatId), debounceMs)
52279
- });
52280
- }
52185
+ const prev = queues.get(env.chatId) ?? Promise.resolve();
52186
+ const next = prev.then(
52187
+ () => runOne(env).catch(
52188
+ (err) => deps.logger?.warn(`larkBot chat-router runOne failed: ${err.message}`)
52189
+ )
52190
+ );
52191
+ queues.set(env.chatId, next);
52192
+ void next.finally(() => {
52193
+ if (queues.get(env.chatId) === next) queues.delete(env.chatId);
52194
+ });
52281
52195
  },
52282
52196
  listLarkSessions(personaId2) {
52283
52197
  return [...activity.values()].filter((a) => a.personaId === personaId2).map((a) => ({ chatId: a.chatId, chatName: a.chatName, lastActiveAt: a.lastActiveAt }));
@@ -53020,7 +52934,7 @@ var import_node_fs28 = __toESM(require("fs"), 1);
53020
52934
  var import_node_os8 = __toESM(require("os"), 1);
53021
52935
  var import_node_path30 = __toESM(require("path"), 1);
53022
52936
  init_protocol();
53023
- var MAX_FILE_BYTES2 = 2 * 1024 * 1024;
52937
+ var MAX_FILE_BYTES = 2 * 1024 * 1024;
53024
52938
  function resolveInsideCwd(cwd, subpath) {
53025
52939
  const absCwd = import_node_path30.default.resolve(cwd);
53026
52940
  const joined = import_node_path30.default.resolve(absCwd, subpath ?? ".");
@@ -53076,8 +52990,8 @@ var WorkspaceBrowser = class {
53076
52990
  if (!st.isFile()) {
53077
52991
  throw new ClawdError(ERROR_CODES.INVALID_PATH, `not a file: ${args.path}`);
53078
52992
  }
53079
- if (st.size > MAX_FILE_BYTES2) {
53080
- throw new ClawdError(ERROR_CODES.FILE_TOO_LARGE, `file > ${MAX_FILE_BYTES2} bytes`);
52993
+ if (st.size > MAX_FILE_BYTES) {
52994
+ throw new ClawdError(ERROR_CODES.FILE_TOO_LARGE, `file > ${MAX_FILE_BYTES} bytes`);
53081
52995
  }
53082
52996
  const buf = import_node_fs28.default.readFileSync(full);
53083
52997
  const isBinary = buf.includes(0);
@@ -59036,7 +58950,7 @@ function computeMethodAccess(args) {
59036
58950
  }
59037
58951
 
59038
58952
  // src/version.ts
59039
- var version = "0.2.297".length > 0 ? "0.2.297" : "dev";
58953
+ var version = "0.2.298".length > 0 ? "0.2.298" : "dev";
59040
58954
 
59041
58955
  // src/cli-probe/probe.ts
59042
58956
  var fs56 = __toESM(require("fs"), 1);
@@ -63054,7 +62968,7 @@ async function startDaemon(config) {
63054
62968
  manager,
63055
62969
  cloud: larkBotCloud,
63056
62970
  store: larkBotStore,
63057
- fetchResource: (appId, messageId, fileKey, maxBytes, type) => larkBotCloud.fetchResource(appId, messageId, fileKey, maxBytes, type),
62971
+ fetchResource: (appId, messageId, fileKey, maxBytes) => larkBotCloud.fetchResource(appId, messageId, fileKey, maxBytes),
63058
62972
  // 图片落 guest userWorkDir 下(capId = lark-<chat_id>):CC 经 --add-dir + allowRead carve 可 Read
63059
62973
  mediaRootFor: (chatId) => import_node_path65.default.join(deriveUserWorkDir(`lark-${chatId}`, usersRoot), "lark-media"),
63060
62974
  logger: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clawos-dev/clawd",
3
- "version": "0.2.297",
3
+ "version": "0.2.298",
4
4
  "description": "Standalone clawd daemon — Claude Code (and future Codex) session server over WebSocket",
5
5
  "type": "module",
6
6
  "license": "MIT",