@yanhaidao/wecom 2.3.14 → 2.3.141

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yanhaidao/wecom",
3
- "version": "2.3.14",
3
+ "version": "2.3.141",
4
4
  "type": "module",
5
5
  "description": "OpenClaw 企业微信(WeCom)插件,默认 Bot WebSocket,支持加密媒体解密、Agent 主动发消息与多账号接入",
6
6
  "repository": {
@@ -708,7 +708,7 @@ const ctxPayload = core.channel.reply.finalizeInboundContext({
708
708
  ctx: ctxPayload,
709
709
  cfg: config,
710
710
  replyOptions: {
711
- disableBlockStreaming: true,
711
+ disableBlockStreaming: false,
712
712
  },
713
713
  dispatcherOptions: {
714
714
  deliver: async (payload: { text?: string }, info: { kind: string }) => {
@@ -735,9 +735,9 @@ const ctxPayload = core.channel.reply.finalizeInboundContext({
735
735
  touchTransportSession?.({ lastOutboundAt: Date.now(), running: true });
736
736
  log?.(`[wecom-agent] reply chunk delivered (${info.kind}) to ${fromUser}, len=${chunk.length}`);
737
737
 
738
- // 强制延时:确保企业微信有足够时间处理顺序
738
+ // 强制延时:确保企业微信有足够时间处理顺序(优化:200ms → 50ms)
739
739
  if (i + MAX_CHUNK_SIZE < text.length) {
740
- await new Promise(resolve => setTimeout(resolve, 200));
740
+ await new Promise(resolve => setTimeout(resolve, 50));
741
741
  }
742
742
  } catch (err: unknown) {
743
743
  const message = err instanceof Error ? `${err.message}${err.cause ? ` (cause: ${String(err.cause)})` : ""}` : String(err);
@@ -756,9 +756,9 @@ const ctxPayload = core.channel.reply.finalizeInboundContext({
756
756
  }
757
757
  }
758
758
 
759
- // 不同 Block 之间也增加一点间隔
759
+ // 不同 Block 之间也增加一点间隔(优化:200ms → 50ms)
760
760
  if (info.kind !== "final") {
761
- await new Promise(resolve => setTimeout(resolve, 200));
761
+ await new Promise(resolve => setTimeout(resolve, 50));
762
762
  }
763
763
  };
764
764
 
@@ -631,16 +631,108 @@ export class WecomDocClient {
631
631
  return json;
632
632
  }
633
633
 
634
- async editSheetData(params: { agent: ResolvedAgentAccount; docId: string; request: any }) {
635
- const { agent, docId, request } = params;
636
- const body = { docid: readString(docId), ...readObject(request) };
634
+ async editSheetData(params: {
635
+ agent: ResolvedAgentAccount;
636
+ docId: string;
637
+ sheetId: string;
638
+ startRow?: number;
639
+ startColumn?: number;
640
+ gridData?: any;
641
+ }) {
642
+ const { agent, docId, sheetId, startRow = 0, startColumn = 0, gridData } = params;
643
+
644
+ // Validate required docId
645
+ const normalizedDocId = readString(docId);
646
+ if (!normalizedDocId) {
647
+ throw new Error('docId is required');
648
+ }
649
+
650
+ // Validate required sheetId
651
+ const normalizedSheetId = readString(sheetId);
652
+ if (!normalizedSheetId) {
653
+ throw new Error('sheetId is required');
654
+ }
655
+
656
+ // Build GridData per official API
657
+ // gridData.rows[i].values[j] must be: {cell_value: {text} | {link: {text, url}}, cell_format?: {...}}
658
+ const finalGridData = {
659
+ start_row: startRow,
660
+ start_column: startColumn,
661
+ rows: (gridData?.rows || []).map((row: any) => ({
662
+ values: (row.values || []).map((cell: any) => {
663
+ // If already CellData format, use as-is
664
+ if (cell && typeof cell === 'object' && cell.cell_value) {
665
+ return cell;
666
+ }
667
+ // Otherwise wrap primitive as CellValue
668
+ return { cell_value: { text: String(cell ?? '') } };
669
+ })
670
+ }))
671
+ };
672
+
673
+ // Build batch_update request per official API
674
+ const body = {
675
+ docid: normalizedDocId,
676
+ requests: [{
677
+ update_range_request: {
678
+ sheet_id: normalizedSheetId,
679
+ grid_data: finalGridData
680
+ }
681
+ }]
682
+ };
683
+
637
684
  const json = await this.postWecomDocApi({
638
- path: "/cgi-bin/wedoc/spreadsheet/edit_data",
639
- actionLabel: "edit_data",
685
+ path: "/cgi-bin/wedoc/spreadsheet/batch_update",
686
+ actionLabel: "spreadsheet_batch_update",
640
687
  agent, body,
641
688
  });
642
689
  return { raw: json, docId: body.docid as string };
643
690
  }
691
+
692
+ /**
693
+ * Build CellFormat object per official API
694
+ */
695
+ private buildCellFormat(formatData: any): any {
696
+ const textFormat: any = {};
697
+
698
+ // Font properties
699
+ if (formatData.font != null) {
700
+ textFormat.font = String(formatData.font);
701
+ }
702
+ if (formatData.font_size != null) {
703
+ textFormat.font_size = Math.min(72, Math.max(1, Number(formatData.font_size)));
704
+ }
705
+ if (formatData.bold != null) {
706
+ textFormat.bold = Boolean(formatData.bold);
707
+ }
708
+ if (formatData.italic != null) {
709
+ textFormat.italic = Boolean(formatData.italic);
710
+ }
711
+ if (formatData.strikethrough != null) {
712
+ textFormat.strikethrough = Boolean(formatData.strikethrough);
713
+ }
714
+ if (formatData.underline != null) {
715
+ textFormat.underline = Boolean(formatData.underline);
716
+ }
717
+
718
+ // Color (RGBA)
719
+ if (formatData.color != null && typeof formatData.color === "object") {
720
+ const color = formatData.color;
721
+ textFormat.color = {
722
+ red: Math.min(255, Math.max(0, Number(color.red ?? 0))),
723
+ green: Math.min(255, Math.max(0, Number(color.green ?? 0))),
724
+ blue: Math.min(255, Math.max(0, Number(color.blue ?? 0))),
725
+ alpha: Math.min(255, Math.max(0, Number(color.alpha ?? 255)))
726
+ };
727
+ }
728
+
729
+ // Return empty object if no format properties
730
+ if (Object.keys(textFormat).length === 0) {
731
+ return null;
732
+ }
733
+
734
+ return { text_format: textFormat };
735
+ }
644
736
 
645
737
  async getSheetData(params: { agent: ResolvedAgentAccount; docId: string; sheetId: string; range: string }) {
646
738
  const { agent, docId, sheetId, range } = params;
@@ -877,7 +877,7 @@ export const wecomDocToolSchema = {
877
877
  {
878
878
  type: "object",
879
879
  additionalProperties: false,
880
- required: ["action", "docId", "request"],
880
+ required: ["action", "docId", "sheetId", "gridData"],
881
881
  properties: {
882
882
  action: { const: "edit_sheet_data" },
883
883
  accountId: accountIdProperty,
@@ -885,24 +885,146 @@ export const wecomDocToolSchema = {
885
885
  ...docIdProperty,
886
886
  description: "在线表格 docid",
887
887
  },
888
- request: {
888
+ sheetId: {
889
+ type: "string",
890
+ minLength: 1,
891
+ description: "工作表 sheet_id",
892
+ },
893
+ startRow: {
894
+ type: "integer",
895
+ minimum: 0,
896
+ description: "起始行号(从 0 开始)",
897
+ },
898
+ startColumn: {
899
+ type: "integer",
900
+ minimum: 0,
901
+ description: "起始列号(从 0 开始)",
902
+ },
903
+ gridData: {
889
904
  type: "object",
890
- description: "编辑表格请求体,按企业微信官方 edit_data 定义填写",
891
- additionalProperties: true,
892
- required: ["sheet_id", "range", "values"],
905
+ description: "表格数据,按企业微信官方 GridData 定义填写",
906
+ additionalProperties: false,
907
+ required: ["rows"],
893
908
  properties: {
894
- sheet_id: { type: "string" },
895
- range: { type: "string" },
896
- values: {
897
- type: "array",
898
- items: {
899
- type: "array",
900
- items: {
901
- type: "object",
902
- properties: { text: { type: "string" }, url: { type: "string" } }
903
- }
904
- }
905
- }
909
+ startRow: { type: "integer", minimum: 0, description: "起始行号(从 0 开始)" },
910
+ startColumn: { type: "integer", minimum: 0, description: "起始列号(从 0 开始)" },
911
+ rows: {
912
+ type: "array",
913
+ minItems: 1,
914
+ description: "行数据列表",
915
+ items: {
916
+ type: "object",
917
+ additionalProperties: false,
918
+ required: ["values"],
919
+ properties: {
920
+ values: {
921
+ type: "array",
922
+ minItems: 1,
923
+ description: "单元格数据列表(CellData 格式)",
924
+ items: {
925
+ type: "object",
926
+ additionalProperties: false,
927
+ required: ["cell_value"],
928
+ properties: {
929
+ cell_value: {
930
+ type: "object",
931
+ description: "单元格值(text 或 link 二选一)",
932
+ additionalProperties: false,
933
+ oneOf: [
934
+ { required: ["text"], not: { required: ["link"] } },
935
+ { required: ["link"], not: { required: ["text"] } }
936
+ ],
937
+ properties: {
938
+ text: { type: "string", description: "文本内容" },
939
+ link: {
940
+ type: "object",
941
+ description: "超链接内容",
942
+ additionalProperties: false,
943
+ required: ["text", "url"],
944
+ properties: {
945
+ text: { type: "string", description: "链接显示文本" },
946
+ url: { type: "string", description: "链接地址" }
947
+ }
948
+ }
949
+ }
950
+ },
951
+ cell_format: {
952
+ type: "object",
953
+ description: "单元格格式(可选)",
954
+ additionalProperties: false,
955
+ properties: {
956
+ text_format: {
957
+ type: "object",
958
+ description: "文本格式",
959
+ additionalProperties: false,
960
+ properties: {
961
+ font: {
962
+ type: "string",
963
+ description: "字体名称(Microsoft YaHei, SimSun, Arial 等)"
964
+ },
965
+ font_size: {
966
+ type: "integer",
967
+ minimum: 1,
968
+ maximum: 72,
969
+ description: "字体大小(最大 72)"
970
+ },
971
+ bold: {
972
+ type: "boolean",
973
+ description: "加粗"
974
+ },
975
+ italic: {
976
+ type: "boolean",
977
+ description: "斜体"
978
+ },
979
+ strikethrough: {
980
+ type: "boolean",
981
+ description: "删除线"
982
+ },
983
+ underline: {
984
+ type: "boolean",
985
+ description: "下划线"
986
+ },
987
+ color: {
988
+ type: "object",
989
+ description: "字体颜色(RGBA)",
990
+ additionalProperties: false,
991
+ properties: {
992
+ red: {
993
+ type: "integer",
994
+ minimum: 0,
995
+ maximum: 255,
996
+ description: "红色通道"
997
+ },
998
+ green: {
999
+ type: "integer",
1000
+ minimum: 0,
1001
+ maximum: 255,
1002
+ description: "绿色通道"
1003
+ },
1004
+ blue: {
1005
+ type: "integer",
1006
+ minimum: 0,
1007
+ maximum: 255,
1008
+ description: "蓝色通道"
1009
+ },
1010
+ alpha: {
1011
+ type: "integer",
1012
+ minimum: 0,
1013
+ maximum: 255,
1014
+ description: "透明度(255 完全不透明)"
1015
+ }
1016
+ }
1017
+ }
1018
+ }
1019
+ }
1020
+ }
1021
+ }
1022
+ }
1023
+ }
1024
+ }
1025
+ }
1026
+ }
1027
+ }
906
1028
  }
907
1029
  },
908
1030
  },
@@ -930,34 +1052,8 @@ export const wecomDocToolSchema = {
930
1052
  },
931
1053
  },
932
1054
  },
933
- {
934
- type: "object",
935
- additionalProperties: false,
936
- required: ["action", "docId", "requests"],
937
- properties: {
938
- action: { const: "modify_sheet_properties" },
939
- accountId: accountIdProperty,
940
- docId: {
941
- ...docIdProperty,
942
- description: "在线表格 docid",
943
- },
944
- requests: {
945
- type: "array",
946
- minItems: 1,
947
- maxItems: 5,
948
- description: "修改属性请求列表,必须遵循企业微信 modify_sheet_properties 定义",
949
- items: {
950
- type: "object",
951
- oneOf: [
952
- { required: ["add_sheet_request"], properties: { add_sheet_request: addSheetRequest } },
953
- { required: ["update_range_request"], properties: { update_range_request: updateRangeRequest } },
954
- { required: ["delete_dimension_request"], properties: { delete_dimension_request: deleteDimensionRequest } },
955
- { required: ["delete_sheet_request"], properties: { delete_sheet_request: deleteSheetRequest } }
956
- ]
957
- }
958
- },
959
- },
960
- },
1055
+ // Note: batch_update is the underlying API, but users should use edit_sheet_data action instead
1056
+ // The edit_sheet_data action handles conversion to batch_update format internally
961
1057
  {
962
1058
  type: "object",
963
1059
  additionalProperties: false,
@@ -909,7 +909,10 @@ export function registerWecomDocTools(api: OpenClawPluginApi) {
909
909
  const result = await docClient.editSheetData({
910
910
  agent: account,
911
911
  docId: params.docId,
912
- request: params.request,
912
+ sheetId: params.sheetId,
913
+ startRow: params.startRow ?? 0,
914
+ startColumn: params.startColumn ?? 0,
915
+ gridData: params.gridData,
913
916
  });
914
917
  return buildToolResult({
915
918
  ok: true,