@modelzen/feishu-codex-bridge 0.6.0 → 0.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/cli.js +139 -5
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -829,9 +829,9 @@ var init_cards = __esm({
829
829
  // src/card/managed.ts
830
830
  function stampRenderToken(card2) {
831
831
  const token = (++renderToken).toString(36);
832
- const visit = (node) => {
832
+ const visit2 = (node) => {
833
833
  if (Array.isArray(node)) {
834
- node.forEach(visit);
834
+ node.forEach(visit2);
835
835
  return;
836
836
  }
837
837
  if (!node || typeof node !== "object") return;
@@ -845,9 +845,9 @@ function stampRenderToken(card2) {
845
845
  }
846
846
  }
847
847
  }
848
- for (const k2 of Object.keys(obj)) visit(obj[k2]);
848
+ for (const k2 of Object.keys(obj)) visit2(obj[k2]);
849
849
  };
850
- visit(card2);
850
+ visit2(card2);
851
851
  }
852
852
  function isCardIdNotReady(err) {
853
853
  const data = err?.response?.data;
@@ -5953,6 +5953,7 @@ function buildDoctorCard(i) {
5953
5953
  `- Codex\uFF1A${i.codexOk ? `\u2705 \u53EF\u7528${i.codexVer ? `\uFF08${i.codexVer}\uFF09` : ""}` : "\u274C \u4E0D\u53EF\u7528\uFF08\u68C0\u67E5 CODEX_BIN / PATH\uFF09"}`
5954
5954
  ),
5955
5955
  md(`- \u98DE\u4E66\u957F\u8FDE\u63A5\uFF1A${connLabel(i.conn)}`),
5956
+ md(`- \u673A\u5668\u4EBA open_id\uFF1A${i.botOpenId ? `\`${i.botOpenId}\`` : "\u26A0\uFE0F \u672A\u80FD\u83B7\u53D6\uFF08\u51ED\u636E\u5931\u6548\u6216\u7F51\u7EDC\u4E0D\u901A\uFF09"}`),
5956
5957
  ...scopeDiagnosis(i),
5957
5958
  ...eventSubscriptionDiagnosis(i),
5958
5959
  note(`bridge v${i.bridgeVer}\u3000\xB7\u3000Node ${i.node}\u3000\xB7\u3000${i.platform}`),
@@ -9741,6 +9742,80 @@ async function handleDmConsole(channel, cfg, msg) {
9741
9742
  });
9742
9743
  }
9743
9744
 
9745
+ // src/bot/card-content.ts
9746
+ init_logger();
9747
+ function isDegradedCardContent(content) {
9748
+ const t = content.trim();
9749
+ if (t === "" || t === "[interactive card]") return true;
9750
+ return /请升级至最新版本客户端|请使用新版本.*查看|client to view|upgrade .*client/i.test(t);
9751
+ }
9752
+ function parseRawCardWrapper(bodyContent) {
9753
+ try {
9754
+ const parsed = JSON.parse(bodyContent);
9755
+ if (typeof parsed.json_card === "string") return JSON.parse(parsed.json_card);
9756
+ return parsed;
9757
+ } catch {
9758
+ return void 0;
9759
+ }
9760
+ }
9761
+ function extractRawCardText(jsonCard) {
9762
+ const out = [];
9763
+ visit(jsonCard, out);
9764
+ const seen = /* @__PURE__ */ new Set();
9765
+ const lines = [];
9766
+ for (const piece of out) {
9767
+ const key = piece.trim();
9768
+ if (!key || seen.has(key)) continue;
9769
+ seen.add(key);
9770
+ lines.push(key);
9771
+ }
9772
+ return lines.join("\n");
9773
+ }
9774
+ function visit(node, out) {
9775
+ if (node == null) return;
9776
+ if (Array.isArray(node)) {
9777
+ for (const child of node) visit(child, out);
9778
+ return;
9779
+ }
9780
+ if (typeof node !== "object") return;
9781
+ const obj = node;
9782
+ if (obj.header) visit(obj.header, out);
9783
+ if (obj.body) visit(obj.body, out);
9784
+ const prop = obj.property;
9785
+ if (!prop) return;
9786
+ if (typeof prop.content === "string" && prop.content.trim()) {
9787
+ const url = prop.url?.url;
9788
+ out.push(url ? `[${prop.content.trim()}](${url})` : prop.content);
9789
+ }
9790
+ const i18n = prop.i18nElements;
9791
+ if (i18n && typeof i18n === "object") {
9792
+ visit(i18n.zh_cn ?? i18n.zh_hk ?? i18n.zh_tw ?? i18n.en_us ?? Object.values(i18n)[0], out);
9793
+ }
9794
+ visit(prop.title, out);
9795
+ visit(prop.text, out);
9796
+ visit(prop.elements, out);
9797
+ visit(prop.columns, out);
9798
+ visit(prop.actions, out);
9799
+ }
9800
+ async function fetchInteractiveCardText(channel, messageId) {
9801
+ let body;
9802
+ try {
9803
+ const res = await channel.rawClient.im.v1.message.get({
9804
+ path: { message_id: messageId },
9805
+ params: { card_msg_content_type: "raw_card_content" }
9806
+ });
9807
+ body = res.data?.items?.[0]?.body?.content;
9808
+ } catch (err) {
9809
+ log.warn("intake", "card-content-fetch-failed", { messageId, err: String(err) });
9810
+ return void 0;
9811
+ }
9812
+ if (!body) return void 0;
9813
+ const card2 = parseRawCardWrapper(body);
9814
+ if (card2 == null) return void 0;
9815
+ const text = extractRawCardText(card2);
9816
+ return text.trim() ? text : void 0;
9817
+ }
9818
+
9744
9819
  // src/bot/media.ts
9745
9820
  init_paths();
9746
9821
  init_logger();
@@ -10061,7 +10136,7 @@ function extractMessageText(msgType, content, mentions) {
10061
10136
  case "sticker":
10062
10137
  return "[\u8868\u60C5]";
10063
10138
  case "interactive":
10064
- return "[\u5361\u7247\u6D88\u606F]";
10139
+ return extractCardText(parsed) || "[\u5361\u7247\u6D88\u606F]";
10065
10140
  case "share_chat":
10066
10141
  return "[\u5206\u4EAB\u7FA4\u540D\u7247]";
10067
10142
  case "share_user":
@@ -10123,6 +10198,55 @@ function nodeToText(node) {
10123
10198
  return typeof n.text === "string" ? n.text : "";
10124
10199
  }
10125
10200
  }
10201
+ var CARD_UPGRADE_HINT = "\u8BF7\u5347\u7EA7\u81F3\u6700\u65B0\u7248\u672C\u5BA2\u6237\u7AEF";
10202
+ function extractCardText(parsed) {
10203
+ if (!parsed || typeof parsed !== "object") return "";
10204
+ const obj = parsed;
10205
+ const parts = [];
10206
+ const title = textValue(obj.title);
10207
+ if (title.trim()) parts.push(title.trim());
10208
+ if (Array.isArray(obj.elements)) {
10209
+ for (const line of obj.elements) {
10210
+ const nodes = Array.isArray(line) ? line : [line];
10211
+ const lineText = nodes.map(cardNodeToText).join("").trim();
10212
+ if (lineText && !lineText.includes(CARD_UPGRADE_HINT)) parts.push(lineText);
10213
+ }
10214
+ }
10215
+ return parts.join("\n").trim();
10216
+ }
10217
+ function textValue(t) {
10218
+ if (typeof t === "string") return t;
10219
+ if (t && typeof t === "object") {
10220
+ const c = t.content;
10221
+ if (typeof c === "string") return c;
10222
+ }
10223
+ return "";
10224
+ }
10225
+ function cardNodeToText(node) {
10226
+ if (typeof node === "string") return node;
10227
+ if (!node || typeof node !== "object") return "";
10228
+ const n = node;
10229
+ switch (n.tag) {
10230
+ case "text":
10231
+ return textValue(n.text);
10232
+ case "a":
10233
+ return textValue(n.text) || (typeof n.href === "string" ? n.href : "");
10234
+ case "at": {
10235
+ const name = typeof n.user_name === "string" ? n.user_name : "";
10236
+ return name ? `@${name}` : "@\u67D0\u4EBA";
10237
+ }
10238
+ case "note":
10239
+ return Array.isArray(n.elements) ? n.elements.map(cardNodeToText).join("") : "";
10240
+ case "button": {
10241
+ const label = textValue(n.text);
10242
+ return label ? `[\u6309\u94AE\uFF1A${label}]` : "";
10243
+ }
10244
+ case "img":
10245
+ return "";
10246
+ default:
10247
+ return textValue(n.text);
10248
+ }
10249
+ }
10126
10250
  function replaceMentions(text, mentions) {
10127
10251
  if (!text || !mentions?.length) return text;
10128
10252
  let out = text;
@@ -10768,6 +10892,13 @@ function createOrchestrator(channel, cfg, fallbackCwd, cliBridge) {
10768
10892
  }
10769
10893
  return;
10770
10894
  }
10895
+ if (msg.rawContentType === "interactive" && isDegradedCardContent(msg.content)) {
10896
+ const full = await fetchInteractiveCardText(channel, msg.messageId);
10897
+ if (full) {
10898
+ log.info("intake", "card-content-enriched", { msgId: msg.messageId, len: full.length });
10899
+ msg.content = full;
10900
+ }
10901
+ }
10771
10902
  const text = msg.content.trim();
10772
10903
  const cmd = parseCommand(text);
10773
10904
  const goalObjective = parseGoalTrigger(text);
@@ -11590,6 +11721,9 @@ function createOrchestrator(channel, cfg, fallbackCwd, cliBridge) {
11590
11721
  codexOk: codexProbe.ok,
11591
11722
  codexVer: codexProbe.version,
11592
11723
  conn: channel.getConnectionStatus?.()?.state ?? "unknown",
11724
+ // 复用上面 validateAppCredentials 的返回(bot/v3/info),不额外发请求;
11725
+ // scopeCheck 没换成 token → undefined,卡片降级显示「未能获取」。
11726
+ botOpenId: scopeCheck?.botOpenId,
11593
11727
  bridgeVer: bridgeVersion(),
11594
11728
  node: process.version,
11595
11729
  platform: `${process.platform}-${process.arch}`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@modelzen/feishu-codex-bridge",
3
- "version": "0.6.0",
3
+ "version": "0.6.2",
4
4
  "description": "Bridge Feishu/Lark messenger with local Codex via app-server (project=group, thread=session)",
5
5
  "type": "module",
6
6
  "bin": {