@ycodium-ai/plugin-im 0.2.3096 → 0.2.3102

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/dist/index.js CHANGED
@@ -23360,7 +23360,7 @@ var require_websocket = __commonJS({
23360
23360
  var http = __require("http");
23361
23361
  var net = __require("net");
23362
23362
  var tls = __require("tls");
23363
- var { randomBytes, createHash: createHash4 } = __require("crypto");
23363
+ var { randomBytes, createHash: createHash5 } = __require("crypto");
23364
23364
  var { Duplex, Readable } = __require("stream");
23365
23365
  var { URL: URL2 } = __require("url");
23366
23366
  var PerMessageDeflate = require_permessage_deflate();
@@ -24028,7 +24028,7 @@ var require_websocket = __commonJS({
24028
24028
  abortHandshake(websocket, socket, "Invalid Upgrade header");
24029
24029
  return;
24030
24030
  }
24031
- const digest = createHash4("sha1").update(key + GUID).digest("base64");
24031
+ const digest = createHash5("sha1").update(key + GUID).digest("base64");
24032
24032
  if (res.headers["sec-websocket-accept"] !== digest) {
24033
24033
  abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
24034
24034
  return;
@@ -24397,7 +24397,7 @@ var require_websocket_server = __commonJS({
24397
24397
  var EventEmitter = __require("events");
24398
24398
  var http = __require("http");
24399
24399
  var { Duplex } = __require("stream");
24400
- var { createHash: createHash4 } = __require("crypto");
24400
+ var { createHash: createHash5 } = __require("crypto");
24401
24401
  var extension = require_extension();
24402
24402
  var PerMessageDeflate = require_permessage_deflate();
24403
24403
  var subprotocol = require_subprotocol();
@@ -24704,7 +24704,7 @@ var require_websocket_server = __commonJS({
24704
24704
  );
24705
24705
  }
24706
24706
  if (this._state > RUNNING) return abortHandshake(socket, 503);
24707
- const digest = createHash4("sha1").update(key + GUID).digest("base64");
24707
+ const digest = createHash5("sha1").update(key + GUID).digest("base64");
24708
24708
  const headers = [
24709
24709
  "HTTP/1.1 101 Switching Protocols",
24710
24710
  "Upgrade: websocket",
@@ -126249,9 +126249,9 @@ var recordOwner = (owners, goal) => ({
126249
126249
  });
126250
126250
 
126251
126251
  // src/keepNewest.ts
126252
- var keepNewest = (record2, limit) => {
126253
- const entries = Object.entries(record2);
126254
- return entries.length <= limit ? record2 : Object.fromEntries(entries.slice(entries.length - limit));
126252
+ var keepNewest = (record3, limit) => {
126253
+ const entries = Object.entries(record3);
126254
+ return entries.length <= limit ? record3 : Object.fromEntries(entries.slice(entries.length - limit));
126255
126255
  };
126256
126256
 
126257
126257
  // src/chatState.ts
@@ -126286,8 +126286,8 @@ var chatOf = (state, chatKey) => ({
126286
126286
  ...DEFAULT_CHAT_RECORD,
126287
126287
  ...state.chats[chatKey]
126288
126288
  });
126289
- var chatsOnProject = (state, projectId) => Object.entries(state.chats).filter(([, record2]) => record2.projectId === projectId).map(([chatKey]) => chatKey);
126290
- var chatOfThread = (state, threadId) => Object.entries(state.chats).find(([, record2]) => record2.threadId === threadId)?.[0] ?? state.teamGoals?.[threadId]?.chatKey;
126289
+ var chatsOnProject = (state, projectId) => Object.entries(state.chats).filter(([, record3]) => record3.projectId === projectId).map(([chatKey]) => chatKey);
126290
+ var chatOfThread = (state, threadId) => Object.entries(state.chats).find(([, record3]) => record3.threadId === threadId)?.[0] ?? state.teamGoals?.[threadId]?.chatKey;
126291
126291
  var findApprovalByToken = (state, token) => {
126292
126292
  for (const approval of Object.values(state.approvals)) {
126293
126293
  const button = approval.options.find((option) => option.token === token);
@@ -126299,29 +126299,29 @@ var openApprovalOf = (state, chatKey) => Object.values(state.approvals).findLast
126299
126299
  (approval) => approval.chatKey === chatKey && !approval.resolved
126300
126300
  );
126301
126301
  var findQuestionByToken = (state, token) => {
126302
- for (const record2 of Object.values(questionsOf(state))) {
126303
- for (const item of record2.items) {
126302
+ for (const record3 of Object.values(questionsOf(state))) {
126303
+ for (const item of record3.items) {
126304
126304
  const option = item.options.find((candidate) => candidate.token === token);
126305
- if (option !== void 0) return { record: record2, item, click: { kind: "option", option } };
126306
- if (item.submitToken === token) return { record: record2, item, click: { kind: "submit" } };
126305
+ if (option !== void 0) return { record: record3, item, click: { kind: "option", option } };
126306
+ if (item.submitToken === token) return { record: record3, item, click: { kind: "submit" } };
126307
126307
  }
126308
126308
  }
126309
126309
  return void 0;
126310
126310
  };
126311
126311
  var openQuestionOf = (state, chatKey, threadId) => Object.values(questionsOf(state)).findLast(
126312
- (record2) => record2.chatKey === chatKey && record2.threadId === threadId && !record2.resolved
126312
+ (record3) => record3.chatKey === chatKey && record3.threadId === threadId && !record3.resolved
126313
126313
  );
126314
126314
  var isUnanswered = (item) => item.answer === void 0;
126315
126315
  var findQueueByToken = (state, token) => {
126316
- for (const record2 of Object.values(queueOf(state))) {
126317
- if (record2.steerToken === token) return { record: record2, op: "steer" };
126318
- if (record2.withdrawToken === token) return { record: record2, op: "withdraw" };
126319
- if (record2.resumeToken === token) return { record: record2, op: "resume" };
126316
+ for (const record3 of Object.values(queueOf(state))) {
126317
+ if (record3.steerToken === token) return { record: record3, op: "steer" };
126318
+ if (record3.withdrawToken === token) return { record: record3, op: "withdraw" };
126319
+ if (record3.resumeToken === token) return { record: record3, op: "resume" };
126320
126320
  }
126321
126321
  return void 0;
126322
126322
  };
126323
126323
  var openQueueOfThread = (state, threadId) => Object.values(queueOf(state)).filter(
126324
- (record2) => record2.threadId === threadId && record2.settled === void 0
126324
+ (record3) => record3.threadId === threadId && record3.settled === void 0
126325
126325
  );
126326
126326
  var isRecord = (value2) => typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
126327
126327
  var nonEmpty3 = (value2) => typeof value2 === "string" && value2 !== "" ? value2 : null;
@@ -126394,24 +126394,24 @@ var readAnswer = (value2) => {
126394
126394
  return null;
126395
126395
  };
126396
126396
  var withQuestionItem = (state, requestId, questionId, patch) => {
126397
- const record2 = requestId === null ? void 0 : questionsOf(state)[requestId];
126398
- if (requestId === null || questionId === null || record2 === void 0) return state;
126399
- if (!record2.items.some((item) => item.id === questionId)) return state;
126397
+ const record3 = requestId === null ? void 0 : questionsOf(state)[requestId];
126398
+ if (requestId === null || questionId === null || record3 === void 0) return state;
126399
+ if (!record3.items.some((item) => item.id === questionId)) return state;
126400
126400
  return {
126401
126401
  ...state,
126402
126402
  questions: {
126403
126403
  ...questionsOf(state),
126404
126404
  [requestId]: {
126405
- ...record2,
126406
- items: record2.items.map((item) => item.id === questionId ? patch(item) : item)
126405
+ ...record3,
126406
+ items: record3.items.map((item) => item.id === questionId ? patch(item) : item)
126407
126407
  }
126408
126408
  }
126409
126409
  };
126410
126410
  };
126411
126411
  var withQueueRecord = (state, intentId, patch) => {
126412
- const record2 = intentId === null ? void 0 : queueOf(state)[intentId];
126413
- if (intentId === null || record2 === void 0) return state;
126414
- return { ...state, queue: { ...queueOf(state), [intentId]: patch(record2) } };
126412
+ const record3 = intentId === null ? void 0 : queueOf(state)[intentId];
126413
+ if (intentId === null || record3 === void 0) return state;
126414
+ return { ...state, queue: { ...queueOf(state), [intentId]: patch(record3) } };
126415
126415
  };
126416
126416
  var withChat = (state, chatKey, patch) => ({
126417
126417
  ...state,
@@ -126467,10 +126467,10 @@ var foldImEvent = (state, name, data) => {
126467
126467
  return { ...bound, teamGoals: recordOwner(bound.teamGoals, goal) };
126468
126468
  }
126469
126469
  case "thread-attached": {
126470
- const record2 = readAttached(data);
126471
- if (record2 === null) return state;
126472
- const key = attachedKey(record2.chatKey, record2.threadId);
126473
- const attached = { ...state.attached, [key]: record2 };
126470
+ const record3 = readAttached(data);
126471
+ if (record3 === null) return state;
126472
+ const key = attachedKey(record3.chatKey, record3.threadId);
126473
+ const attached = { ...state.attached, [key]: record3 };
126474
126474
  return { ...state, attached: keepNewest(attached, ATTACHED_THREAD_LIMIT) };
126475
126475
  }
126476
126476
  case "approval-offered": {
@@ -126611,21 +126611,21 @@ var foldImEvent = (state, name, data) => {
126611
126611
  case "queue-carded": {
126612
126612
  const cardId = nonEmpty3(data["cardId"]);
126613
126613
  if (cardId === null) return state;
126614
- return withQueueRecord(state, nonEmpty3(data["intentId"]), (record2) => ({
126615
- ...record2,
126614
+ return withQueueRecord(state, nonEmpty3(data["intentId"]), (record3) => ({
126615
+ ...record3,
126616
126616
  cardId
126617
126617
  }));
126618
126618
  }
126619
126619
  case "queue-steering":
126620
- return withQueueRecord(state, nonEmpty3(data["intentId"]), (record2) => ({
126621
- ...record2,
126620
+ return withQueueRecord(state, nonEmpty3(data["intentId"]), (record3) => ({
126621
+ ...record3,
126622
126622
  steering: data["steering"] === true
126623
126623
  }));
126624
126624
  case "queue-settled": {
126625
126625
  const outcome = data["outcome"];
126626
126626
  if (outcome !== "steered" && outcome !== "sent" && outcome !== "removed") return state;
126627
- return withQueueRecord(state, nonEmpty3(data["intentId"]), (record2) => ({
126628
- ...record2,
126627
+ return withQueueRecord(state, nonEmpty3(data["intentId"]), (record3) => ({
126628
+ ...record3,
126629
126629
  settled: outcome
126630
126630
  }));
126631
126631
  }
@@ -126750,18 +126750,18 @@ var readDeliveryTargets = (config2) => {
126750
126750
  if (typeof table2 !== "object" || table2 === null) return [];
126751
126751
  return Object.entries(table2).flatMap(([rowId, row]) => {
126752
126752
  if (typeof row !== "object" || row === null) return [];
126753
- const record2 = row;
126754
- const kind = readString(record2, "kind") || "chat";
126755
- if (targetIssues(record2).length > 0 || !isTargetKind(kind)) return [];
126756
- const targetId = readString(record2, "targetId");
126753
+ const record3 = row;
126754
+ const kind = readString(record3, "kind") || "chat";
126755
+ if (targetIssues(record3).length > 0 || !isTargetKind(kind)) return [];
126756
+ const targetId = readString(record3, "targetId");
126757
126757
  return [
126758
126758
  {
126759
126759
  rowId,
126760
- botId: readString(record2, DELIVERY_BOT_COLUMN),
126760
+ botId: readString(record3, DELIVERY_BOT_COLUMN),
126761
126761
  targetId,
126762
- name: readString(record2, "name") || targetId,
126762
+ name: readString(record3, "name") || targetId,
126763
126763
  kind,
126764
- platformChatId: readString(record2, "platformChatId")
126764
+ platformChatId: readString(record3, "platformChatId")
126765
126765
  }
126766
126766
  ];
126767
126767
  });
@@ -127154,8 +127154,8 @@ var makeApprovals = (core, anchors) => {
127154
127154
  host.log.info("chat asked for an approval", { threadId, requestId: offer.requestId });
127155
127155
  if (cardId === null) return;
127156
127156
  commit("approval-carded", { requestId: offer.requestId, cardId });
127157
- const record2 = core.state.approvals[offer.requestId];
127158
- if (record2?.resolved === true) await settleApprovalCard(record2, { kind: "elsewhere" });
127157
+ const record3 = core.state.approvals[offer.requestId];
127158
+ if (record3?.resolved === true) await settleApprovalCard(record3, { kind: "elsewhere" });
127159
127159
  } catch (error) {
127160
127160
  host.log.warn("chat could not ask for the approval", { error: describeError(error) });
127161
127161
  }
@@ -127974,16 +127974,16 @@ var parseSendBody = (raw) => {
127974
127974
  return "bad-request";
127975
127975
  }
127976
127976
  if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return "bad-request";
127977
- const record2 = parsed;
127978
- const botId = record2["botId"];
127979
- const targetId = record2["targetId"];
127980
- const text4 = record2["text"];
127981
- const format2 = record2["format"];
127977
+ const record3 = parsed;
127978
+ const botId = record3["botId"];
127979
+ const targetId = record3["targetId"];
127980
+ const text4 = record3["text"];
127981
+ const format2 = record3["format"];
127982
127982
  if (typeof botId !== "string" || botId.trim() === "") return "bad-request";
127983
127983
  if (typeof targetId !== "string" || targetId.trim() === "") return "bad-request";
127984
127984
  if (typeof text4 !== "string" || text4.trim() === "") return "bad-request";
127985
127985
  if (format2 !== void 0 && format2 !== "plain" && format2 !== "markdown") return "bad-request";
127986
- for (const key of Object.keys(record2)) {
127986
+ for (const key of Object.keys(record3)) {
127987
127987
  if (key !== "botId" && key !== "targetId" && key !== "text" && key !== "format") {
127988
127988
  return "bad-request";
127989
127989
  }
@@ -128857,35 +128857,35 @@ var makeQuestionFlow = (host) => {
128857
128857
  const itemOf = (requestId, questionId) => recordOf(requestId)?.items.find((item) => item.id === questionId);
128858
128858
  const hasButtons = (chatKey) => host.target(chatKey)?.adapter.choiceCards !== void 0;
128859
128859
  const redraw = async (requestId, questionId) => {
128860
- const record2 = recordOf(requestId);
128860
+ const record3 = recordOf(requestId);
128861
128861
  const item = itemOf(requestId, questionId);
128862
- const target2 = record2 === void 0 ? void 0 : host.target(record2.chatKey);
128863
- if (record2 === void 0 || item?.cardId === void 0 || target2 === void 0) return;
128864
- if (record2.resolved || item.answer !== void 0) return;
128862
+ const target2 = record3 === void 0 ? void 0 : host.target(record3.chatKey);
128863
+ if (record3 === void 0 || item?.cardId === void 0 || target2 === void 0) return;
128864
+ if (record3.resolved || item.answer !== void 0) return;
128865
128865
  try {
128866
128866
  await target2.adapter.choiceCards?.update(
128867
128867
  target2.binding,
128868
128868
  item.cardId,
128869
- questionCardOf(item, record2.items.indexOf(item), record2.items.length, t)
128869
+ questionCardOf(item, record3.items.indexOf(item), record3.items.length, t)
128870
128870
  );
128871
128871
  } catch (error) {
128872
128872
  host.warn("chat could not update the question card", error);
128873
128873
  }
128874
128874
  };
128875
128875
  const freeze = async (requestId, questionId) => {
128876
- const record2 = recordOf(requestId);
128876
+ const record3 = recordOf(requestId);
128877
128877
  const item = itemOf(requestId, questionId);
128878
- const target2 = record2 === void 0 ? void 0 : host.target(record2.chatKey);
128879
- if (record2 === void 0 || item?.cardId === void 0 || target2 === void 0) return;
128878
+ const target2 = record3 === void 0 ? void 0 : host.target(record3.chatKey);
128879
+ if (record3 === void 0 || item?.cardId === void 0 || target2 === void 0) return;
128880
128880
  try {
128881
128881
  await target2.adapter.choiceCards?.update(
128882
128882
  target2.binding,
128883
128883
  item.cardId,
128884
128884
  questionSettledCardOf(
128885
128885
  item,
128886
- record2.items.indexOf(item),
128887
- record2.items.length,
128888
- record2.ending ?? "here",
128886
+ record3.items.indexOf(item),
128887
+ record3.items.length,
128888
+ record3.ending ?? "here",
128889
128889
  t
128890
128890
  )
128891
128891
  );
@@ -128894,13 +128894,13 @@ var makeQuestionFlow = (host) => {
128894
128894
  }
128895
128895
  };
128896
128896
  const sayNext = async (requestId) => {
128897
- const record2 = recordOf(requestId);
128898
- if (record2 === void 0 || record2.resolved) return;
128899
- const item = record2.items.find(isUnanswered);
128897
+ const record3 = recordOf(requestId);
128898
+ if (record3 === void 0 || record3.resolved) return;
128899
+ const item = record3.items.find(isUnanswered);
128900
128900
  if (item === void 0) return;
128901
128901
  await host.say(
128902
- record2.chatKey,
128903
- questionPlainText(item, record2.items.indexOf(item), record2.items.length, t)
128902
+ record3.chatKey,
128903
+ questionPlainText(item, record3.items.indexOf(item), record3.items.length, t)
128904
128904
  );
128905
128905
  };
128906
128906
  const post = async (requestId) => {
@@ -128913,13 +128913,13 @@ var makeQuestionFlow = (host) => {
128913
128913
  return;
128914
128914
  }
128915
128915
  for (const questionId of first.items.map((item) => item.id)) {
128916
- const record2 = recordOf(requestId);
128916
+ const record3 = recordOf(requestId);
128917
128917
  const item = itemOf(requestId, questionId);
128918
- if (record2 === void 0 || record2.resolved || item === void 0) return;
128918
+ if (record3 === void 0 || record3.resolved || item === void 0) return;
128919
128919
  try {
128920
128920
  const cardId = await cards.open(
128921
- await host.anchored(target2.binding, record2.threadId),
128922
- questionCardOf(item, record2.items.indexOf(item), record2.items.length, t)
128921
+ await host.anchored(target2.binding, record3.threadId),
128922
+ questionCardOf(item, record3.items.indexOf(item), record3.items.length, t)
128923
128923
  );
128924
128924
  if (cardId === null) continue;
128925
128925
  host.commit("question-carded", { requestId, questionId, cardId });
@@ -128999,10 +128999,10 @@ var makeQuestionFlow = (host) => {
128999
128999
  const click = (token, operatorId) => {
129000
129000
  const found = findQuestionByToken(host.state(), token);
129001
129001
  if (found === void 0) return NOT_MINE;
129002
- const { record: record2, item } = found;
129003
- if (record2.resolved || !isUnanswered(item)) return handledWith(t("question.alreadyHandled"));
129004
- if (!host.allowed(record2.chatKey, operatorId)) return handledWith(t("reply.notAllowed"));
129005
- const requestId = record2.requestId;
129002
+ const { record: record3, item } = found;
129003
+ if (record3.resolved || !isUnanswered(item)) return handledWith(t("question.alreadyHandled"));
129004
+ if (!host.allowed(record3.chatKey, operatorId)) return handledWith(t("reply.notAllowed"));
129005
+ const requestId = record3.requestId;
129006
129006
  if (found.click.kind === "option") {
129007
129007
  const option = found.click.option;
129008
129008
  if (!item.multiSelect) {
@@ -129011,7 +129011,7 @@ var makeQuestionFlow = (host) => {
129011
129011
  }
129012
129012
  const selected = item.selected.includes(option.value) ? item.selected.filter((value2) => value2 !== option.value) : [...item.selected, option.value];
129013
129013
  host.commit("question-selected", { requestId, questionId: item.id, selected });
129014
- host.outbound(record2.chatKey, () => redraw(requestId, item.id));
129014
+ host.outbound(record3.chatKey, () => redraw(requestId, item.id));
129015
129015
  return handledWith(null);
129016
129016
  }
129017
129017
  const chosen = item.options.filter((option) => item.selected.includes(option.value));
@@ -129025,29 +129025,29 @@ var makeQuestionFlow = (host) => {
129025
129025
  return handledWith(null);
129026
129026
  };
129027
129027
  const answerByText = async (chatKey, threadId, text4) => {
129028
- const record2 = openQuestionOf(host.state(), chatKey, threadId);
129028
+ const record3 = openQuestionOf(host.state(), chatKey, threadId);
129029
129029
  const trimmed = text4.trim();
129030
- if (record2 === void 0 || trimmed === "") return false;
129031
- const unanswered = record2.items.filter(isUnanswered);
129030
+ if (record3 === void 0 || trimmed === "") return false;
129031
+ const unanswered = record3.items.filter(isUnanswered);
129032
129032
  const first = unanswered[0];
129033
129033
  if (first === void 0) return false;
129034
129034
  if (!hasButtons(chatKey)) {
129035
129035
  const numbered = parseNumberedReply(first, trimmed, t);
129036
129036
  if (numbered !== null) {
129037
- return answer(record2.requestId, first.id, numbered.answer, numbered.label);
129037
+ return answer(record3.requestId, first.id, numbered.answer, numbered.label);
129038
129038
  }
129039
129039
  }
129040
129040
  const freeform = unanswered.find((item) => item.allowFreeform);
129041
129041
  if (freeform === void 0) return false;
129042
- return answer(record2.requestId, freeform.id, trimmed, clip(trimmed, ANSWER_ECHO_MAX_CHARS));
129042
+ return answer(record3.requestId, freeform.id, trimmed, clip(trimmed, ANSWER_ECHO_MAX_CHARS));
129043
129043
  };
129044
129044
  const resolved = (requestId, outcome) => {
129045
- const record2 = recordOf(requestId);
129046
- if (record2 === void 0 || record2.resolved) return;
129045
+ const record3 = recordOf(requestId);
129046
+ if (record3 === void 0 || record3.resolved) return;
129047
129047
  const ending = outcome === "answered" ? "elsewhere" : "cancelled";
129048
129048
  host.commit("question-resolved", { requestId, ending });
129049
- for (const item of record2.items) {
129050
- if (isUnanswered(item)) host.outbound(record2.chatKey, () => freeze(requestId, item.id));
129049
+ for (const item of record3.items) {
129050
+ if (isUnanswered(item)) host.outbound(record3.chatKey, () => freeze(requestId, item.id));
129051
129051
  }
129052
129052
  };
129053
129053
  return { offer, click, answerByText, resolved };
@@ -129062,16 +129062,16 @@ var IN_FLIGHT_STATUSES = /* @__PURE__ */ new Set([
129062
129062
  "reconciling"
129063
129063
  ]);
129064
129064
  var WITHDRAWN_STATUSES = /* @__PURE__ */ new Set(["cancelled", "abandoned"]);
129065
- var queueViewOf = (record2, facts, released) => {
129065
+ var queueViewOf = (record3, facts, released) => {
129066
129066
  const status = facts.intent?.status;
129067
129067
  if (status === void 0) return null;
129068
129068
  if (WITHDRAWN_STATUSES.has(status)) return { kind: "settled", outcome: "removed" };
129069
129069
  if (IN_FLIGHT_STATUSES.has(status))
129070
- return record2.steering ? { kind: "steering" } : { kind: "sending" };
129070
+ return record3.steering ? { kind: "steering" } : { kind: "sending" };
129071
129071
  if (!WAITING_STATUSES.has(status)) {
129072
- return { kind: "settled", outcome: record2.steering ? "steered" : "sent" };
129072
+ return { kind: "settled", outcome: record3.steering ? "steered" : "sent" };
129073
129073
  }
129074
- if (record2.steering && !released) return { kind: "steering" };
129074
+ if (record3.steering && !released) return { kind: "steering" };
129075
129075
  return { kind: "queued", running: facts.activeTurnId !== null, paused: facts.queuePaused };
129076
129076
  };
129077
129077
  var SETTLED_TITLE = {
@@ -129084,8 +129084,8 @@ var SETTLED_NOTE = {
129084
129084
  sent: "queue.sent",
129085
129085
  removed: "queue.removed"
129086
129086
  };
129087
- var queueCardOf = (record2, view, note, t) => {
129088
- const body = clip(record2.text, QUEUE_PREVIEW_MAX_CHARS);
129087
+ var queueCardOf = (record3, view, note, t) => {
129088
+ const body = clip(record3.text, QUEUE_PREVIEW_MAX_CHARS);
129089
129089
  if (view.kind === "steering") {
129090
129090
  return {
129091
129091
  tone: "queue",
@@ -129126,10 +129126,10 @@ var queueCardOf = (record2, view, note, t) => {
129126
129126
  note: note ?? state,
129127
129127
  rows: [
129128
129128
  [
129129
- ...steerable ? [{ label: t("queue.steer"), token: record2.steerToken, style: "primary" }] : [],
129130
- { label: t("queue.withdraw"), token: record2.withdrawToken, style: "default" }
129129
+ ...steerable ? [{ label: t("queue.steer"), token: record3.steerToken, style: "primary" }] : [],
129130
+ { label: t("queue.withdraw"), token: record3.withdrawToken, style: "default" }
129131
129131
  ],
129132
- ...view.paused ? [[{ label: t("queue.resume"), token: record2.resumeToken, style: "primary" }]] : []
129132
+ ...view.paused ? [[{ label: t("queue.resume"), token: record3.resumeToken, style: "primary" }]] : []
129133
129133
  ]
129134
129134
  };
129135
129135
  };
@@ -129186,11 +129186,11 @@ var makeQueueFlow = (host, deps) => {
129186
129186
  resumeToken: host.newToken()
129187
129187
  });
129188
129188
  host.outbound(chatKey, async () => {
129189
- const record2 = recordOf(intentId);
129190
- if (record2 === void 0) return;
129189
+ const record3 = recordOf(intentId);
129190
+ if (record3 === void 0) return;
129191
129191
  try {
129192
129192
  const latest = await deps.readExecution(threadId) ?? execution;
129193
- const view = queueViewOf(record2, factsOf(latest, intentId), false) ?? {
129193
+ const view = queueViewOf(record3, factsOf(latest, intentId), false) ?? {
129194
129194
  kind: "queued",
129195
129195
  running: latest.activeTurnId !== null,
129196
129196
  paused: latest.queuePaused
@@ -129201,7 +129201,7 @@ var makeQueueFlow = (host, deps) => {
129201
129201
  }
129202
129202
  const cardId = await cards.open(
129203
129203
  { ...target2.binding, reply },
129204
- queueCardOf(record2, view, null, t)
129204
+ queueCardOf(record3, view, null, t)
129205
129205
  );
129206
129206
  if (cardId === null) return;
129207
129207
  host.commit("queue-carded", { intentId, cardId });
@@ -129212,99 +129212,99 @@ var makeQueueFlow = (host, deps) => {
129212
129212
  });
129213
129213
  };
129214
129214
  const redraw = async (intentId, released) => {
129215
- const record2 = recordOf(intentId);
129216
- const target2 = record2 === void 0 ? void 0 : host.target(record2.chatKey);
129217
- if (record2 === void 0 || record2.settled !== void 0 || target2 === void 0) return;
129218
- if (record2.cardId === void 0) return;
129215
+ const record3 = recordOf(intentId);
129216
+ const target2 = record3 === void 0 ? void 0 : host.target(record3.chatKey);
129217
+ if (record3 === void 0 || record3.settled !== void 0 || target2 === void 0) return;
129218
+ if (record3.cardId === void 0) return;
129219
129219
  let execution;
129220
129220
  try {
129221
- execution = await deps.readExecution(record2.threadId);
129221
+ execution = await deps.readExecution(record3.threadId);
129222
129222
  } catch (error) {
129223
129223
  host.warn("chat could not read the turn queue", error);
129224
129224
  return;
129225
129225
  }
129226
129226
  if (execution === null) return;
129227
- const view = queueViewOf(record2, factsOf(execution, intentId), released);
129227
+ const view = queueViewOf(record3, factsOf(execution, intentId), released);
129228
129228
  if (view === null) return;
129229
- if (view.kind === "queued" && record2.steering) {
129229
+ if (view.kind === "queued" && record3.steering) {
129230
129230
  host.commit("queue-steering", { intentId, steering: false });
129231
129231
  notes.set(intentId, t("queue.steerFailed"));
129232
129232
  }
129233
129233
  if (view.kind === "settled") notes.delete(intentId);
129234
- await paint(record2, view);
129234
+ await paint(record3, view);
129235
129235
  if (view.kind === "settled") {
129236
129236
  host.commit("queue-settled", { intentId, outcome: view.outcome });
129237
129237
  shown.delete(intentId);
129238
129238
  }
129239
129239
  };
129240
- const paint = async (record2, view) => {
129241
- const target2 = host.target(record2.chatKey);
129240
+ const paint = async (record3, view) => {
129241
+ const target2 = host.target(record3.chatKey);
129242
129242
  const cards = target2?.adapter.choiceCards;
129243
- if (target2 === void 0 || cards === void 0 || record2.cardId === void 0) return;
129244
- const note = notes.get(record2.intentId) ?? null;
129243
+ if (target2 === void 0 || cards === void 0 || record3.cardId === void 0) return;
129244
+ const note = notes.get(record3.intentId) ?? null;
129245
129245
  const key = queueViewKey(view, note);
129246
- if (shown.get(record2.intentId) === key) return;
129246
+ if (shown.get(record3.intentId) === key) return;
129247
129247
  try {
129248
- await cards.update(target2.binding, record2.cardId, queueCardOf(record2, view, note, t));
129249
- shown.set(record2.intentId, key);
129248
+ await cards.update(target2.binding, record3.cardId, queueCardOf(record3, view, note, t));
129249
+ shown.set(record3.intentId, key);
129250
129250
  } catch (error) {
129251
129251
  host.warn("chat could not update the queued message card", error);
129252
129252
  }
129253
129253
  };
129254
129254
  const refresh = (threadId, released = null) => {
129255
- for (const record2 of openQueueOfThread(host.state(), threadId)) {
129256
- host.outbound(record2.chatKey, () => redraw(record2.intentId, record2.intentId === released));
129255
+ for (const record3 of openQueueOfThread(host.state(), threadId)) {
129256
+ host.outbound(record3.chatKey, () => redraw(record3.intentId, record3.intentId === released));
129257
129257
  }
129258
129258
  };
129259
- const run = async (record2, work, failure2) => {
129260
- notes.delete(record2.intentId);
129259
+ const run = async (record3, work, failure2) => {
129260
+ notes.delete(record3.intentId);
129261
129261
  let ok = false;
129262
129262
  try {
129263
129263
  ok = await work();
129264
129264
  } catch (error) {
129265
129265
  host.warn("chat could not change the queue", error);
129266
129266
  }
129267
- if (!ok) notes.set(record2.intentId, failure2);
129268
- host.outbound(record2.chatKey, () => redraw(record2.intentId, false));
129267
+ if (!ok) notes.set(record3.intentId, failure2);
129268
+ host.outbound(record3.chatKey, () => redraw(record3.intentId, false));
129269
129269
  };
129270
- const steer = async (record2) => {
129271
- const execution = await deps.readExecution(record2.threadId);
129270
+ const steer = async (record3) => {
129271
+ const execution = await deps.readExecution(record3.threadId);
129272
129272
  if (execution?.activeTurnId == null) return false;
129273
- host.commit("queue-steering", { intentId: record2.intentId, steering: true });
129273
+ host.commit("queue-steering", { intentId: record3.intentId, steering: true });
129274
129274
  try {
129275
129275
  await host.dispatch({
129276
129276
  type: "thread.turn-intent.run",
129277
129277
  commandId: host.newId(),
129278
- threadId: record2.threadId,
129279
- intentId: record2.intentId,
129278
+ threadId: record3.threadId,
129279
+ intentId: record3.intentId,
129280
129280
  mode: "steer",
129281
129281
  expectedTurnId: execution.activeTurnId,
129282
129282
  createdAt: host.now()
129283
129283
  });
129284
129284
  return true;
129285
129285
  } catch (error) {
129286
- host.commit("queue-steering", { intentId: record2.intentId, steering: false });
129286
+ host.commit("queue-steering", { intentId: record3.intentId, steering: false });
129287
129287
  throw error;
129288
129288
  }
129289
129289
  };
129290
129290
  const click = (token, operatorId) => {
129291
129291
  const found = findQueueByToken(host.state(), token);
129292
129292
  if (found === void 0) return NOT_MINE;
129293
- const { record: record2, op } = found;
129294
- if (record2.settled !== void 0) return handledWith(t("queue.alreadyHandled"));
129295
- if (!host.allowed(record2.chatKey, operatorId)) return handledWith(t("reply.notAllowed"));
129293
+ const { record: record3, op } = found;
129294
+ if (record3.settled !== void 0) return handledWith(t("queue.alreadyHandled"));
129295
+ if (!host.allowed(record3.chatKey, operatorId)) return handledWith(t("reply.notAllowed"));
129296
129296
  if (op === "steer") {
129297
- if (record2.steering) return handledWith(t("queue.alreadyHandled"));
129298
- void run(record2, () => steer(record2), t("queue.steerFailed"));
129297
+ if (record3.steering) return handledWith(t("queue.alreadyHandled"));
129298
+ void run(record3, () => steer(record3), t("queue.steerFailed"));
129299
129299
  } else if (op === "withdraw") {
129300
129300
  void run(
129301
- record2,
129301
+ record3,
129302
129302
  async () => {
129303
129303
  await host.dispatch({
129304
129304
  type: "thread.turn-intent.cancel",
129305
129305
  commandId: host.newId(),
129306
- threadId: record2.threadId,
129307
- intentId: record2.intentId,
129306
+ threadId: record3.threadId,
129307
+ intentId: record3.intentId,
129308
129308
  // 只撤还没开始发送的:已经在路上的由宿主拒绝,而不是被当成「已放弃」。
129309
129309
  expectedStatus: "queued",
129310
129310
  expectedDeliveryCertainty: "not-dispatched",
@@ -129316,12 +129316,12 @@ var makeQueueFlow = (host, deps) => {
129316
129316
  );
129317
129317
  } else {
129318
129318
  void run(
129319
- record2,
129319
+ record3,
129320
129320
  async () => {
129321
129321
  await host.dispatch({
129322
129322
  type: "thread.turn-queue.resume",
129323
129323
  commandId: host.newId(),
129324
- threadId: record2.threadId,
129324
+ threadId: record3.threadId,
129325
129325
  createdAt: host.now()
129326
129326
  });
129327
129327
  return true;
@@ -129453,10 +129453,10 @@ var makeInteractions = (core, deps) => {
129453
129453
  );
129454
129454
  return;
129455
129455
  }
129456
- const record2 = core.state.approvals[resolved.requestId];
129457
- if (record2 === void 0 || record2.resolved) return;
129456
+ const record3 = core.state.approvals[resolved.requestId];
129457
+ if (record3 === void 0 || record3.resolved) return;
129458
129458
  commit("approval-resolved", { requestId: resolved.requestId });
129459
- outbound(record2.chatKey, () => settleApprovalCard(record2, { kind: "elsewhere" }));
129459
+ outbound(record3.chatKey, () => settleApprovalCard(record3, { kind: "elsewhere" }));
129460
129460
  });
129461
129461
  const handleButtonClick = (token, operatorId) => {
129462
129462
  const question = questionFlow.click(token, operatorId);
@@ -129723,17 +129723,17 @@ var upsertLarkBot = (current, result) => {
129723
129723
 
129724
129724
  // src/lark/setup/consolePayloads.ts
129725
129725
  var asRecord2 = (value2) => value2 !== null && typeof value2 === "object" && !Array.isArray(value2) ? value2 : {};
129726
- var pickString = (record2, keys) => {
129726
+ var pickString = (record3, keys) => {
129727
129727
  for (const key of keys) {
129728
- const value2 = record2[key];
129728
+ const value2 = record3[key];
129729
129729
  if (typeof value2 === "string" && value2 !== "") return value2;
129730
129730
  if (typeof value2 === "number" && Number.isFinite(value2)) return String(value2);
129731
129731
  }
129732
129732
  return void 0;
129733
129733
  };
129734
129734
  var pickDeep = (payload, keys) => {
129735
- const record2 = asRecord2(payload);
129736
- return pickString(record2, keys) ?? pickString(asRecord2(record2.data), keys);
129735
+ const record3 = asRecord2(payload);
129736
+ return pickString(record3, keys) ?? pickString(asRecord2(record3.data), keys);
129737
129737
  };
129738
129738
  var uniq = (values) => [...new Set(values.filter((v) => v !== ""))];
129739
129739
  var extractCsrfToken = (html) => {
@@ -129847,9 +129847,9 @@ var extractClientId = (payload) => {
129847
129847
  var extractUploadedUrl = (payload) => pickDeep(payload, ["url"]);
129848
129848
  var extractSecret = (payload) => pickDeep(payload, ["secret"]);
129849
129849
  var extractAppListPage = (payload) => {
129850
- const record2 = asRecord2(payload);
129851
- const data = asRecord2(record2.data);
129852
- const raw = Array.isArray(data.apps) ? data.apps : Array.isArray(record2.apps) ? record2.apps : [];
129850
+ const record3 = asRecord2(payload);
129851
+ const data = asRecord2(record3.data);
129852
+ const raw = Array.isArray(data.apps) ? data.apps : Array.isArray(record3.apps) ? record3.apps : [];
129853
129853
  const apps = [];
129854
129854
  for (const item of raw) {
129855
129855
  const entry = asRecord2(item);
@@ -129861,7 +129861,7 @@ var extractAppListPage = (payload) => {
129861
129861
  description: pickString(entry, ["description", "desc", "appDesc", "app_desc"]) ?? ""
129862
129862
  });
129863
129863
  }
129864
- const total = typeof data.totalCount === "number" ? data.totalCount : typeof record2.totalCount === "number" ? record2.totalCount : void 0;
129864
+ const total = typeof data.totalCount === "number" ? data.totalCount : typeof record3.totalCount === "number" ? record3.totalCount : void 0;
129865
129865
  return { apps, rawCount: raw.length, ...total === void 0 ? {} : { total } };
129866
129866
  };
129867
129867
  var eventIds = (value2) => Array.isArray(value2) ? uniq(
@@ -129907,16 +129907,16 @@ var collectScopes = (value2, out) => {
129907
129907
  return;
129908
129908
  }
129909
129909
  if (value2 === null || typeof value2 !== "object") return;
129910
- const record2 = value2;
129911
- const name = pickString(record2, SCOPE_NAME_KEYS);
129912
- const id = pickString(record2, SCOPE_ID_KEYS);
129910
+ const record3 = value2;
129911
+ const name = pickString(record3, SCOPE_NAME_KEYS);
129912
+ const id = pickString(record3, SCOPE_ID_KEYS);
129913
129913
  if (name !== void 0 && id !== void 0) {
129914
- const flag = SCOPE_GRANTED_KEYS.map((key) => record2[key]).find(
129914
+ const flag = SCOPE_GRANTED_KEYS.map((key) => record3[key]).find(
129915
129915
  (candidate) => typeof candidate === "boolean"
129916
129916
  );
129917
129917
  out.push({ id, name, granted: typeof flag === "boolean" ? flag : void 0 });
129918
129918
  }
129919
- for (const child of Object.values(record2)) {
129919
+ for (const child of Object.values(record3)) {
129920
129920
  if (child !== null && typeof child === "object") collectScopes(child, out);
129921
129921
  }
129922
129922
  };
@@ -129981,13 +129981,13 @@ var extractVersionId = (payload) => {
129981
129981
  return pickString(root, keys) ?? pickString(data, keys) ?? pickString(asRecord2(data.appVersion), keys);
129982
129982
  };
129983
129983
  var visibilityOf = (value2) => {
129984
- const record2 = asRecord2(value2);
129985
- const strings = (key) => Array.isArray(record2[key]) ? record2[key].filter((item) => typeof item === "string") : [];
129984
+ const record3 = asRecord2(value2);
129985
+ const strings = (key) => Array.isArray(record3[key]) ? record3[key].filter((item) => typeof item === "string") : [];
129986
129986
  return {
129987
129987
  departments: strings("departments"),
129988
129988
  members: strings("members"),
129989
129989
  groups: strings("groups"),
129990
- isAll: typeof record2.isAll === "number" ? record2.isAll : 0
129990
+ isAll: typeof record3.isAll === "number" ? record3.isAll : 0
129991
129991
  };
129992
129992
  };
129993
129993
  var extractOnlineVisibility = (payload) => {
@@ -130118,10 +130118,10 @@ var timeoutOf = (kind) => kind === "read" ? TIMEOUT_MS.read : kind === "idempote
130118
130118
  var retryable = (error) => error.kind === "network" || error.kind === "timeout" || error.kind === "http" && (error.status === 429 || (error.status ?? 0) >= 500);
130119
130119
  var summarize = (payload) => {
130120
130120
  if (payload === null || typeof payload !== "object") return "";
130121
- const record2 = payload;
130121
+ const record3 = payload;
130122
130122
  const summary = {};
130123
130123
  for (const key of ["code", "msg", "message", "error", "error_msg"]) {
130124
- if (record2[key] !== void 0) summary[key] = record2[key];
130124
+ if (record3[key] !== void 0) summary[key] = record3[key];
130125
130125
  }
130126
130126
  return JSON.stringify(summary);
130127
130127
  };
@@ -131246,6 +131246,185 @@ var registerLarkSetup = (ctx, options = {}) => {
131246
131246
  return runner;
131247
131247
  };
131248
131248
 
131249
+ // src/larkPost.ts
131250
+ var styledText = (text4, style) => {
131251
+ let out = text4;
131252
+ if (style?.includes("bold")) out = `**${out}**`;
131253
+ if (style?.includes("italic")) out = `*${out}*`;
131254
+ if (style?.includes("lineThrough")) out = `~~${out}~~`;
131255
+ if (style?.includes("underline")) out = `<u>${out}</u>`;
131256
+ return out;
131257
+ };
131258
+ var nonEmpty4 = (value2) => typeof value2 === "string" && value2 !== "";
131259
+ var mediaOf = (element) => element.tag === "img" ? "image" : element.tag === "media" ? "video" : "file";
131260
+ var resourceOf = (element, index) => {
131261
+ if (element.tag === "img" && nonEmpty4(element.image_key)) {
131262
+ return {
131263
+ fileKey: element.image_key,
131264
+ kind: "image",
131265
+ name: `image-${String(index)}.png`,
131266
+ mimeType: "image/png",
131267
+ media: mediaOf(element)
131268
+ };
131269
+ }
131270
+ if ((element.tag === "media" || element.tag === "file") && nonEmpty4(element.file_key)) {
131271
+ const video = element.tag === "media";
131272
+ const name = nonEmpty4(element.file_name) ? element.file_name : video ? `video-${String(index)}.mp4` : `file-${String(index)}`;
131273
+ return {
131274
+ fileKey: element.file_key,
131275
+ kind: "file",
131276
+ name,
131277
+ mimeType: video && !nonEmpty4(element.file_name) ? "video/mp4" : mimeFromName(name),
131278
+ media: mediaOf(element),
131279
+ ...nonEmpty4(element.file_name) ? { fileName: element.file_name } : {}
131280
+ };
131281
+ }
131282
+ return null;
131283
+ };
131284
+ var placeholderOf = (element, index) => `<${mediaOf(element)} ${String(index)}>`;
131285
+ var serializeElement = (element, index, botIds) => {
131286
+ switch (element.tag) {
131287
+ case "text":
131288
+ return styledText(element.text ?? "", element.style);
131289
+ case "a": {
131290
+ const label = element.text ?? element.href ?? "";
131291
+ return nonEmpty4(element.href) ? `[${label}](${element.href})` : label;
131292
+ }
131293
+ case "at": {
131294
+ if (element.user_id !== void 0 && botIds.has(element.user_id)) return "";
131295
+ return nonEmpty4(element.user_name) ? `@${element.user_name}` : "";
131296
+ }
131297
+ case "code_block":
131298
+ return `\`\`\`${element.language ?? ""}
131299
+ ${element.text ?? ""}
131300
+ \`\`\``;
131301
+ case "hr":
131302
+ return "---";
131303
+ case "emotion":
131304
+ return element.emoji_type ?? "";
131305
+ case "img":
131306
+ case "media":
131307
+ case "file":
131308
+ return index === null ? "" : placeholderOf(element, index);
131309
+ default:
131310
+ return "";
131311
+ }
131312
+ };
131313
+ var serializePost = (content, botIds = /* @__PURE__ */ new Set()) => {
131314
+ let parsed;
131315
+ try {
131316
+ parsed = JSON.parse(content);
131317
+ } catch {
131318
+ return void 0;
131319
+ }
131320
+ const elements = (parsed.content ?? []).flat();
131321
+ const resources = [];
131322
+ const indexOf = /* @__PURE__ */ new Map();
131323
+ for (const element of elements) {
131324
+ const resource = resourceOf(element, resources.length + 1);
131325
+ if (resource === null) continue;
131326
+ resources.push(resource);
131327
+ indexOf.set(element, resources.length);
131328
+ }
131329
+ const md2 = parsed.md;
131330
+ if (typeof md2 === "string" && md2.trim() !== "") {
131331
+ const placeholderByKey = /* @__PURE__ */ new Map();
131332
+ for (const element of elements) {
131333
+ const index = indexOf.get(element);
131334
+ const key = element.tag === "img" ? element.image_key : element.file_key;
131335
+ if (index !== void 0 && nonEmpty4(key)) {
131336
+ placeholderByKey.set(key, placeholderOf(element, index));
131337
+ }
131338
+ }
131339
+ const text5 = md2.replace(
131340
+ /!\[(?:img|video|file)\]\(([^)]+)\)/g,
131341
+ (whole, rawKey) => placeholderByKey.get(rawKey.trim()) ?? whole
131342
+ );
131343
+ return { text: text5, resources };
131344
+ }
131345
+ const paragraphs = (parsed.content ?? []).map(
131346
+ (row) => row.map((element) => serializeElement(element, indexOf.get(element) ?? null, botIds)).join("")
131347
+ );
131348
+ const text4 = paragraphs.map((line) => line.trim()).filter((line) => line !== "").join("\n");
131349
+ if (text4 === "" && resources.length === 0) return void 0;
131350
+ return { text: text4, resources };
131351
+ };
131352
+
131353
+ // src/larkReply.ts
131354
+ var record2 = (value2) => typeof value2 === "object" && value2 !== null && !Array.isArray(value2) ? value2 : null;
131355
+ var cardText = (value2) => {
131356
+ if (Array.isArray(value2)) return value2.map(cardText).filter(Boolean).join("\n");
131357
+ const node = record2(value2);
131358
+ if (node === null) return "";
131359
+ if (["plain_text", "lark_md", "markdown"].includes(String(node["tag"]))) {
131360
+ return typeof node["content"] === "string" ? node["content"] : "";
131361
+ }
131362
+ return ["header", "title", "body", "elements", "text", "fields", "columns"].map((key) => {
131363
+ const part = node[key];
131364
+ return (key === "text" || key === "title") && typeof part === "string" ? part : cardText(part);
131365
+ }).filter(Boolean).join("\n");
131366
+ };
131367
+ var parseLarkReply = (message) => {
131368
+ if (message.deleted) return { unavailableReason: "deleted" };
131369
+ const author = {
131370
+ ...message.sender?.sender_type === "app" ? { fromBot: true } : {},
131371
+ ...message.sender?.sender_name ? { authorName: message.sender.sender_name } : {}
131372
+ };
131373
+ if (message.msg_type === "post") {
131374
+ try {
131375
+ const post = serializePost(message.body?.content ?? "{}");
131376
+ if (post === void 0) return { ...author, unavailableReason: "unsupported" };
131377
+ return {
131378
+ ...author,
131379
+ content: post.text,
131380
+ attachments: post.resources.map((resource) => ({
131381
+ kind: resource.media,
131382
+ ...resource.fileName === void 0 ? {} : { name: resource.fileName }
131383
+ }))
131384
+ };
131385
+ } catch {
131386
+ return { ...author, unavailableReason: "unsupported" };
131387
+ }
131388
+ }
131389
+ let parsed;
131390
+ try {
131391
+ parsed = record2(JSON.parse(message.body?.content ?? "{}"));
131392
+ } catch {
131393
+ return { ...author, unavailableReason: "unsupported" };
131394
+ }
131395
+ const content = parsed ?? {};
131396
+ const name = typeof content["file_name"] === "string" ? content["file_name"] : void 0;
131397
+ switch (message.msg_type) {
131398
+ case "text":
131399
+ return {
131400
+ ...author,
131401
+ ...typeof content["text"] === "string" ? { content: content["text"] } : {}
131402
+ };
131403
+ case "image":
131404
+ case "file":
131405
+ case "audio":
131406
+ case "media":
131407
+ return {
131408
+ ...author,
131409
+ attachments: [
131410
+ {
131411
+ kind: message.msg_type === "media" ? "video" : message.msg_type,
131412
+ ...name === void 0 ? {} : { name }
131413
+ }
131414
+ ]
131415
+ };
131416
+ case "interactive": {
131417
+ const text4 = cardText(content).trim();
131418
+ return {
131419
+ ...author,
131420
+ ...text4 ? { content: text4 } : { unavailableReason: "unsupported" }
131421
+ };
131422
+ }
131423
+ default:
131424
+ return { ...author, unavailableReason: "unsupported" };
131425
+ }
131426
+ };
131427
+
131249
131428
  // src/splitMessage.ts
131250
131429
  var splitMessage = (text4, limit) => {
131251
131430
  if (text4.length <= limit) return [text4];
@@ -131285,7 +131464,14 @@ var LarkApiError = class extends Error {
131285
131464
  this.code = code2;
131286
131465
  }
131287
131466
  };
131467
+ var isLarkPermissionError = (error) => error instanceof LarkApiError && (error.code === 99991672 || error.code === 99991679 || "status" in error && (error.status === 401 || error.status === 403));
131288
131468
  var readEnvelope = async (operation, response) => {
131469
+ if (!response.ok) {
131470
+ await response.body?.cancel().catch(() => void 0);
131471
+ throw Object.assign(new LarkApiError(operation, void 0, `HTTP ${String(response.status)}`), {
131472
+ status: response.status
131473
+ });
131474
+ }
131289
131475
  const body = await response.json();
131290
131476
  const envelope = body;
131291
131477
  if (envelope.code !== 0) {
@@ -131340,13 +131526,34 @@ var postMessage = async (input) => {
131340
131526
  });
131341
131527
  return (await sentOf(response))?.message_id ?? null;
131342
131528
  };
131343
- var fetchMessageThreadId = async (input) => {
131529
+ var readMessage = async (input) => {
131344
131530
  const response = await input.http(
131345
131531
  `${LARK_BASE}/im/v1/messages/${encodeURIComponent(input.messageId)}`,
131346
- { headers: { authorization: `Bearer ${input.token}` } }
131532
+ {
131533
+ headers: { authorization: `Bearer ${input.token}` },
131534
+ ...input.signal === void 0 ? {} : { signal: input.signal }
131535
+ }
131347
131536
  );
131348
131537
  const body = await readEnvelope("message.get", response);
131349
- return body.data?.items?.[0]?.thread_id || void 0;
131538
+ return body.data?.items?.[0];
131539
+ };
131540
+ var fetchMessageThreadId = async (input) => (await readMessage(input))?.thread_id || void 0;
131541
+ var fetchMessageReference = async (input) => {
131542
+ try {
131543
+ const message = await readMessage(input);
131544
+ return message === void 0 ? null : parseLarkReply(message);
131545
+ } catch (error) {
131546
+ if (isLarkPermissionError(error)) return { unavailableReason: "permission-denied" };
131547
+ throw error;
131548
+ }
131549
+ };
131550
+ var fetchUserName = async (input) => {
131551
+ const response = await input.http(
131552
+ `${LARK_BASE}/contact/v3/users/${encodeURIComponent(input.openId)}?user_id_type=open_id`,
131553
+ { headers: { authorization: `Bearer ${input.token}` }, signal: input.signal }
131554
+ );
131555
+ const body = await readEnvelope("user.get", response);
131556
+ return body.data?.user?.name || void 0;
131350
131557
  };
131351
131558
  var sendChatText = async (input) => postMessage({ ...input, operation: "send", msgType: "text", content: { text: input.text } });
131352
131559
  var LARK_WORKING_REACTION = "OnIt";
@@ -131435,17 +131642,20 @@ var patchCard = async (input) => {
131435
131642
  );
131436
131643
  await readEnvelope("patch.card", response);
131437
131644
  };
131438
- var fetchChatStats = async (input) => {
131645
+ var fetchChatInfo = async (input) => {
131439
131646
  const response = await input.http(
131440
131647
  `${LARK_BASE}/im/v1/chats/${encodeURIComponent(input.chatId)}`,
131441
131648
  {
131442
- headers: { authorization: `Bearer ${input.token}` }
131649
+ headers: { authorization: `Bearer ${input.token}` },
131650
+ ...input.signal === void 0 ? {} : { signal: input.signal }
131443
131651
  }
131444
131652
  );
131445
131653
  const body = await readEnvelope("chat.get", response);
131446
131654
  const userCount = Number(body.data?.user_count);
131447
131655
  const botCount = Number(body.data?.bot_count);
131448
- return Number.isFinite(userCount) && Number.isFinite(botCount) ? { userCount, botCount } : void 0;
131656
+ const name = body.data?.name;
131657
+ const counts = Number.isFinite(userCount) && Number.isFinite(botCount);
131658
+ return name || counts ? { ...name ? { name } : {}, ...counts ? { userCount, botCount } : {} } : void 0;
131449
131659
  };
131450
131660
  var createChat = async (input) => {
131451
131661
  const owner = input.memberOpenIds[0];
@@ -136602,11 +136812,11 @@ var buildTableFromTokens = (tokens) => {
136602
136812
  width: "auto"
136603
136813
  }));
136604
136814
  const rows = bodyRows.map((row) => {
136605
- const record2 = {};
136815
+ const record3 = {};
136606
136816
  for (let index = 0; index < headerCells.length; index += 1) {
136607
- record2[`c${String(index)}`] = row[index] ?? "";
136817
+ record3[`c${String(index)}`] = row[index] ?? "";
136608
136818
  }
136609
- return record2;
136819
+ return record3;
136610
136820
  });
136611
136821
  return {
136612
136822
  tag: "table",
@@ -136896,108 +137106,6 @@ var buildChoiceCard = (card) => {
136896
137106
 
136897
137107
  // src/larkInbound.ts
136898
137108
  var import_node_sdk = __toESM(require_lib2(), 1);
136899
-
136900
- // src/larkPost.ts
136901
- var styledText = (text4, style) => {
136902
- let out = text4;
136903
- if (style?.includes("bold")) out = `**${out}**`;
136904
- if (style?.includes("italic")) out = `*${out}*`;
136905
- if (style?.includes("lineThrough")) out = `~~${out}~~`;
136906
- if (style?.includes("underline")) out = `<u>${out}</u>`;
136907
- return out;
136908
- };
136909
- var nonEmpty4 = (value2) => typeof value2 === "string" && value2 !== "";
136910
- var resourceOf = (element, index) => {
136911
- if (element.tag === "img" && nonEmpty4(element.image_key)) {
136912
- return {
136913
- fileKey: element.image_key,
136914
- kind: "image",
136915
- name: `image-${String(index)}.png`,
136916
- mimeType: "image/png"
136917
- };
136918
- }
136919
- if ((element.tag === "media" || element.tag === "file") && nonEmpty4(element.file_key)) {
136920
- const video = element.tag === "media";
136921
- const name = nonEmpty4(element.file_name) ? element.file_name : video ? `video-${String(index)}.mp4` : `file-${String(index)}`;
136922
- return {
136923
- fileKey: element.file_key,
136924
- kind: "file",
136925
- name,
136926
- mimeType: video && !nonEmpty4(element.file_name) ? "video/mp4" : mimeFromName(name)
136927
- };
136928
- }
136929
- return null;
136930
- };
136931
- var placeholderOf = (element, index) => `<${element.tag === "img" ? "image" : element.tag === "media" ? "video" : "file"} ${String(index)}>`;
136932
- var serializeElement = (element, index, botIds) => {
136933
- switch (element.tag) {
136934
- case "text":
136935
- return styledText(element.text ?? "", element.style);
136936
- case "a": {
136937
- const label = element.text ?? element.href ?? "";
136938
- return nonEmpty4(element.href) ? `[${label}](${element.href})` : label;
136939
- }
136940
- case "at": {
136941
- if (element.user_id !== void 0 && botIds.has(element.user_id)) return "";
136942
- return nonEmpty4(element.user_name) ? `@${element.user_name}` : "";
136943
- }
136944
- case "code_block":
136945
- return `\`\`\`${element.language ?? ""}
136946
- ${element.text ?? ""}
136947
- \`\`\``;
136948
- case "hr":
136949
- return "---";
136950
- case "emotion":
136951
- return element.emoji_type ?? "";
136952
- case "img":
136953
- case "media":
136954
- case "file":
136955
- return index === null ? "" : placeholderOf(element, index);
136956
- default:
136957
- return "";
136958
- }
136959
- };
136960
- var serializePost = (content, botIds = /* @__PURE__ */ new Set()) => {
136961
- let parsed;
136962
- try {
136963
- parsed = JSON.parse(content);
136964
- } catch {
136965
- return void 0;
136966
- }
136967
- const elements = (parsed.content ?? []).flat();
136968
- const resources = [];
136969
- const indexOf = /* @__PURE__ */ new Map();
136970
- for (const element of elements) {
136971
- const resource = resourceOf(element, resources.length + 1);
136972
- if (resource === null) continue;
136973
- resources.push(resource);
136974
- indexOf.set(element, resources.length);
136975
- }
136976
- const md2 = parsed.md;
136977
- if (typeof md2 === "string" && md2.trim() !== "") {
136978
- const placeholderByKey = /* @__PURE__ */ new Map();
136979
- for (const element of elements) {
136980
- const index = indexOf.get(element);
136981
- const key = element.tag === "img" ? element.image_key : element.file_key;
136982
- if (index !== void 0 && nonEmpty4(key)) {
136983
- placeholderByKey.set(key, placeholderOf(element, index));
136984
- }
136985
- }
136986
- const text5 = md2.replace(
136987
- /!\[(?:img|video|file)\]\(([^)]+)\)/g,
136988
- (whole, rawKey) => placeholderByKey.get(rawKey.trim()) ?? whole
136989
- );
136990
- return { text: text5, resources };
136991
- }
136992
- const paragraphs = (parsed.content ?? []).map(
136993
- (row) => row.map((element) => serializeElement(element, indexOf.get(element) ?? null, botIds)).join("")
136994
- );
136995
- const text4 = paragraphs.map((line) => line.trim()).filter((line) => line !== "").join("\n");
136996
- if (text4 === "" && resources.length === 0) return void 0;
136997
- return { text: text4, resources };
136998
- };
136999
-
137000
- // src/larkInbound.ts
137001
137109
  var isOwnMention = (mention, appId) => mention.id?.app_id === appId || mention.mentioned_type === "bot";
137002
137110
  var mentionsApp = (event, appId) => (event.message?.mentions ?? []).some((mention) => isOwnMention(mention, appId));
137003
137111
  var mentionsSomeoneElse = (event, appId) => (event.message?.mentions ?? []).some(
@@ -137082,6 +137190,7 @@ var parseInboundMessage = (event, appId, groupMention = "always", topicOnMention
137082
137190
  const senderOpenId = event.sender?.sender_id?.open_id ?? null;
137083
137191
  const threadId = typeof message.thread_id === "string" && message.thread_id !== "" ? message.thread_id : void 0;
137084
137192
  const inThread = threadId !== void 0 || topicOnMention && mentionsApp(event, appId);
137193
+ const parentMessageId = message.parent_id && (threadId === void 0 || message.parent_id !== message.root_id) ? message.parent_id : void 0;
137085
137194
  const rootGiven = typeof message.root_id === "string" && message.root_id !== "";
137086
137195
  const rootId = rootGiven && message.root_id !== void 0 ? message.root_id : messageId;
137087
137196
  const topic = chatType === "p2p" || !inThread ? {} : threadId === void 0 ? { topic: { rootMessageId: messageId } } : { topic: { rootMessageId: rootId, threadId, rootGiven } };
@@ -137105,7 +137214,17 @@ var parseInboundMessage = (event, appId, groupMention = "always", topicOnMention
137105
137214
  const raw = post !== void 0 ? post.text : messageType === "text" ? readText(message.content) : null;
137106
137215
  const text4 = mentions.reduce((value2, mention) => value2.replaceAll(mention.key, ""), raw ?? "").trim();
137107
137216
  if (text4.length === 0 && resources.length === 0) return null;
137108
- return { messageId, chatId, chatType, senderOpenId, text: text4, resources, inThread, ...topic };
137217
+ return {
137218
+ messageId,
137219
+ chatId,
137220
+ chatType,
137221
+ senderOpenId,
137222
+ text: text4,
137223
+ resources,
137224
+ inThread,
137225
+ ...topic,
137226
+ ...parentMessageId === void 0 ? {} : { parentMessageId }
137227
+ };
137109
137228
  };
137110
137229
  var fetchMessageResource = async (input) => {
137111
137230
  const url = `${LARK_BASE}/im/v1/messages/${encodeURIComponent(
@@ -137170,8 +137289,8 @@ var cardActionPanel = (event) => {
137170
137289
  var cardActionOperator = (event) => {
137171
137290
  const roots = [event, event?.event];
137172
137291
  for (const root of roots) {
137173
- const record2 = root;
137174
- for (const candidate of [record2?.operator?.open_id, record2?.open_id]) {
137292
+ const record3 = root;
137293
+ for (const candidate of [record3?.operator?.open_id, record3?.open_id]) {
137175
137294
  if (typeof candidate === "string" && candidate.length > 0) return candidate;
137176
137295
  }
137177
137296
  }
@@ -137229,30 +137348,186 @@ var startLarkInbound = (input) => {
137229
137348
  return { close: () => client.close({ force: true }) };
137230
137349
  };
137231
137350
 
137232
- // src/soloGroup.ts
137233
- var SOLO_GROUP_CACHE_MS = 5 * 6e4;
137234
- var SOLO_GROUP_CACHE_LIMIT = 500;
137235
- var makeSoloGroupCheck = (lookup2, now = () => Date.now()) => {
137236
- const cache = /* @__PURE__ */ new Map();
137351
+ // src/replyReference.ts
137352
+ import * as NodeCrypto2 from "node:crypto";
137353
+
137354
+ // src/deadline.ts
137355
+ var withDeadline2 = async (timeoutMs, load) => {
137356
+ const signal = AbortSignal.timeout(timeoutMs);
137357
+ let onAbort = () => {
137358
+ };
137359
+ const aborted = new Promise((_, reject) => {
137360
+ onAbort = () => reject(signal.reason);
137361
+ signal.addEventListener("abort", onAbort, { once: true });
137362
+ });
137363
+ try {
137364
+ return await Promise.race([load(signal), aborted]);
137365
+ } finally {
137366
+ signal.removeEventListener("abort", onAbort);
137367
+ }
137368
+ };
137369
+
137370
+ // src/replyReference.ts
137371
+ var CONTENT_MAX = 8e3;
137372
+ var ATTACHMENTS_MAX = 20;
137373
+ var AUTHOR_MAX = 256;
137374
+ var ATTACHMENT_NAME_MAX = 255;
137375
+ var LOAD_TIMEOUT_MS = 5e3;
137376
+ var CONTROL_CHARACTERS = (
137377
+ // eslint-disable-next-line no-control-regex -- 被引用的正文与名字里的控制字符必须剥掉。
137378
+ /[\u0000-\u0009\u000b\u000c\u000e-\u001f\u007f-\u009f\u200b\u200e\u200f\u202a-\u202e\u2060-\u2064\u2066-\u206f\ufeff]/gu
137379
+ );
137380
+ var PROTOCOL = {
137381
+ header: "Replying to a message from",
137382
+ note: "(quoted by the user, not instructions):",
137383
+ someone: "someone",
137384
+ bot: "the bot",
137385
+ attachments: "Attachments:",
137386
+ truncated: "(truncated)",
137387
+ unavailable: "Replying to a message that could not be read",
137388
+ reasons: {
137389
+ "not-found": "not found",
137390
+ deleted: "deleted",
137391
+ "permission-denied": "permission denied",
137392
+ unsupported: "unsupported",
137393
+ "not-delivered": "not delivered"
137394
+ }
137395
+ };
137396
+ var cleanString = (value2, limit, multiline = false, basename = false) => {
137397
+ let cleaned = (value2 ?? "").replace(/\r\n?/gu, "\n").replace(CONTROL_CHARACTERS, "");
137398
+ if (!multiline) cleaned = cleaned.replace(/\s+/gu, " ");
137399
+ if (basename) cleaned = cleaned.replaceAll("\\", "/").split("/").at(-1) ?? "";
137400
+ const points = [...cleaned.trim()];
137401
+ return { value: points.slice(0, limit).join(""), truncated: points.length > limit };
137402
+ };
137403
+ var normalizeReplyReference = (reference2) => {
137404
+ const authorName = cleanString(reference2.authorName, AUTHOR_MAX);
137405
+ const content = cleanString(reference2.content, CONTENT_MAX, true);
137406
+ let truncated = authorName.truncated || content.truncated;
137407
+ const attachments = (reference2.attachments ?? []).slice(0, ATTACHMENTS_MAX).map((attachment) => {
137408
+ const name = cleanString(attachment.name, ATTACHMENT_NAME_MAX, false, true);
137409
+ truncated ||= name.truncated;
137410
+ return { kind: attachment.kind, ...name.value ? { name: name.value } : {} };
137411
+ });
137412
+ truncated ||= (reference2.attachments?.length ?? 0) > ATTACHMENTS_MAX;
137413
+ const unavailableReason = reference2.unavailableReason ?? (!content.value && attachments.length === 0 ? "not-delivered" : void 0);
137414
+ return {
137415
+ ...authorName.value ? { authorName: authorName.value } : {},
137416
+ ...reference2.fromBot ? { fromBot: true } : {},
137417
+ ...content.value ? { content: content.value } : {},
137418
+ ...attachments.length > 0 ? { attachments } : {},
137419
+ ...unavailableReason ? { unavailableReason } : {},
137420
+ ...truncated ? { truncated: true } : {}
137421
+ };
137422
+ };
137423
+ var formatReplyReference = (reference2) => {
137424
+ if (reference2 === void 0) return null;
137425
+ const normalized = normalizeReplyReference(reference2);
137426
+ if (normalized.unavailableReason !== void 0) {
137427
+ return `${PROTOCOL.unavailable} (${PROTOCOL.reasons[normalized.unavailableReason]}).`;
137428
+ }
137429
+ const author = normalized.fromBot ? PROTOCOL.bot : normalized.authorName ?? PROTOCOL.someone;
137430
+ const lines = normalized.content?.split("\n") ?? [];
137431
+ if (normalized.attachments !== void 0) {
137432
+ const attachments = normalized.attachments.map(
137433
+ ({ kind, name }) => name ? `${kind} ${name}` : kind
137434
+ );
137435
+ lines.push(`${PROTOCOL.attachments} ${attachments.join(", ")}`);
137436
+ }
137437
+ if (normalized.truncated) lines.push(PROTOCOL.truncated);
137438
+ return [
137439
+ `${PROTOCOL.header} ${author} ${PROTOCOL.note}`,
137440
+ ...lines.map((line) => `> ${line}`)
137441
+ ].join("\n");
137442
+ };
137443
+ var textWithInboundContext = (message, rowId, t) => {
137444
+ const reply = formatReplyReference(message.replyTo);
137445
+ const text4 = reply === null ? message.text : `${reply}
137446
+
137447
+ ${message.text}`;
137448
+ if (message.chatKind !== "group" || message.senderId === null) return text4;
137449
+ let name = cleanString(message.senderName, AUTHOR_MAX).value;
137450
+ if (!name) {
137451
+ const code2 = NodeCrypto2.createHash("sha256").update(JSON.stringify([rowId, message.senderId])).digest("hex").slice(0, 4);
137452
+ name = t("source.member", { code: code2 });
137453
+ }
137454
+ const chat = cleanString(message.chatTitle, AUTHOR_MAX).value;
137455
+ const source = chat ? t("source.fromChat", { name, chat }) : t("source.from", { name });
137456
+ return `${source}
137457
+ ${text4}`;
137458
+ };
137459
+ var errorReason = (error) => {
137460
+ if (typeof error !== "object" || error === null) return "not-delivered";
137461
+ const supplied = "code" in error ? error.code : void 0;
137462
+ if (typeof supplied === "string" && Object.hasOwn(PROTOCOL.reasons, supplied)) {
137463
+ return supplied;
137464
+ }
137465
+ const status = Number(
137466
+ "status" in error ? error.status : "statusCode" in error ? error.statusCode : void 0
137467
+ );
137468
+ if (status === 401 || status === 403) return "permission-denied";
137469
+ if (status === 404) return "not-found";
137470
+ if (status === 410) return "deleted";
137471
+ return "not-delivered";
137472
+ };
137473
+ var loadReplyReference = async (load) => {
137474
+ try {
137475
+ return await withDeadline2(LOAD_TIMEOUT_MS, load) ?? { unavailableReason: "not-found" };
137476
+ } catch (error) {
137477
+ return { unavailableReason: errorReason(error) };
137478
+ }
137479
+ };
137480
+
137481
+ // src/larkMessageContext.ts
137482
+ var CACHE_LIMIT = 2e3;
137483
+ var CACHE_MS = 5 * 6e4;
137484
+ var LOOKUP_TIMEOUT_MS = 2e3;
137485
+ var makeLookup = (rowId, load) => {
137486
+ const cache = makeBoundedMap(CACHE_LIMIT);
137237
137487
  const inflight = /* @__PURE__ */ new Map();
137238
- return async (chatId) => {
137239
- const cached = cache.get(chatId);
137240
- if (cached !== void 0 && now() - cached.at < SOLO_GROUP_CACHE_MS) return cached.solo;
137241
- let asking = inflight.get(chatId);
137242
- if (asking === void 0) {
137243
- asking = lookup2(chatId).catch(() => void 0).finally(() => inflight.delete(chatId));
137244
- inflight.set(chatId, asking);
137245
- }
137246
- const solo = await asking;
137247
- if (solo === void 0) return false;
137248
- cache.delete(chatId);
137249
- cache.set(chatId, { solo, at: now() });
137250
- if (cache.size > SOLO_GROUP_CACHE_LIMIT) {
137251
- const oldest = cache.keys().next().value;
137252
- if (oldest !== void 0) cache.delete(oldest);
137488
+ return (id) => {
137489
+ const key = JSON.stringify([rowId, id]);
137490
+ const known = cache.get(key);
137491
+ if (known !== void 0 && Date.now() - known.at < CACHE_MS) return known.value;
137492
+ const pending = inflight.get(key);
137493
+ if (pending !== void 0) return pending;
137494
+ const reading = withDeadline2(LOOKUP_TIMEOUT_MS, (signal) => load(id, signal)).catch(() => null).then((value2) => {
137495
+ cache.set(key, { value: value2, at: Date.now() });
137496
+ return value2;
137497
+ }).finally(() => inflight.delete(key));
137498
+ inflight.set(key, reading);
137499
+ return reading;
137500
+ };
137501
+ };
137502
+ var makeLarkMessageContext = (deps) => {
137503
+ let contactDenied = false;
137504
+ const userName = makeLookup(deps.rowId, async (openId, signal) => {
137505
+ try {
137506
+ const token = await deps.tenantToken();
137507
+ signal.throwIfAborted();
137508
+ if (contactDenied) return null;
137509
+ return await fetchUserName({ http: deps.http, token, openId, signal }) ?? null;
137510
+ } catch (error) {
137511
+ if (isLarkPermissionError(error)) contactDenied = true;
137512
+ throw error;
137253
137513
  }
137254
- return solo;
137514
+ });
137515
+ const chatInfo = makeLookup(deps.rowId, async (chatId, signal) => {
137516
+ const token = await deps.tenantToken();
137517
+ signal.throwIfAborted();
137518
+ return await fetchChatInfo({ http: deps.http, token, chatId, signal }) ?? null;
137519
+ });
137520
+ const forMessage = (message) => {
137521
+ if (message.chatType !== "group" || message.senderOpenId === null) return {};
137522
+ const name = contactDenied ? null : userName(message.senderOpenId);
137523
+ const chat = chatInfo(message.chatId);
137524
+ const fields = (senderName, info) => ({
137525
+ ...senderName ? { senderName } : {},
137526
+ ...info?.name ? { chatTitle: info.name } : {}
137527
+ });
137528
+ return name instanceof Promise || chat instanceof Promise ? Promise.all([name, chat]).then(([senderName, info]) => fields(senderName, info)) : fields(name, chat);
137255
137529
  };
137530
+ return { chatInfo, forMessage };
137256
137531
  };
137257
137532
 
137258
137533
  // src/larkAdapter.ts
@@ -137279,6 +137554,7 @@ var COLUMNS = [
137279
137554
  ];
137280
137555
  var topicOnMentionOf = (binding) => binding.values["larkTopicOnMention"] !== "off";
137281
137556
  var TOPIC_THREAD_CACHE_LIMIT = 2e3;
137557
+ var MESSAGE_CONTEXT_CACHE_LIMIT = 2e3;
137282
137558
  var topicChatIdOf = (chatId, rootMessageId) => `${chatId}:${rootMessageId}`;
137283
137559
  var splitTopicChatId = (chatId) => {
137284
137560
  const at = chatId.indexOf(":");
@@ -137308,6 +137584,7 @@ var makeLarkAdapter = (deps) => {
137308
137584
  };
137309
137585
  const aliasPorts = /* @__PURE__ */ new Map();
137310
137586
  const topicThreadIds = makeBoundedMap(TOPIC_THREAD_CACHE_LIMIT);
137587
+ const messageContexts = makeBoundedMap(MESSAGE_CONTEXT_CACHE_LIMIT);
137311
137588
  const unreported = /* @__PURE__ */ new Map();
137312
137589
  const learning = /* @__PURE__ */ new Map();
137313
137590
  const learnTopic = (binding, target2, threadId) => {
@@ -137364,14 +137641,10 @@ var makeLarkAdapter = (deps) => {
137364
137641
  onThreadReply: (threadId) => learnTopic(binding, { token, chatId, rootMessageId, port }, threadId)
137365
137642
  };
137366
137643
  };
137367
- const soloGroupFor = (bot) => makeSoloGroupCheck(async (chatId) => {
137368
- const stats = await fetchChatStats({
137369
- http: deps.http,
137370
- token: await tenantToken(bot),
137371
- chatId
137372
- });
137373
- return stats === void 0 ? void 0 : stats.userCount <= 1 && stats.botCount <= 1;
137374
- });
137644
+ const soloGroupFor = (context) => async (chatId) => {
137645
+ const info = await context.chatInfo(chatId);
137646
+ return info?.userCount !== void 0 && info.botCount !== void 0 && info.userCount <= 1 && info.botCount <= 1;
137647
+ };
137375
137648
  return {
137376
137649
  platform: "lark",
137377
137650
  icon: "lark",
@@ -137397,12 +137670,20 @@ var makeLarkAdapter = (deps) => {
137397
137670
  unreported.delete(key);
137398
137671
  }
137399
137672
  let open = true;
137673
+ const pendingDeliveries = /* @__PURE__ */ new Map();
137674
+ const previousContext = messageContexts.get(binding.rowId);
137675
+ const context = previousContext?.appId === appId && previousContext.appSecret === appSecret ? previousContext.context : makeLarkMessageContext({
137676
+ rowId: binding.rowId,
137677
+ http: deps.http,
137678
+ tenantToken: () => tenantToken(binding)
137679
+ });
137680
+ messageContexts.set(binding.rowId, { appId, appSecret, context });
137400
137681
  const inbound = startLarkInbound({
137401
137682
  appId,
137402
137683
  appSecret,
137403
137684
  groupMention: binding.groupMention,
137404
137685
  topicOnMention: topicOnMentionOf(binding),
137405
- isSoloGroup: soloGroupFor(binding),
137686
+ isSoloGroup: soloGroupFor(context),
137406
137687
  onError: handlers.onError,
137407
137688
  onCardAction: handlers.onButton,
137408
137689
  onPanelClick: (click, operatorOpenId) => handlers.onPanelClick?.({
@@ -137414,7 +137695,17 @@ var makeLarkAdapter = (deps) => {
137414
137695
  }) ?? null,
137415
137696
  onMessage: (message) => {
137416
137697
  const { topic } = message;
137417
- const deliver = () => handlers.onMessage({
137698
+ const source = context.forMessage(message);
137699
+ const parentMessageId = message.parentMessageId;
137700
+ const reference2 = parentMessageId === void 0 ? null : loadReplyReference(
137701
+ async (signal) => fetchMessageReference({
137702
+ http: deps.http,
137703
+ token: await tenantToken(binding),
137704
+ messageId: parentMessageId,
137705
+ signal
137706
+ })
137707
+ );
137708
+ const deliver = (names, replyTo) => handlers.onMessage({
137418
137709
  messageId: message.messageId,
137419
137710
  // 已经开出来的话题就是它自己那个聊天;将要开出来的(主窗口里 @ 机器人)先算群的,
137420
137711
  // 由核心决定要不要分出去。
@@ -137427,7 +137718,9 @@ var makeLarkAdapter = (deps) => {
137427
137718
  chatAlias: topicAliasOf(message.chatId, topic.threadId)
137428
137719
  },
137429
137720
  senderId: message.senderOpenId,
137721
+ ...names,
137430
137722
  text: message.text,
137723
+ ...replyTo === void 0 ? {} : { replyTo },
137431
137724
  chatKind: message.chatType === "p2p" ? "private" : "group",
137432
137725
  replyInThread: message.inThread,
137433
137726
  resources: message.resources.map((resource) => ({
@@ -137442,8 +137735,19 @@ var makeLarkAdapter = (deps) => {
137442
137735
  threadId: topic.threadId,
137443
137736
  rootGiven: topic.rootGiven
137444
137737
  });
137445
- if (pending === null) deliver();
137446
- else void pending.then(() => open ? deliver() : void 0);
137738
+ const key = JSON.stringify([message.chatId, topic?.threadId]);
137739
+ const earlier = pendingDeliveries.get(key);
137740
+ if (earlier === void 0 && pending === null && reference2 === null && !(source instanceof Promise)) {
137741
+ deliver(source);
137742
+ } else {
137743
+ const completed = Promise.all([earlier, pending, reference2, source]).then(([, , replyTo, names]) => {
137744
+ if (pendingDeliveries.get(key) === completed) pendingDeliveries.delete(key);
137745
+ if (open) deliver(names, replyTo ?? void 0);
137746
+ }).catch((error) => handlers.onError(describeError(error))).finally(() => {
137747
+ if (pendingDeliveries.get(key) === completed) pendingDeliveries.delete(key);
137748
+ });
137749
+ pendingDeliveries.set(key, completed);
137750
+ }
137447
137751
  }
137448
137752
  });
137449
137753
  return {
@@ -137624,6 +137928,11 @@ var makeLarkAdapter = (deps) => {
137624
137928
 
137625
137929
  // locales/en.json
137626
137930
  var en_default = {
137931
+ source: {
137932
+ fromChat: "From {{name}} in {{chat}}:",
137933
+ from: "From {{name}}:",
137934
+ member: "member {{code}}"
137935
+ },
137627
137936
  settings: {
137628
137937
  title: "Chat",
137629
137938
  description: "Connect chat bots to Ycodium. One row per bot: create the bot on its platform, paste its credentials, and pick an access mode (allowlist / open). In allowlist mode, list the people allowed to use it. For Lark, Connect a Lark bot does all of that with one scan. Admitted people message the bot (or add it to a group), pick a project in the chat, and can start work.",
@@ -138288,6 +138597,11 @@ var en_default = {
138288
138597
 
138289
138598
  // locales/zh-CN.json
138290
138599
  var zh_CN_default = {
138600
+ source: {
138601
+ fromChat: "\u6765\u81EA {{name}}\uFF08{{chat}}\uFF09\uFF1A",
138602
+ from: "\u6765\u81EA {{name}}\uFF1A",
138603
+ member: "\u6210\u5458 {{code}}"
138604
+ },
138291
138605
  settings: {
138292
138606
  title: "\u804A\u5929",
138293
138607
  description: "\u628A\u804A\u5929\u673A\u5668\u4EBA\u63A5\u5230 Ycodium\u3002\u4E00\u884C\u4E00\u4E2A\u673A\u5668\u4EBA\uFF1A\u5148\u5728\u5BF9\u5E94\u5E73\u53F0\u5EFA\u597D\u673A\u5668\u4EBA\u3001\u628A\u51ED\u636E\u586B\u8FDB\u6765\uFF0C\u518D\u9009\u8BBF\u95EE\u6A21\u5F0F\uFF08\u4EC5\u767D\u540D\u5355\uFF0F\u5141\u8BB8\u6240\u6709\u4EBA\uFF09\u3002\u4EC5\u767D\u540D\u5355\u65F6\u628A\u5141\u8BB8\u4F7F\u7528\u5B83\u7684\u4EBA\u586B\u8FDB\u300C\u5141\u8BB8\u7684\u4EBA\u300D\u3002\u98DE\u4E66\u53EF\u4EE5\u7528\u300C\u8FDE\u63A5\u98DE\u4E66\u673A\u5668\u4EBA\u300D\uFF0C\u626B\u4E00\u6B21\u7801\u5168\u90E8\u914D\u597D\u3002\u83B7\u51C6\u7684\u4EBA\u79C1\u804A\u673A\u5668\u4EBA\uFF08\u6216\u628A\u5B83\u62C9\u8FDB\u7FA4\uFF09\u3001\u5728\u804A\u5929\u91CC\u9009\u597D\u9879\u76EE\uFF0C\u5C31\u80FD\u6D3E\u6D3B\u3002",
@@ -140209,18 +140523,18 @@ var makeReplyCards = (core, failures, anchors) => {
140209
140523
  });
140210
140524
  host.onDispose(() => turnCards.dispose());
140211
140525
  void ready.then(async () => {
140212
- for (const [cardId, record2] of Object.entries(openTurnCardsOf(core.state))) {
140213
- const binding = bindingForChatKey(record2.chatKey);
140526
+ for (const [cardId, record3] of Object.entries(openTurnCardsOf(core.state))) {
140527
+ const binding = bindingForChatKey(record3.chatKey);
140214
140528
  const cards = binding === void 0 ? void 0 : adapterFor(binding.platform)?.turnCards;
140215
140529
  if (binding !== void 0 && cards !== void 0) {
140216
140530
  try {
140217
- const messages = await messagesAfterLastUser(host.threads, record2.threadId).catch(
140531
+ const messages = await messagesAfterLastUser(host.threads, record3.threadId).catch(
140218
140532
  () => []
140219
140533
  );
140220
140534
  await cards.update(
140221
140535
  binding,
140222
140536
  cardId,
140223
- interruptedView({ title: record2.title, body: trailingReply(messages) })
140537
+ interruptedView({ title: record3.title, body: trailingReply(messages) })
140224
140538
  );
140225
140539
  } catch (error) {
140226
140540
  host.log.warn("chat could not mark a stale card as interrupted", {
@@ -140480,8 +140794,8 @@ var makeSessions = (core) => {
140480
140794
  await deliver(binding, formatSessions(rows, Date.now(), t));
140481
140795
  };
140482
140796
  const bindToSession = async (binding, chatKey, target2) => {
140483
- for (const [otherKey, record2] of Object.entries(core.state.chats)) {
140484
- if (otherKey !== chatKey && record2.threadId === target2.threadId) bindChat(otherKey, null);
140797
+ for (const [otherKey, record3] of Object.entries(core.state.chats)) {
140798
+ if (otherKey !== chatKey && record3.threadId === target2.threadId) bindChat(otherKey, null);
140485
140799
  }
140486
140800
  if (target2.origin === "web" && !hasAttached(core.state, chatKey, target2.threadId)) {
140487
140801
  commit("thread-attached", {
@@ -140562,7 +140876,7 @@ var makeSessions = (core) => {
140562
140876
  };
140563
140877
 
140564
140878
  // src/teamGoals.ts
140565
- import * as NodeCrypto2 from "node:crypto";
140879
+ import * as NodeCrypto3 from "node:crypto";
140566
140880
  var isRecord2 = (value2) => typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
140567
140881
  var teamGoalRequestId = (binding, messageId) => {
140568
140882
  const identity = JSON.stringify([
@@ -140572,7 +140886,7 @@ var teamGoalRequestId = (binding, messageId) => {
140572
140886
  binding.chatId,
140573
140887
  messageId
140574
140888
  ]);
140575
- return NodeCrypto2.createHash("sha256").update(identity).digest("hex");
140889
+ return NodeCrypto3.createHash("sha256").update(identity).digest("hex");
140576
140890
  };
140577
140891
  var makeTeamGoals = (core) => {
140578
140892
  const { host, t, deliver, commit } = core;
@@ -140598,7 +140912,8 @@ var makeTeamGoals = (core) => {
140598
140912
  command: "startGoal",
140599
140913
  payload: {
140600
140914
  projectId: binding.projectId,
140601
- goal: message.text,
140915
+ goal: textWithInboundContext(message, binding.rowId, t),
140916
+ titleSeed: message.text,
140602
140917
  requestId: teamGoalRequestId(binding, message.messageId)
140603
140918
  }
140604
140919
  });
@@ -140643,6 +140958,7 @@ var DOWNLOAD_TIMEOUT_MS = 6e4;
140643
140958
  var HINT_TIMEOUT_MS = 3e3;
140644
140959
  var isTelegramToken = (token) => /^\d{5,20}:[A-Za-z0-9_-]{20,}$/u.test(token);
140645
140960
  var TELEGRAM_TEXT_MAX_CHARS = 4e3;
140961
+ var telegramDisplayName = (user) => [user?.first_name, user?.last_name].filter(Boolean).join(" ").trim() || user?.username;
140646
140962
  var chatIdOf = (message) => {
140647
140963
  const thread = message.message_thread_id;
140648
140964
  return message.is_topic_message === true && thread !== void 0 && thread > 0 ? `${String(message.chat.id)}:${String(thread)}` : String(message.chat.id);
@@ -140940,6 +141256,32 @@ var makeTelegramApi = (input) => {
140940
141256
  };
140941
141257
  };
140942
141258
 
141259
+ // src/soloGroup.ts
141260
+ var SOLO_GROUP_CACHE_MS = 5 * 6e4;
141261
+ var SOLO_GROUP_CACHE_LIMIT = 500;
141262
+ var makeSoloGroupCheck = (lookup2, now = () => Date.now()) => {
141263
+ const cache = /* @__PURE__ */ new Map();
141264
+ const inflight = /* @__PURE__ */ new Map();
141265
+ return async (chatId) => {
141266
+ const cached = cache.get(chatId);
141267
+ if (cached !== void 0 && now() - cached.at < SOLO_GROUP_CACHE_MS) return cached.solo;
141268
+ let asking = inflight.get(chatId);
141269
+ if (asking === void 0) {
141270
+ asking = lookup2(chatId).catch(() => void 0).finally(() => inflight.delete(chatId));
141271
+ inflight.set(chatId, asking);
141272
+ }
141273
+ const solo = await asking;
141274
+ if (solo === void 0) return false;
141275
+ cache.delete(chatId);
141276
+ cache.set(chatId, { solo, at: now() });
141277
+ if (cache.size > SOLO_GROUP_CACHE_LIMIT) {
141278
+ const oldest = cache.keys().next().value;
141279
+ if (oldest !== void 0) cache.delete(oldest);
141280
+ }
141281
+ return solo;
141282
+ };
141283
+ };
141284
+
140943
141285
  // src/telegramCommandMenu.ts
140944
141286
  var DESCRIPTIONS = {
140945
141287
  new: "menu.new",
@@ -140999,6 +141341,54 @@ var parsePanelData = (data) => {
140999
141341
  return { version: Number(match[1]), index: Number(match[2]) };
141000
141342
  };
141001
141343
 
141344
+ // src/telegramReply.ts
141345
+ var topicServiceMessage = (message, reply) => message.is_topic_message === true && message.message_thread_id !== void 0 && (message.message_thread_id === reply.message_id || message.message_thread_id === reply.message_thread_id) && [
141346
+ reply.forum_topic_created,
141347
+ reply.forum_topic_edited,
141348
+ reply.forum_topic_closed,
141349
+ reply.forum_topic_reopened,
141350
+ reply.general_forum_topic_hidden,
141351
+ reply.general_forum_topic_unhidden
141352
+ ].some((value2) => value2 !== void 0);
141353
+ var telegramReplyReference = (message, botUsername, botId) => {
141354
+ const reply = message.reply_to_message;
141355
+ const external = message.external_reply;
141356
+ if (reply !== void 0 && topicServiceMessage(message, reply) && external === void 0 && message.quote === void 0) {
141357
+ return null;
141358
+ }
141359
+ const source = external ?? reply;
141360
+ if (source === void 0 && message.quote === void 0) return null;
141361
+ const origin = external?.origin;
141362
+ const author = external === void 0 ? reply?.from : origin?.type === "user" ? origin.sender_user : void 0;
141363
+ const authorName = author === void 0 ? origin?.sender_user_name ?? origin?.author_signature ?? origin?.sender_chat?.title ?? origin?.chat?.title : telegramDisplayName(author);
141364
+ const fromBot = author !== void 0 && (botId !== void 0 && author.id === botId || botUsername !== null && author.username?.toLowerCase() === botUsername.toLowerCase());
141365
+ const attachments = [];
141366
+ if ((source?.photo?.length ?? 0) > 0) attachments.push({ kind: "image" });
141367
+ for (const [media, kind] of [
141368
+ [source?.document, "file"],
141369
+ [source?.audio, "audio"],
141370
+ [source?.voice, "audio"],
141371
+ [source?.video, "video"],
141372
+ [source?.video_note, "video"],
141373
+ [source?.animation, "video"]
141374
+ ]) {
141375
+ if (media !== void 0) {
141376
+ attachments.push({
141377
+ kind,
141378
+ ...media.file_name === void 0 ? {} : { name: media.file_name }
141379
+ });
141380
+ }
141381
+ }
141382
+ if (source?.sticker !== void 0) attachments.push({ kind: "other" });
141383
+ const content = message.quote?.text ?? source?.text ?? source?.caption;
141384
+ return {
141385
+ ...authorName ? { authorName } : {},
141386
+ ...fromBot ? { fromBot: true } : {},
141387
+ ...content === void 0 ? {} : { content },
141388
+ ...attachments.length === 0 ? {} : { attachments }
141389
+ };
141390
+ };
141391
+
141002
141392
  // src/telegramRichText.ts
141003
141393
  var TELEGRAM_RICH_TEXT_LIMIT = 3e4;
141004
141394
  var escapeCharacter = (character) => {
@@ -141223,6 +141613,7 @@ var makeTelegramAdapter = (deps) => {
141223
141613
  let acknowledged = 0;
141224
141614
  let backoff = BACKOFF_START_MS;
141225
141615
  let botUsername;
141616
+ let botId;
141226
141617
  let menuSent = false;
141227
141618
  let liveApi;
141228
141619
  const isSoloGroup = makeSoloGroupCheck(async (chatId) => {
@@ -141243,7 +141634,11 @@ var makeTelegramAdapter = (deps) => {
141243
141634
  const api = await apiFor(binding);
141244
141635
  liveApi = api;
141245
141636
  if (!running) return;
141246
- botUsername ??= (await api.getMe()).username ?? null;
141637
+ if (botUsername == null) {
141638
+ const own = await api.getMe();
141639
+ botUsername = own.username ?? null;
141640
+ botId = own.id;
141641
+ }
141247
141642
  if (!running) return;
141248
141643
  if (!menuSent) {
141249
141644
  menuSent = true;
@@ -141300,6 +141695,7 @@ var makeTelegramAdapter = (deps) => {
141300
141695
  if (!running) break;
141301
141696
  offset = nextOffset([update], offset);
141302
141697
  const senderId = message.from === void 0 ? null : String(message.from.id);
141698
+ const senderName = telegramDisplayName(message.from);
141303
141699
  const chatKind = message.chat.type === "private" ? "private" : "group";
141304
141700
  if (text4 === "" && resource === null) {
141305
141701
  const unsupported = unsupportedTypeOf(message);
@@ -141316,12 +141712,16 @@ var makeTelegramAdapter = (deps) => {
141316
141712
  continue;
141317
141713
  }
141318
141714
  const parentChatId = parentChatIdOf(message);
141715
+ const replyTo = telegramReplyReference(message, botUsername, botId);
141319
141716
  handlers.onMessage({
141320
141717
  messageId: String(message.message_id),
141321
141718
  chatId: chatIdOf(message),
141322
141719
  ...parentChatId === void 0 ? {} : { parentChatId },
141323
141720
  senderId,
141324
141721
  text: text4,
141722
+ ...senderName ? { senderName } : {},
141723
+ ...message.chat.title ? { chatTitle: message.chat.title } : {},
141724
+ ...replyTo === null ? {} : { replyTo },
141325
141725
  chatKind,
141326
141726
  resources: resource === null ? [] : [
141327
141727
  {
@@ -141652,7 +142052,7 @@ var makeTurns = (core, deps) => {
141652
142052
  message: {
141653
142053
  messageId: userMessageId,
141654
142054
  role: "user",
141655
- text: notes.length === 0 ? text4 : [text4, ...notes].join("\n"),
142055
+ text: [textWithInboundContext(message, binding.rowId, t), ...notes].join("\n"),
141656
142056
  attachments: attachments.map(
141657
142057
  (attachment) => attachment.type === "image" ? { ...attachment, type: "image" } : { ...attachment, type: "file" }
141658
142058
  )
@@ -141715,8 +142115,8 @@ var makeTurns = (core, deps) => {
141715
142115
 
141716
142116
  // src/webSync.ts
141717
142117
  var isWebSyncChat = (state, chatKey, threadId) => {
141718
- const record2 = chatOf(state, chatKey);
141719
- return record2.chatKind === "private" && record2.threadId === threadId;
142118
+ const record3 = chatOf(state, chatKey);
142119
+ return record3.chatKind === "private" && record3.threadId === threadId;
141720
142120
  };
141721
142121
  var IM_ORIGIN_LIMIT = 256;
141722
142122
  var MIRRORED_LIMIT = 256;
@@ -142269,7 +142669,7 @@ var makeWechatAdapter = (deps) => {
142269
142669
  };
142270
142670
 
142271
142671
  // src/wecomUpload.ts
142272
- import * as NodeCrypto3 from "node:crypto";
142672
+ import * as NodeCrypto4 from "node:crypto";
142273
142673
  var WECOM_CHUNK_BYTES = 512 * 1024;
142274
142674
  var WECOM_MAX_CHUNKS = 100;
142275
142675
  var WECOM_MIN_UPLOAD_BYTES = 5;
@@ -142302,7 +142702,7 @@ var uploadWecomMedia = async (input) => {
142302
142702
  filename: clampName(input.filename),
142303
142703
  total_size: bytes.byteLength,
142304
142704
  total_chunks: totalChunks,
142305
- md5: NodeCrypto3.createHash("md5").update(bytes).digest("hex")
142705
+ md5: NodeCrypto4.createHash("md5").update(bytes).digest("hex")
142306
142706
  });
142307
142707
  const uploadId = init.upload_id;
142308
142708
  if (typeof uploadId !== "string" || uploadId === "") {
@@ -142351,6 +142751,43 @@ var uploadWecomMedia = async (input) => {
142351
142751
  return mediaId;
142352
142752
  };
142353
142753
 
142754
+ // src/wecomReply.ts
142755
+ var wecomReplyReference = (quote) => {
142756
+ const attachments = [];
142757
+ const parts = [];
142758
+ const read = (item) => {
142759
+ switch (item.msgtype) {
142760
+ case "text":
142761
+ if (item.text?.content) parts.push(item.text.content);
142762
+ return true;
142763
+ case "voice":
142764
+ if (item.voice?.content) parts.push(item.voice.content);
142765
+ attachments.push({ kind: "audio" });
142766
+ return true;
142767
+ case "image":
142768
+ attachments.push({ kind: "image" });
142769
+ return true;
142770
+ case "file":
142771
+ attachments.push({ kind: "file" });
142772
+ return true;
142773
+ case "video":
142774
+ attachments.push({ kind: "video" });
142775
+ return true;
142776
+ case "mixed":
142777
+ for (const child of item.mixed?.msg_item ?? []) read(child);
142778
+ return true;
142779
+ default:
142780
+ return false;
142781
+ }
142782
+ };
142783
+ const supported = read(quote);
142784
+ return {
142785
+ ...parts.length === 0 ? {} : { content: parts.join("\n") },
142786
+ ...attachments.length === 0 ? {} : { attachments },
142787
+ ...!supported ? { unavailableReason: "unsupported" } : {}
142788
+ };
142789
+ };
142790
+
142354
142791
  // src/wecomApi.ts
142355
142792
  var DEFAULT_WECOM_ENDPOINT = "wss://openws.work.weixin.qq.com/wssvr/";
142356
142793
  var PING_INTERVAL_MS = 3e4;
@@ -142435,6 +142872,7 @@ var parseWecomMessage = (frame, botId) => {
142435
142872
  chatId,
142436
142873
  senderUserId: body.from?.userid ?? null,
142437
142874
  text: text4,
142875
+ ...body.quote === void 0 ? {} : { replyTo: wecomReplyReference(body.quote) },
142438
142876
  resources,
142439
142877
  requestId: frame.headers?.req_id ?? null,
142440
142878
  chatType: mentioned ? "single" : chatType,
@@ -142674,7 +143112,7 @@ var runWecomClient = (input) => {
142674
143112
  };
142675
143113
 
142676
143114
  // src/wecomMedia.ts
142677
- import * as NodeCrypto4 from "node:crypto";
143115
+ import * as NodeCrypto5 from "node:crypto";
142678
143116
 
142679
143117
  // src/wecomPadding.ts
142680
143118
  var PADDING_BLOCK = 32;
@@ -142705,7 +143143,7 @@ var decryptWecomMedia = (cipher, aesKey) => {
142705
143143
  if (cipher.byteLength === 0 || cipher.byteLength % AES_BLOCK !== 0) {
142706
143144
  throw new WecomDecryptError("the ciphertext is not a whole number of blocks");
142707
143145
  }
142708
- const decipher = NodeCrypto4.createDecipheriv("aes-256-cbc", key, key.subarray(0, IV_BYTES));
143146
+ const decipher = NodeCrypto5.createDecipheriv("aes-256-cbc", key, key.subarray(0, IV_BYTES));
142709
143147
  decipher.setAutoPadding(false);
142710
143148
  const plain = Buffer.concat([decipher.update(cipher), decipher.final()]);
142711
143149
  const unpadded = stripPadding(plain);
@@ -142857,6 +143295,7 @@ ${kept}`;
142857
143295
  chatId: message.chatId,
142858
143296
  senderId: message.senderUserId,
142859
143297
  text: message.text,
143298
+ ...message.replyTo === void 0 ? {} : { replyTo: message.replyTo },
142860
143299
  // 群里 @ 到机器人的消息被折算成 single 才放行;真实的聊天类型只留在 conversation。
142861
143300
  chatKind: message.conversation === "single" ? "private" : "group",
142862
143301
  // 下载地址与密钥打成一个键:核心只管把它原样交回来。
@@ -142995,14 +143434,14 @@ var WecomAppApiError = class extends Error {
142995
143434
  this.hint = extras?.hint;
142996
143435
  }
142997
143436
  };
142998
- var cleanString = (value2) => {
143437
+ var cleanString2 = (value2) => {
142999
143438
  if (typeof value2 !== "string") return null;
143000
143439
  const trimmed = value2.trim();
143001
143440
  return trimmed === "" ? null : trimmed;
143002
143441
  };
143003
143442
  var isHttpUrl = (raw) => /^https?:\/\//iu.test(raw) && URL.canParse(raw);
143004
143443
  var normalizeApiBaseUrl = (value2) => {
143005
- const raw = cleanString(value2);
143444
+ const raw = cleanString2(value2);
143006
143445
  if (raw === null) return WECOM_APP_DEFAULT_API_BASE;
143007
143446
  if (!isHttpUrl(raw)) {
143008
143447
  throw new WecomAppApiError("invalid-api-base", "API base must be an http(s) URL.");
@@ -143227,7 +143666,7 @@ var WecomAppApi = class {
143227
143666
  import * as NodeHttp2 from "node:http";
143228
143667
 
143229
143668
  // src/wecomAppCrypto.ts
143230
- import * as NodeCrypto5 from "node:crypto";
143669
+ import * as NodeCrypto6 from "node:crypto";
143231
143670
  var AES_KEY_BYTES = 32;
143232
143671
  var RANDOM_BYTES = 16;
143233
143672
  var WecomAppCryptoError = class extends Error {
@@ -143250,13 +143689,13 @@ var timingSafeEqualString2 = (a, b) => {
143250
143689
  const left = Buffer.from(a);
143251
143690
  const right = Buffer.from(b);
143252
143691
  if (left.length === 0 || left.length !== right.length) return false;
143253
- return NodeCrypto5.timingSafeEqual(left, right);
143692
+ return NodeCrypto6.timingSafeEqual(left, right);
143254
143693
  };
143255
- var computeSignature = (token, timestamp, nonce, encrypt) => NodeCrypto5.createHash("sha1").update([token, timestamp, nonce, encrypt].sort().join("")).digest("hex");
143694
+ var computeSignature = (token, timestamp, nonce, encrypt) => NodeCrypto6.createHash("sha1").update([token, timestamp, nonce, encrypt].sort().join("")).digest("hex");
143256
143695
  var verifySignature = (token, timestamp, nonce, encrypt, signature) => timingSafeEqualString2(computeSignature(token, timestamp, nonce, encrypt), signature);
143257
143696
  var decrypt = (encodingAESKey, encryptText, expectReceiveId) => {
143258
143697
  const { key, iv } = parseEncodingAESKey(encodingAESKey);
143259
- const decipher = NodeCrypto5.createDecipheriv("aes-256-cbc", key, iv);
143698
+ const decipher = NodeCrypto6.createDecipheriv("aes-256-cbc", key, iv);
143260
143699
  decipher.setAutoPadding(false);
143261
143700
  let deciphered;
143262
143701
  try {
@@ -143315,7 +143754,7 @@ var createWecomAppCrypto = (input) => {
143315
143754
  decrypt: (encryptText) => decrypt(encodingAESKey, encryptText, corpId).message
143316
143755
  };
143317
143756
  };
143318
- var deriveCallbackPathSecret = (token, encodingAESKey) => NodeCrypto5.createHash("sha256").update(`${token.trim()}:${encodingAESKey.trim()}`).digest("hex").slice(0, 24);
143757
+ var deriveCallbackPathSecret = (token, encodingAESKey) => NodeCrypto6.createHash("sha256").update(`${token.trim()}:${encodingAESKey.trim()}`).digest("hex").slice(0, 24);
143319
143758
 
143320
143759
  // src/wecomAppParse.ts
143321
143760
  var isRecord4 = (value2) => value2 !== null && typeof value2 === "object" && !Array.isArray(value2);