feishu-bridge 1.0.6 → 1.0.8

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/index.js CHANGED
@@ -616,9 +616,6 @@ ${error.substring(0, 2e3)}`;
616
616
  }
617
617
  };
618
618
 
619
- // src/feishu/websocket.ts
620
- var import_ws = require("ws");
621
-
622
619
  // src/core/message-router.ts
623
620
  init_logger();
624
621
  var MessageRouter = class {
@@ -761,163 +758,109 @@ var MessageRouter = class {
761
758
  // src/feishu/websocket.ts
762
759
  init_logger();
763
760
  init_config();
761
+ var Lark = __toESM(require("@larksuiteoapi/node-sdk"));
764
762
  var FeishuWebSocketHandler = class {
765
763
  constructor(client, commandExecutor, adapters) {
766
764
  this.client = client;
767
765
  this.commandExecutor = commandExecutor;
768
766
  this.adapters = adapters;
769
- this.ws = null;
770
- this.reconnectAttempts = 0;
771
- this.maxReconnectAttempts = 5;
772
- this.reconnectInterval = 5e3;
773
- // 5秒
774
- this.heartbeatInterval = null;
767
+ this.wsClient = null;
768
+ this.eventDispatcher = null;
775
769
  this.isRunning = false;
776
770
  this.logger = new Logger();
777
771
  this.messageRouter = new MessageRouter(adapters);
778
772
  }
779
- /**
780
- * 启动WebSocket连接
781
- */
782
773
  async start() {
783
774
  if (this.isRunning) {
784
775
  this.logger.warn("WebSocket handler already running");
785
776
  return;
786
777
  }
787
- this.isRunning = true;
788
- this.reconnectAttempts = 0;
789
- await this.connect();
790
- }
791
- /**
792
- * 停止WebSocket连接
793
- */
794
- async stop() {
795
- this.isRunning = false;
796
- if (this.heartbeatInterval) {
797
- clearInterval(this.heartbeatInterval);
798
- this.heartbeatInterval = null;
799
- }
800
- if (this.ws) {
801
- this.ws.close();
802
- this.ws = null;
803
- }
804
- this.logger.info("WebSocket handler stopped");
805
- }
806
- /**
807
- * 建立WebSocket连接
808
- */
809
- async connect() {
778
+ const config = ConfigManager.getInstance().getFeishuConfig();
810
779
  try {
811
- const config = ConfigManager.getInstance().getFeishuConfig();
812
- const wsUrl = config.domain === "feishu" ? "wss://ws.feishu.cn/passport/" : "wss://ws.larksuite.com/passport/";
813
- this.logger.info(`Connecting to WebSocket: ${wsUrl}`);
814
- this.ws = new import_ws.WebSocket(wsUrl, {
815
- headers: {
816
- "Authorization": `Bearer ${await this.getAccessToken()}`
817
- }
780
+ this.logger.info("Creating Feishu WebSocket client...");
781
+ this.wsClient = new Lark.WSClient({
782
+ appId: config.appId,
783
+ appSecret: config.appSecret,
784
+ domain: config.domain === "lark" ? Lark.Domain.Lark : Lark.Domain.Feishu,
785
+ loggerLevel: Lark.LoggerLevel.info
818
786
  });
819
- this.setupWebSocketHandlers();
787
+ this.eventDispatcher = new Lark.EventDispatcher({
788
+ encryptKey: config.encryptKey || "",
789
+ verificationToken: config.verificationToken || ""
790
+ });
791
+ this.registerEventHandlers();
792
+ this.logger.info("Starting WebSocket connection...");
793
+ await this.wsClient.start({ eventDispatcher: this.eventDispatcher });
794
+ this.isRunning = true;
795
+ this.logger.info("\u2705 Feishu WebSocket connected successfully!");
820
796
  } catch (error) {
821
- this.logger.error("Failed to connect WebSocket:", error);
822
- this.handleReconnect();
797
+ this.logger.error("\u274C Failed to start WebSocket handler:", error);
798
+ throw error;
823
799
  }
824
800
  }
825
- /**
826
- * 设置WebSocket事件处理器
827
- */
828
- setupWebSocketHandlers() {
829
- if (!this.ws) return;
830
- this.ws.on("open", () => {
831
- this.logger.info("WebSocket connected");
832
- this.reconnectAttempts = 0;
833
- this.startHeartbeat();
834
- });
835
- this.ws.on("message", (data) => {
836
- this.handleMessage(data.toString());
837
- });
838
- this.ws.on("close", (code, reason) => {
839
- this.logger.info(`WebSocket closed: ${code} - ${reason.toString()}`);
840
- this.stopHeartbeat();
841
- if (this.isRunning) {
842
- this.handleReconnect();
801
+ registerEventHandlers() {
802
+ if (!this.eventDispatcher) return;
803
+ this.eventDispatcher.register({
804
+ "im.message.receive_v1": async (event) => {
805
+ await this.handleMessageEvent(event);
806
+ },
807
+ "im.message.message_read_v1": (event) => {
808
+ this.logger.debug("Message read:", event);
809
+ },
810
+ "im.chat.member.bot.added_v1": (event) => {
811
+ this.logger.info("Bot added to chat:", event);
812
+ },
813
+ "im.chat.member.bot.deleted_v1": (event) => {
814
+ this.logger.info("Bot removed from chat:", event);
843
815
  }
844
816
  });
845
- this.ws.on("error", (error) => {
846
- this.logger.error("WebSocket error:", error);
847
- });
848
- this.ws.on("ping", () => {
849
- this.ws?.pong();
850
- });
851
- }
852
- /**
853
- * 处理收到的消息
854
- */
855
- async handleMessage(data) {
856
- try {
857
- const event = JSON.parse(data);
858
- this.logger.debug("Received WebSocket message:", event);
859
- if (event.type === "url_verification") {
860
- this.logger.info("Received URL verification challenge via WebSocket");
861
- return;
862
- }
863
- if (event.type === "event_callback" && event.event) {
864
- await this.handleEvent(event.event);
865
- }
866
- } catch (error) {
867
- this.logger.error("Error handling WebSocket message:", error);
868
- }
869
817
  }
870
- /**
871
- * 处理事件
872
- */
873
- async handleEvent(event) {
874
- const { message } = event;
818
+ async handleMessageEvent(event) {
819
+ const { message, sender } = event;
875
820
  if (!message || message.message_type !== "text") {
876
821
  this.logger.debug("Ignoring non-text message");
877
822
  return;
878
823
  }
879
824
  try {
880
825
  const content = JSON.parse(message.content);
881
- const text = content.text.trim();
882
- const sender = event.sender?.sender_id?.open_id;
883
- if (!sender) {
826
+ const text = content.text?.trim() || "";
827
+ const senderId = sender?.sender_id?.open_id;
828
+ if (!senderId) {
884
829
  this.logger.warn("Missing sender ID");
885
830
  return;
886
831
  }
887
- this.logger.info(`Received message from ${sender}: ${text}`);
832
+ this.logger.info(`\u{1F4E8} Received message from ${senderId}: ${text}`);
888
833
  const route = await this.messageRouter.route(text);
889
834
  if (route.type === "error") {
890
835
  await this.client.sendMessage(message.chat_id, {
891
836
  msg_type: "text",
892
- content: {
893
- text: route.content
894
- }
837
+ content: { text: route.content }
895
838
  });
896
839
  return;
897
840
  }
898
841
  if (route.type === "prompt_choice") {
899
842
  await this.client.sendMessage(message.chat_id, {
900
843
  msg_type: "text",
901
- content: {
902
- text: route.content
903
- }
844
+ content: { text: route.content }
904
845
  });
905
846
  return;
906
847
  }
907
848
  if (route.type === "direct" && route.target) {
908
849
  const command = this.messageRouter.extractCommand(text);
909
- this.logger.info(`Routing to ${route.target}: ${command}`);
850
+ this.logger.info(`\u{1F3AF} Routing to ${route.target}: ${command}`);
851
+ await this.client.sendMessage(message.chat_id, {
852
+ msg_type: "text",
853
+ content: { text: `\u23F3 \u6B63\u5728\u6267\u884C: ${command}` }
854
+ });
910
855
  const result = await this.commandExecutor.execute({
911
856
  target: route.target,
912
857
  command,
913
- sender,
858
+ sender: senderId,
914
859
  chatId: message.chat_id
915
860
  });
916
861
  await this.client.sendMessage(message.chat_id, {
917
862
  msg_type: "text",
918
- content: {
919
- text: this.formatResponse(result)
920
- }
863
+ content: { text: this.formatResponse(result) }
921
864
  });
922
865
  }
923
866
  } catch (error) {
@@ -925,89 +868,13 @@ var FeishuWebSocketHandler = class {
925
868
  try {
926
869
  await this.client.sendMessage(message.chat_id, {
927
870
  msg_type: "text",
928
- content: {
929
- text: `\u274C \u5904\u7406\u6D88\u606F\u65F6\u51FA\u9519: ${error instanceof Error ? error.message : "\u672A\u77E5\u9519\u8BEF"}`
930
- }
871
+ content: { text: `\u274C \u5904\u7406\u6D88\u606F\u65F6\u51FA\u9519` }
931
872
  });
932
873
  } catch (sendError) {
933
874
  this.logger.error("Failed to send error message:", sendError);
934
875
  }
935
876
  }
936
877
  }
937
- /**
938
- * 启动心跳保活
939
- */
940
- startHeartbeat() {
941
- this.heartbeatInterval = setInterval(() => {
942
- if (this.ws?.readyState === import_ws.WebSocket.OPEN) {
943
- this.ws.ping();
944
- }
945
- }, 3e4);
946
- }
947
- /**
948
- * 停止心跳
949
- */
950
- stopHeartbeat() {
951
- if (this.heartbeatInterval) {
952
- clearInterval(this.heartbeatInterval);
953
- this.heartbeatInterval = null;
954
- }
955
- }
956
- /**
957
- * 处理重连
958
- */
959
- handleReconnect() {
960
- if (this.reconnectAttempts >= this.maxReconnectAttempts) {
961
- this.logger.error(`Max reconnection attempts (${this.maxReconnectAttempts}) reached`);
962
- return;
963
- }
964
- this.reconnectAttempts++;
965
- const delay = this.reconnectInterval * this.reconnectAttempts;
966
- this.logger.info(`Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts}/${this.maxReconnectAttempts})`);
967
- setTimeout(() => {
968
- if (this.isRunning) {
969
- this.connect();
970
- }
971
- }, delay);
972
- }
973
- /**
974
- * 获取访问令牌
975
- */
976
- async getAccessToken() {
977
- const config = ConfigManager.getInstance().getFeishuConfig();
978
- const response = await fetch(
979
- `https://open.${config.domain === "lark" ? "larksuite" : "feishu"}.cn/open-apis/auth/v3/tenant_access_token/internal`,
980
- {
981
- method: "POST",
982
- headers: { "Content-Type": "application/json" },
983
- body: JSON.stringify({
984
- app_id: config.appId,
985
- app_secret: config.appSecret
986
- })
987
- }
988
- );
989
- const data = await response.json();
990
- if (data.code !== 0) {
991
- throw new Error(`Failed to get access token: ${data.msg}`);
992
- }
993
- return data.tenant_access_token;
994
- }
995
- /**
996
- * 提取目标IDE
997
- */
998
- extractTargetIDE(text) {
999
- const match = text.match(/@(vscode|cursor|trae|antigravity|kiro|opencode|claude)/i);
1000
- return match ? match[1].toLowerCase() : "auto";
1001
- }
1002
- /**
1003
- * 提取命令
1004
- */
1005
- extractCommand(text) {
1006
- return text.replace(/@(vscode|cursor|trae|antigravity|kiro|opencode|claude)\s*/i, "").trim();
1007
- }
1008
- /**
1009
- * 格式化响应
1010
- */
1011
878
  formatResponse(result) {
1012
879
  if (result.success) {
1013
880
  const output = typeof result.output === "string" ? result.output.substring(0, 2e3) : JSON.stringify(result.output).substring(0, 2e3);
@@ -1021,6 +888,14 @@ ${output}`;
1021
888
  ${error.substring(0, 2e3)}`;
1022
889
  }
1023
890
  }
891
+ async stop() {
892
+ this.isRunning = false;
893
+ if (this.wsClient) {
894
+ this.wsClient.close();
895
+ this.wsClient = null;
896
+ }
897
+ this.logger.info("WebSocket handler stopped");
898
+ }
1024
899
  };
1025
900
 
1026
901
  // src/feishu/client.ts
@@ -3445,18 +3320,42 @@ var ReverseChannel = class extends import_events.EventEmitter {
3445
3320
  };
3446
3321
 
3447
3322
  // src/skills/builtin/feishu.ts
3323
+ init_config();
3448
3324
  var FeishuSkills = class {
3449
3325
  constructor(client) {
3326
+ this.accessToken = null;
3327
+ this.tokenExpireTime = 0;
3450
3328
  this.client = client;
3329
+ const config = ConfigManager.getInstance().getFeishuConfig();
3330
+ this.baseUrl = config.domain === "lark" ? "https://open.larksuite.com/open-apis" : "https://open.feishu.cn/open-apis";
3331
+ }
3332
+ async getAccessToken() {
3333
+ const now = Date.now();
3334
+ if (this.accessToken && now < this.tokenExpireTime) {
3335
+ return this.accessToken;
3336
+ }
3337
+ const config = ConfigManager.getInstance().getFeishuConfig();
3338
+ const response = await fetch(`${this.baseUrl}/auth/v3/tenant_access_token/internal`, {
3339
+ method: "POST",
3340
+ headers: { "Content-Type": "application/json" },
3341
+ body: JSON.stringify({
3342
+ app_id: config.appId,
3343
+ app_secret: config.appSecret
3344
+ })
3345
+ });
3346
+ const data = await response.json();
3347
+ if (data.code !== 0) {
3348
+ throw new Error(`Failed to get access token: ${data.msg}`);
3349
+ }
3350
+ this.accessToken = data.tenant_access_token;
3351
+ this.tokenExpireTime = now + (data.expire - 300) * 1e3;
3352
+ return this.accessToken;
3451
3353
  }
3452
- /**
3453
- * 发送消息技能
3454
- */
3455
3354
  sendMessageSkill() {
3456
3355
  return {
3457
3356
  name: "feishu.sendMessage",
3458
3357
  description: "\u53D1\u9001\u6D88\u606F\u5230\u6307\u5B9A\u4F1A\u8BDD",
3459
- trigger: /发送消息|发信息/,
3358
+ trigger: /发送消息|发信息|发消息/,
3460
3359
  riskLevel: "low",
3461
3360
  examples: [
3462
3361
  "\u53D1\u9001\u6D88\u606F\u7ED9\u5F20\u4E09\uFF1A\u4E0B\u5348\u5F00\u4F1A",
@@ -3464,32 +3363,23 @@ var FeishuSkills = class {
3464
3363
  ],
3465
3364
  execute: async (context) => {
3466
3365
  try {
3467
- const { target, content } = this.parseMessageArgs(context.message);
3366
+ const { content } = this.parseMessageArgs(context.message);
3468
3367
  await this.client.sendMessage(context.chatId, {
3469
3368
  msg_type: "text",
3470
3369
  content: { text: content }
3471
3370
  });
3472
- return {
3473
- success: true,
3474
- content: "\u2705 \u6D88\u606F\u5DF2\u53D1\u9001"
3475
- };
3371
+ return { success: true, content: "\u2705 \u6D88\u606F\u5DF2\u53D1\u9001" };
3476
3372
  } catch (error) {
3477
- return {
3478
- success: false,
3479
- content: `\u274C \u53D1\u9001\u5931\u8D25: ${error instanceof Error ? error.message : "\u672A\u77E5\u9519\u8BEF"}`
3480
- };
3373
+ return { success: false, content: `\u274C \u53D1\u9001\u5931\u8D25: ${error instanceof Error ? error.message : "\u672A\u77E5\u9519\u8BEF"}` };
3481
3374
  }
3482
3375
  }
3483
3376
  };
3484
3377
  }
3485
- /**
3486
- * 创建日程技能
3487
- */
3488
3378
  createEventSkill() {
3489
3379
  return {
3490
3380
  name: "feishu.createEvent",
3491
3381
  description: "\u5728\u98DE\u4E66\u65E5\u5386\u521B\u5EFA\u65E5\u7A0B",
3492
- trigger: /创建日程|创建会议|添加日程/,
3382
+ trigger: /创建日程|创建会议|添加日程|新建日程/,
3493
3383
  riskLevel: "medium",
3494
3384
  examples: [
3495
3385
  "\u521B\u5EFA\u65E5\u7A0B\uFF1A\u660E\u5929\u4E0B\u53483\u70B9\u56E2\u961F\u5468\u4F1A",
@@ -3497,36 +3387,57 @@ var FeishuSkills = class {
3497
3387
  ],
3498
3388
  execute: async (context) => {
3499
3389
  try {
3500
- const { title, startTime, attendees } = this.parseEventArgs(context.message);
3390
+ const { title, startTime, endTime, description } = this.parseEventArgs(context.message);
3391
+ const token = await this.getAccessToken();
3392
+ const response = await fetch(`${this.baseUrl}/calendar/v4/calendars/primary/events`, {
3393
+ method: "POST",
3394
+ headers: {
3395
+ "Authorization": `Bearer ${token}`,
3396
+ "Content-Type": "application/json"
3397
+ },
3398
+ body: JSON.stringify({
3399
+ summary: title,
3400
+ description,
3401
+ start_time: {
3402
+ timestamp: Math.floor(startTime / 1e3).toString(),
3403
+ timezone: "Asia/Shanghai"
3404
+ },
3405
+ end_time: {
3406
+ timestamp: Math.floor(endTime / 1e3).toString(),
3407
+ timezone: "Asia/Shanghai"
3408
+ },
3409
+ attendee_ability: "can_see_others",
3410
+ free_busy_status: "busy"
3411
+ })
3412
+ });
3413
+ const data = await response.json();
3414
+ if (data.code !== 0) {
3415
+ throw new Error(data.msg || "\u521B\u5EFA\u65E5\u7A0B\u5931\u8D25");
3416
+ }
3417
+ const eventLink = data.data?.event_link || "";
3501
3418
  return {
3502
3419
  success: true,
3503
3420
  content: `\u2705 \u65E5\u7A0B\u5DF2\u521B\u5EFA
3504
3421
 
3505
- \u6807\u9898: ${title}
3506
- \u65F6\u95F4: ${startTime}
3507
- \u53C2\u4E0E\u8005: ${attendees.join(", ") || "\u65E0"}`,
3422
+ \u{1F4C5} ${title}
3423
+ \u{1F550} ${this.formatDateTime(startTime)} - ${this.formatDateTime(endTime)}
3424
+
3425
+ \u{1F517} ${eventLink}`,
3508
3426
  actions: [
3509
- { label: "\u67E5\u770B\u65E5\u7A0B", action: "view_calendar" },
3510
- { label: "\u7F16\u8F91", action: "edit_event" }
3427
+ { label: "\u67E5\u770B\u65E5\u7A0B", action: "view_calendar", url: eventLink }
3511
3428
  ]
3512
3429
  };
3513
3430
  } catch (error) {
3514
- return {
3515
- success: false,
3516
- content: `\u274C \u521B\u5EFA\u5931\u8D25: ${error instanceof Error ? error.message : "\u672A\u77E5\u9519\u8BEF"}`
3517
- };
3431
+ return { success: false, content: `\u274C \u521B\u5EFA\u65E5\u7A0B\u5931\u8D25: ${error instanceof Error ? error.message : "\u672A\u77E5\u9519\u8BEF"}` };
3518
3432
  }
3519
3433
  }
3520
3434
  };
3521
3435
  }
3522
- /**
3523
- * 创建文档技能
3524
- */
3525
3436
  createDocSkill() {
3526
3437
  return {
3527
3438
  name: "feishu.createDoc",
3528
3439
  description: "\u521B\u5EFA\u98DE\u4E66\u4E91\u6587\u6863",
3529
- trigger: /创建文档|新建文档/,
3440
+ trigger: /创建文档|新建文档|生成文档/,
3530
3441
  riskLevel: "low",
3531
3442
  examples: [
3532
3443
  "\u521B\u5EFA\u6587\u6863\uFF1A\u9879\u76EE\u9700\u6C42\u6587\u6863",
@@ -3534,89 +3445,114 @@ var FeishuSkills = class {
3534
3445
  ],
3535
3446
  execute: async (context) => {
3536
3447
  try {
3537
- const { title, content, folder } = this.parseDocArgs(context.message);
3448
+ const { title } = this.parseDocArgs(context.message);
3449
+ const token = await this.getAccessToken();
3450
+ const response = await fetch(`${this.baseUrl}/docx/v1/documents`, {
3451
+ method: "POST",
3452
+ headers: {
3453
+ "Authorization": `Bearer ${token}`,
3454
+ "Content-Type": "application/json"
3455
+ },
3456
+ body: JSON.stringify({ title })
3457
+ });
3458
+ const data = await response.json();
3459
+ if (data.code !== 0) {
3460
+ throw new Error(data.msg || "\u521B\u5EFA\u6587\u6863\u5931\u8D25");
3461
+ }
3462
+ const documentId = data.data?.document?.document_id;
3463
+ const domain = ConfigManager.getInstance().getFeishuConfig().domain === "lark" ? "larksuite.com" : "feishu.cn";
3464
+ const documentUrl = `https://${domain}/docx/${documentId}`;
3538
3465
  return {
3539
3466
  success: true,
3540
3467
  content: `\u2705 \u6587\u6863\u5DF2\u521B\u5EFA
3541
3468
 
3542
- \u6807\u9898: ${title}
3543
- \u4F4D\u7F6E: ${folder || "\u6211\u7684\u7A7A\u95F4"}`,
3469
+ \u{1F4C4} ${title}
3470
+
3471
+ \u{1F517} ${documentUrl}`,
3544
3472
  actions: [
3545
- { label: "\u6253\u5F00\u6587\u6863", action: "open_doc" },
3546
- { label: "\u5206\u4EAB", action: "share_doc" }
3473
+ { label: "\u6253\u5F00\u6587\u6863", action: "open_doc", url: documentUrl }
3547
3474
  ]
3548
3475
  };
3549
3476
  } catch (error) {
3550
- return {
3551
- success: false,
3552
- content: `\u274C \u521B\u5EFA\u5931\u8D25: ${error instanceof Error ? error.message : "\u672A\u77E5\u9519\u8BEF"}`
3553
- };
3477
+ return { success: false, content: `\u274C \u521B\u5EFA\u6587\u6863\u5931\u8D25: ${error instanceof Error ? error.message : "\u672A\u77E5\u9519\u8BEF"}` };
3554
3478
  }
3555
3479
  }
3556
3480
  };
3557
3481
  }
3558
- /**
3559
- * 上传文件技能
3560
- */
3561
3482
  uploadFileSkill() {
3562
3483
  return {
3563
3484
  name: "feishu.uploadFile",
3564
3485
  description: "\u4E0A\u4F20\u6587\u4EF6\u5230\u98DE\u4E66",
3565
- trigger: /上传文件|发送文件/,
3486
+ trigger: /上传文件|发送文件|传文件/,
3566
3487
  riskLevel: "low",
3567
3488
  execute: async (context) => {
3568
- return {
3569
- success: true,
3570
- content: "\u{1F4CE} \u6587\u4EF6\u4E0A\u4F20\u529F\u80FD\u5F00\u53D1\u4E2D"
3571
- };
3489
+ return { success: true, content: "\u{1F4CE} \u6587\u4EF6\u4E0A\u4F20\u529F\u80FD\u9700\u8981\u6587\u4EF6\u8DEF\u5F84\uFF0C\u8BF7\u4F7F\u7528\uFF1A\u4E0A\u4F20\u6587\u4EF6 /path/to/file" };
3572
3490
  }
3573
3491
  };
3574
3492
  }
3575
- /**
3576
- * 创建群公告技能
3577
- */
3578
3493
  createAnnouncementSkill() {
3579
3494
  return {
3580
3495
  name: "feishu.createAnnouncement",
3581
3496
  description: "\u53D1\u9001\u7FA4\u516C\u544A",
3582
- trigger: /发送公告|群公告/,
3497
+ trigger: /发送公告|群公告|发布公告|发公告/,
3583
3498
  riskLevel: "medium",
3584
3499
  requireConfirm: true,
3585
3500
  execute: async (context) => {
3586
- return {
3587
- success: true,
3588
- content: "\u{1F4E2} \u516C\u544A\u529F\u80FD\u5F00\u53D1\u4E2D"
3589
- };
3501
+ try {
3502
+ const { title, content } = this.parseAnnouncementArgs(context.message);
3503
+ await this.client.sendMessage(context.chatId, {
3504
+ msg_type: "text",
3505
+ content: { text: `\u{1F4E2} **${title}**
3506
+
3507
+ ${content}` }
3508
+ });
3509
+ return { success: true, content: "\u2705 \u516C\u544A\u5DF2\u53D1\u9001" };
3510
+ } catch (error) {
3511
+ return { success: false, content: `\u274C \u53D1\u5E03\u516C\u544A\u5931\u8D25: ${error instanceof Error ? error.message : "\u672A\u77E5\u9519\u8BEF"}` };
3512
+ }
3590
3513
  }
3591
3514
  };
3592
3515
  }
3593
- // 辅助方法
3594
3516
  parseMessageArgs(message) {
3595
- const match = message.match(/给(.+?)(.+)/);
3596
- if (match) {
3597
- return { target: match[1], content: match[2] };
3598
- }
3517
+ const match = message.match(/给(.+?)[::]\s*(.+)/);
3518
+ if (match) return { target: match[1], content: match[2] };
3599
3519
  return { target: "current", content: message };
3600
3520
  }
3601
3521
  parseEventArgs(message) {
3602
- const titleMatch = message.match(/日程[::]\s*(.+?)(?=\s|$)/);
3603
- const timeMatch = message.match(/(明天|今天|后天|\d{1,2}点|\d{1,2}:\d{2})/);
3604
- return {
3605
- title: titleMatch ? titleMatch[1] : "\u65B0\u65E5\u7A0B",
3606
- startTime: timeMatch ? timeMatch[1] : "\u672A\u6307\u5B9A\u65F6\u95F4",
3607
- attendees: []
3608
- };
3522
+ const now = /* @__PURE__ */ new Date();
3523
+ const titleMatch = message.match(/日程[::]\s*(.+?)(?=(明天|今天|后天|时间|地点|$))/i);
3524
+ const title = titleMatch ? titleMatch[1].trim() : "\u65B0\u65E5\u7A0B";
3525
+ const timeMatch = message.match(/(明天|今天|后天)?\s*(上午|下午|晚上)?\s*(\d{1,2})[:点时]?(\d{0,2})?/);
3526
+ let startTime = new Date(now.getTime() + 60 * 60 * 1e3);
3527
+ if (timeMatch) {
3528
+ const day = timeMatch[1];
3529
+ const period = timeMatch[2];
3530
+ let hour = parseInt(timeMatch[3]);
3531
+ const minute = parseInt(timeMatch[4]) || 0;
3532
+ if (day === "\u660E\u5929") startTime.setDate(startTime.getDate() + 1);
3533
+ else if (day === "\u540E\u5929") startTime.setDate(startTime.getDate() + 2);
3534
+ if (period === "\u4E0B\u5348" && hour < 12) hour += 12;
3535
+ if (period === "\u665A\u4E0A" && hour < 12) hour += 12;
3536
+ startTime.setHours(hour, minute, 0, 0);
3537
+ }
3538
+ const endTime = new Date(startTime.getTime() + 60 * 60 * 1e3);
3539
+ return { title, startTime: startTime.getTime(), endTime: endTime.getTime(), description: "" };
3609
3540
  }
3610
3541
  parseDocArgs(message) {
3611
- const match = message.match(/文档[::]\s*(.+?)(?=\s|$)/);
3612
- return {
3613
- title: match ? match[1] : "\u672A\u547D\u540D\u6587\u6863",
3614
- content: ""
3615
- };
3542
+ const match = message.match(/文档[::]\s*(.+?)(?=(内容|文件夹|$))/i);
3543
+ return { title: match ? match[1].trim() : "\u672A\u547D\u540D\u6587\u6863" };
3544
+ }
3545
+ parseAnnouncementArgs(message) {
3546
+ const titleMatch = message.match(/公告[::]\s*(.+?)(?=内容|$)/i);
3547
+ const title = titleMatch ? titleMatch[1].trim() : "\u7FA4\u516C\u544A";
3548
+ const contentMatch = message.match(/内容[::]\s*(.+)/);
3549
+ const content = contentMatch ? contentMatch[1] : "";
3550
+ return { title, content };
3551
+ }
3552
+ formatDateTime(timestamp) {
3553
+ const date = new Date(timestamp);
3554
+ return `${date.getMonth() + 1}\u6708${date.getDate()}\u65E5 ${date.getHours()}:${date.getMinutes().toString().padStart(2, "0")}`;
3616
3555
  }
3617
- /**
3618
- * 获取所有飞书技能
3619
- */
3620
3556
  getAllSkills() {
3621
3557
  return [
3622
3558
  this.sendMessageSkill(),