chattercatcher 0.1.30 → 0.1.31
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/cli.js +213 -17
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +212 -16
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -8,7 +8,7 @@ import fs15 from "fs/promises";
|
|
|
8
8
|
// package.json
|
|
9
9
|
var package_default = {
|
|
10
10
|
name: "chattercatcher",
|
|
11
|
-
version: "0.1.
|
|
11
|
+
version: "0.1.31",
|
|
12
12
|
description: "\u672C\u5730\u4F18\u5148\u7684\u98DE\u4E66/Lark \u5BB6\u5EAD\u7FA4\u77E5\u8BC6\u5E93\u673A\u5668\u4EBA",
|
|
13
13
|
type: "module",
|
|
14
14
|
main: "dist/index.js",
|
|
@@ -4439,6 +4439,166 @@ var FeishuQuestionHandler = class {
|
|
|
4439
4439
|
// src/feishu/sender.ts
|
|
4440
4440
|
import * as lark from "@larksuiteoapi/node-sdk";
|
|
4441
4441
|
import fs9 from "fs/promises";
|
|
4442
|
+
|
|
4443
|
+
// src/feishu/markdown-post.ts
|
|
4444
|
+
function escapeAtText(value) {
|
|
4445
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
4446
|
+
}
|
|
4447
|
+
function formatTextWithMentions(text, options) {
|
|
4448
|
+
const mentions = options?.mentions ?? [];
|
|
4449
|
+
if (mentions.length === 0) return text;
|
|
4450
|
+
const prefix = mentions.map((mention) => `<at user_id="${escapeAtText(mention.openId)}">${escapeAtText(mention.name)}</at>`).join(" ");
|
|
4451
|
+
return `${prefix} ${text}`.trim();
|
|
4452
|
+
}
|
|
4453
|
+
function findMarkdownLinkEnd(text, start) {
|
|
4454
|
+
let depth = 0;
|
|
4455
|
+
for (let index2 = start; index2 < text.length; index2 += 1) {
|
|
4456
|
+
const char = text[index2];
|
|
4457
|
+
if (char === "(") {
|
|
4458
|
+
depth += 1;
|
|
4459
|
+
} else if (char === ")") {
|
|
4460
|
+
if (depth === 0) return index2;
|
|
4461
|
+
depth -= 1;
|
|
4462
|
+
}
|
|
4463
|
+
}
|
|
4464
|
+
return -1;
|
|
4465
|
+
}
|
|
4466
|
+
function parseInline(text) {
|
|
4467
|
+
const elements = [];
|
|
4468
|
+
let index2 = 0;
|
|
4469
|
+
while (index2 < text.length) {
|
|
4470
|
+
const linkStart = text.indexOf("[", index2);
|
|
4471
|
+
const boldStarStart = text.indexOf("**", index2);
|
|
4472
|
+
const boldUnderscoreStart = text.indexOf("__", index2);
|
|
4473
|
+
const candidates = [linkStart, boldStarStart, boldUnderscoreStart].filter((value) => value >= 0);
|
|
4474
|
+
const next = candidates.length ? Math.min(...candidates) : -1;
|
|
4475
|
+
if (next < 0) {
|
|
4476
|
+
elements.push({ tag: "text", text: text.slice(index2) });
|
|
4477
|
+
break;
|
|
4478
|
+
}
|
|
4479
|
+
if (next > index2) {
|
|
4480
|
+
elements.push({ tag: "text", text: text.slice(index2, next) });
|
|
4481
|
+
}
|
|
4482
|
+
if (next === linkStart) {
|
|
4483
|
+
const labelEnd = text.indexOf("](", next);
|
|
4484
|
+
if (labelEnd > next) {
|
|
4485
|
+
const hrefStart = labelEnd + 2;
|
|
4486
|
+
const hrefEnd = findMarkdownLinkEnd(text, hrefStart);
|
|
4487
|
+
const href = hrefEnd >= 0 ? text.slice(hrefStart, hrefEnd) : "";
|
|
4488
|
+
if (hrefEnd >= 0 && /^https?:\/\/\S+$/.test(href)) {
|
|
4489
|
+
elements.push({ tag: "a", text: text.slice(next + 1, labelEnd), href });
|
|
4490
|
+
index2 = hrefEnd + 1;
|
|
4491
|
+
continue;
|
|
4492
|
+
}
|
|
4493
|
+
}
|
|
4494
|
+
elements.push({ tag: "text", text: text[next] });
|
|
4495
|
+
index2 = next + 1;
|
|
4496
|
+
continue;
|
|
4497
|
+
}
|
|
4498
|
+
const marker = next === boldStarStart ? "**" : "__";
|
|
4499
|
+
const close = text.indexOf(marker, next + marker.length);
|
|
4500
|
+
if (close > next + marker.length) {
|
|
4501
|
+
elements.push({ tag: "text", text: text.slice(next + marker.length, close), style: ["bold"] });
|
|
4502
|
+
index2 = close + marker.length;
|
|
4503
|
+
continue;
|
|
4504
|
+
}
|
|
4505
|
+
elements.push({ tag: "text", text: marker });
|
|
4506
|
+
index2 = next + marker.length;
|
|
4507
|
+
}
|
|
4508
|
+
const compacted = elements.filter((element) => element.tag !== "text" || element.text.length > 0);
|
|
4509
|
+
return compacted.length ? compacted : [{ tag: "text", text: " " }];
|
|
4510
|
+
}
|
|
4511
|
+
function pushParagraph(content, lines) {
|
|
4512
|
+
if (lines.length === 0) return;
|
|
4513
|
+
content.push(parseInline(lines.join("\n")));
|
|
4514
|
+
lines.length = 0;
|
|
4515
|
+
}
|
|
4516
|
+
function parseMarkdownBlocks(markdown) {
|
|
4517
|
+
if (!markdown.trim()) {
|
|
4518
|
+
return [[{ tag: "text", text: " " }]];
|
|
4519
|
+
}
|
|
4520
|
+
const content = [];
|
|
4521
|
+
const paragraph = [];
|
|
4522
|
+
const code = [];
|
|
4523
|
+
let inCodeBlock = false;
|
|
4524
|
+
for (const rawLine of markdown.replace(/\r\n/g, "\n").split("\n")) {
|
|
4525
|
+
const line = rawLine.trimEnd();
|
|
4526
|
+
if (line.startsWith("```")) {
|
|
4527
|
+
if (inCodeBlock) {
|
|
4528
|
+
content.push([{ tag: "text", text: `\`\`\`
|
|
4529
|
+
${code.join("\n")}
|
|
4530
|
+
\`\`\`` }]);
|
|
4531
|
+
code.length = 0;
|
|
4532
|
+
inCodeBlock = false;
|
|
4533
|
+
} else {
|
|
4534
|
+
pushParagraph(content, paragraph);
|
|
4535
|
+
inCodeBlock = true;
|
|
4536
|
+
}
|
|
4537
|
+
continue;
|
|
4538
|
+
}
|
|
4539
|
+
if (inCodeBlock) {
|
|
4540
|
+
code.push(rawLine);
|
|
4541
|
+
continue;
|
|
4542
|
+
}
|
|
4543
|
+
if (!line.trim()) {
|
|
4544
|
+
pushParagraph(content, paragraph);
|
|
4545
|
+
continue;
|
|
4546
|
+
}
|
|
4547
|
+
const heading = line.match(/^#{1,6}\s+(.+)$/);
|
|
4548
|
+
if (heading) {
|
|
4549
|
+
pushParagraph(content, paragraph);
|
|
4550
|
+
content.push([{ tag: "text", text: heading[1], style: ["bold"] }]);
|
|
4551
|
+
continue;
|
|
4552
|
+
}
|
|
4553
|
+
const unordered = line.match(/^[-*]\s+(.+)$/);
|
|
4554
|
+
if (unordered) {
|
|
4555
|
+
pushParagraph(content, paragraph);
|
|
4556
|
+
content.push(parseInline(`\u2022 ${unordered[1]}`));
|
|
4557
|
+
continue;
|
|
4558
|
+
}
|
|
4559
|
+
const ordered = line.match(/^(\d+)\.\s+(.+)$/);
|
|
4560
|
+
if (ordered) {
|
|
4561
|
+
pushParagraph(content, paragraph);
|
|
4562
|
+
content.push(parseInline(`${ordered[1]}. ${ordered[2]}`));
|
|
4563
|
+
continue;
|
|
4564
|
+
}
|
|
4565
|
+
paragraph.push(line);
|
|
4566
|
+
}
|
|
4567
|
+
if (inCodeBlock) {
|
|
4568
|
+
content.push([{ tag: "text", text: `\`\`\`
|
|
4569
|
+
${code.join("\n")}` }]);
|
|
4570
|
+
}
|
|
4571
|
+
pushParagraph(content, paragraph);
|
|
4572
|
+
return content.length ? content : [[{ tag: "text", text: markdown }]];
|
|
4573
|
+
}
|
|
4574
|
+
function buildFeishuPostContent(markdown, options) {
|
|
4575
|
+
const content = parseMarkdownBlocks(markdown);
|
|
4576
|
+
const mentions = options?.mentions ?? [];
|
|
4577
|
+
if (mentions.length) {
|
|
4578
|
+
const mentionElements = mentions.map((mention) => ({
|
|
4579
|
+
tag: "at",
|
|
4580
|
+
user_id: mention.openId,
|
|
4581
|
+
user_name: mention.name
|
|
4582
|
+
}));
|
|
4583
|
+
const firstLine = content[0] ?? [];
|
|
4584
|
+
const firstText = firstLine[0];
|
|
4585
|
+
if (firstText?.tag === "text") {
|
|
4586
|
+
content[0] = [...mentionElements, { ...firstText, text: ` ${firstText.text}` }, ...firstLine.slice(1)];
|
|
4587
|
+
} else {
|
|
4588
|
+
content[0] = [...mentionElements, { tag: "text", text: " " }, ...firstLine];
|
|
4589
|
+
}
|
|
4590
|
+
}
|
|
4591
|
+
return {
|
|
4592
|
+
post: {
|
|
4593
|
+
zh_cn: {
|
|
4594
|
+
title: "",
|
|
4595
|
+
content
|
|
4596
|
+
}
|
|
4597
|
+
}
|
|
4598
|
+
};
|
|
4599
|
+
}
|
|
4600
|
+
|
|
4601
|
+
// src/feishu/sender.ts
|
|
4442
4602
|
function mapDomain(domain) {
|
|
4443
4603
|
return domain === "lark" ? lark.Domain.Lark : lark.Domain.Feishu;
|
|
4444
4604
|
}
|
|
@@ -4454,14 +4614,21 @@ function extractImageKey(response) {
|
|
|
4454
4614
|
}
|
|
4455
4615
|
throw new Error("\u98DE\u4E66\u56FE\u7247\u4E0A\u4F20\u54CD\u5E94\u7F3A\u5C11 image_key\u3002");
|
|
4456
4616
|
}
|
|
4457
|
-
function
|
|
4458
|
-
|
|
4617
|
+
function isRichTextCompatibilityError(error) {
|
|
4618
|
+
const value = error && typeof error === "object" ? error : {};
|
|
4619
|
+
const code = value.code ?? value.errorCode;
|
|
4620
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
4621
|
+
return code === 230001 || /post|msg_type|content|unsupported|invalid/i.test(message);
|
|
4459
4622
|
}
|
|
4460
|
-
function
|
|
4461
|
-
|
|
4462
|
-
|
|
4463
|
-
|
|
4464
|
-
|
|
4623
|
+
async function sendWithTextFallback(input2) {
|
|
4624
|
+
try {
|
|
4625
|
+
await input2.sendPost();
|
|
4626
|
+
} catch (error) {
|
|
4627
|
+
if (!isRichTextCompatibilityError(error)) {
|
|
4628
|
+
throw error;
|
|
4629
|
+
}
|
|
4630
|
+
await input2.sendText();
|
|
4631
|
+
}
|
|
4465
4632
|
}
|
|
4466
4633
|
var FeishuMessageSender = class _FeishuMessageSender {
|
|
4467
4634
|
constructor(client) {
|
|
@@ -4477,7 +4644,17 @@ var FeishuMessageSender = class _FeishuMessageSender {
|
|
|
4477
4644
|
return new _FeishuMessageSender(client);
|
|
4478
4645
|
}
|
|
4479
4646
|
async sendTextToChat(chatId, text, options) {
|
|
4480
|
-
const
|
|
4647
|
+
const postPayload = {
|
|
4648
|
+
data: {
|
|
4649
|
+
receive_id: chatId,
|
|
4650
|
+
msg_type: "post",
|
|
4651
|
+
content: JSON.stringify(buildFeishuPostContent(text, options))
|
|
4652
|
+
},
|
|
4653
|
+
params: {
|
|
4654
|
+
receive_id_type: "chat_id"
|
|
4655
|
+
}
|
|
4656
|
+
};
|
|
4657
|
+
const textPayload = {
|
|
4481
4658
|
data: {
|
|
4482
4659
|
receive_id: chatId,
|
|
4483
4660
|
msg_type: "text",
|
|
@@ -4488,16 +4665,20 @@ var FeishuMessageSender = class _FeishuMessageSender {
|
|
|
4488
4665
|
}
|
|
4489
4666
|
};
|
|
4490
4667
|
if (this.client.im.v1?.message.create) {
|
|
4491
|
-
await
|
|
4668
|
+
await sendWithTextFallback({
|
|
4669
|
+
sendPost: () => this.client.im.v1.message.create(postPayload),
|
|
4670
|
+
sendText: () => this.client.im.v1.message.create(textPayload)
|
|
4671
|
+
});
|
|
4492
4672
|
return;
|
|
4493
4673
|
}
|
|
4494
4674
|
if (this.client.im.message?.create) {
|
|
4495
|
-
await
|
|
4675
|
+
await sendWithTextFallback({
|
|
4676
|
+
sendPost: () => this.client.im.message.create(postPayload),
|
|
4677
|
+
sendText: () => this.client.im.message.create(textPayload)
|
|
4678
|
+
});
|
|
4496
4679
|
return;
|
|
4497
4680
|
}
|
|
4498
|
-
|
|
4499
|
-
throw new Error("\u5F53\u524D\u98DE\u4E66 SDK \u4E0D\u652F\u6301\u6D88\u606F\u53D1\u9001\u63A5\u53E3\u3002");
|
|
4500
|
-
}
|
|
4681
|
+
throw new Error("\u5F53\u524D\u98DE\u4E66 SDK \u4E0D\u652F\u6301\u6D88\u606F\u53D1\u9001\u63A5\u53E3\u3002");
|
|
4501
4682
|
}
|
|
4502
4683
|
async sendImageToChat(chatId, imagePath) {
|
|
4503
4684
|
const imageCreate = this.client.im.v1?.image?.create;
|
|
@@ -4533,7 +4714,16 @@ var FeishuMessageSender = class _FeishuMessageSender {
|
|
|
4533
4714
|
throw new Error("\u5F53\u524D\u98DE\u4E66 SDK \u4E0D\u652F\u6301\u6D88\u606F\u53D1\u9001\u63A5\u53E3\u3002");
|
|
4534
4715
|
}
|
|
4535
4716
|
async replyTextToMessage(messageId, text) {
|
|
4536
|
-
const
|
|
4717
|
+
const postPayload = {
|
|
4718
|
+
path: {
|
|
4719
|
+
message_id: messageId
|
|
4720
|
+
},
|
|
4721
|
+
data: {
|
|
4722
|
+
msg_type: "post",
|
|
4723
|
+
content: JSON.stringify(buildFeishuPostContent(text))
|
|
4724
|
+
}
|
|
4725
|
+
};
|
|
4726
|
+
const textPayload = {
|
|
4537
4727
|
path: {
|
|
4538
4728
|
message_id: messageId
|
|
4539
4729
|
},
|
|
@@ -4543,11 +4733,17 @@ var FeishuMessageSender = class _FeishuMessageSender {
|
|
|
4543
4733
|
}
|
|
4544
4734
|
};
|
|
4545
4735
|
if (this.client.im.v1?.message.reply) {
|
|
4546
|
-
await
|
|
4736
|
+
await sendWithTextFallback({
|
|
4737
|
+
sendPost: () => this.client.im.v1.message.reply(postPayload),
|
|
4738
|
+
sendText: () => this.client.im.v1.message.reply(textPayload)
|
|
4739
|
+
});
|
|
4547
4740
|
return;
|
|
4548
4741
|
}
|
|
4549
4742
|
if (this.client.im.message?.reply) {
|
|
4550
|
-
await
|
|
4743
|
+
await sendWithTextFallback({
|
|
4744
|
+
sendPost: () => this.client.im.message.reply(postPayload),
|
|
4745
|
+
sendText: () => this.client.im.message.reply(textPayload)
|
|
4746
|
+
});
|
|
4551
4747
|
return;
|
|
4552
4748
|
}
|
|
4553
4749
|
throw new Error("\u5F53\u524D\u98DE\u4E66 SDK \u4E0D\u652F\u6301\u6D88\u606F\u56DE\u590D\u63A5\u53E3\u3002");
|