@openclaw/msteams 2026.9.3 → 2026.9.5

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 (38) hide show
  1. package/assets/activity.svg +40 -0
  2. package/assets/icon.png +0 -0
  3. package/dist/{adapter.runtime-DDuc7sKJ.cjs → .setup/adapter.runtime-ChuVK6k_.cjs} +3 -3
  4. package/dist/{approval-handler.runtime-CoTQG4FS.cjs → .setup/approval-handler.runtime-DDxGPJDz.cjs} +3 -3
  5. package/dist/{channel-Cdm6-HsU.cjs → .setup/channel-Dzpbbht8.cjs} +63 -35
  6. package/dist/{channel.runtime-__5ZQlfG.cjs → .setup/channel.runtime-TE49QvFv.cjs} +57 -32
  7. package/dist/{channel.setup-ChwkwdLk.cjs → .setup/channel.setup-BVDfgdCc.cjs} +17 -25
  8. package/dist/{delegated-state-DiEz9JIa.cjs → .setup/delegated-state-u-ywZyZT.cjs} +5 -5
  9. package/dist/{messenger-DbWgzI01.cjs → .setup/messenger-BR1l4zw-.cjs} +108 -178
  10. package/dist/{oauth-BeROaYf0.cjs → .setup/oauth-C6m7dvHj.cjs} +1 -1
  11. package/dist/{polls-BBdZPx_R.cjs → .setup/polls-BJ4-4uZm.cjs} +14 -7
  12. package/dist/{reaction-types-zP91Ncwk.cjs → .setup/reaction-types-C7RA7Wxt.cjs} +1 -1
  13. package/dist/{resolve-allowlist-CoKmLXYe.cjs → .setup/resolve-allowlist-CHzaaWiC.cjs} +141 -93
  14. package/dist/.setup/secret-contract-api-ChQdBeU1.cjs +4 -0
  15. package/dist/.setup/secret-contract-api-ipiUsANg.cjs +28 -0
  16. package/dist/{send-Bw4W8RO7.cjs → .setup/send-D8ATH4QI.cjs} +95 -33
  17. package/dist/.setup/setup-plugin-api-DpiaA8z1.cjs +3 -0
  18. package/dist/{src-B--Qc6lj.cjs → .setup/src-CpKfpP1m.cjs} +134 -58
  19. package/dist/{sso-token-store-DTeYxubp.cjs → .setup/sso-token-store-YYLHXgFH.cjs} +1 -1
  20. package/dist/{thread-session-p8FNgohv.cjs → .setup/thread-session-CXgHK-yi.cjs} +1 -1
  21. package/dist/api.cjs +2 -2
  22. package/dist/channel-config-api.cjs +1 -1
  23. package/dist/channel-plugin-api.cjs +1 -1
  24. package/dist/configured-state.cjs +1 -1
  25. package/dist/directory-contract-api.cjs +1 -1
  26. package/dist/doctor-contract-api.cjs +64 -62
  27. package/dist/qa-runner-api.cjs +1 -1
  28. package/dist/runtime-api.cjs +1 -1
  29. package/dist/secret-contract-api.cjs +4 -13
  30. package/dist/setup-entry.cjs +5 -3
  31. package/dist/setup-plugin-api.cjs +1 -1
  32. package/openclaw.plugin.json +4 -1
  33. package/package.json +14 -11
  34. /package/dist/{approval-card-CPNH_q3P.cjs → .setup/approval-card-CPNH_q3P.cjs} +0 -0
  35. /package/dist/{config-schema-D22Lr1Qk.cjs → .setup/config-schema-D22Lr1Qk.cjs} +0 -0
  36. /package/dist/{rolldown-runtime-VH7oDXx4.cjs → .setup/rolldown-runtime-VH7oDXx4.cjs} +0 -0
  37. /package/dist/{runtime-gZTAuFux.cjs → .setup/runtime-gZTAuFux.cjs} +0 -0
  38. /package/dist/{secret-input-C65t6kjM.cjs → .setup/secret-input-C65t6kjM.cjs} +0 -0
@@ -1,26 +1,30 @@
1
1
  const require_rolldown_runtime = require("./rolldown-runtime-VH7oDXx4.cjs");
2
2
  const require_runtime = require("./runtime-gZTAuFux.cjs");
3
- require("./runtime-api.cjs");
4
- const require_resolve_allowlist = require("./resolve-allowlist-CoKmLXYe.cjs");
5
- const require_channel_setup = require("./channel.setup-ChwkwdLk.cjs");
6
- const require_polls = require("./polls-BBdZPx_R.cjs");
3
+ require("../runtime-api.cjs");
4
+ const require_resolve_allowlist = require("./resolve-allowlist-CHzaaWiC.cjs");
5
+ const require_channel_setup = require("./channel.setup-BVDfgdCc.cjs");
6
+ const require_polls = require("./polls-BJ4-4uZm.cjs");
7
7
  let openclaw_plugin_sdk_lazy_runtime = require("openclaw/plugin-sdk/lazy-runtime");
8
8
  let openclaw_plugin_sdk_string_coerce_runtime = require("openclaw/plugin-sdk/string-coerce-runtime");
9
+ let openclaw_plugin_sdk_fetch_runtime = require("openclaw/plugin-sdk/fetch-runtime");
9
10
  let openclaw_plugin_sdk_provider_http = require("openclaw/plugin-sdk/provider-http");
10
11
  let openclaw_plugin_sdk_reply_payload = require("openclaw/plugin-sdk/reply-payload");
12
+ let openclaw_plugin_sdk_ssrf_runtime = require("openclaw/plugin-sdk/ssrf-runtime");
11
13
  let openclaw_plugin_sdk_text_chunking = require("openclaw/plugin-sdk/text-chunking");
12
14
  let node_dns_promises = require("node:dns/promises");
13
15
  let openclaw_plugin_sdk_ssrf_policy = require("openclaw/plugin-sdk/ssrf-policy");
14
16
  let openclaw_plugin_sdk_text_utility_runtime = require("openclaw/plugin-sdk/text-utility-runtime");
17
+ let openclaw_plugin_sdk_error_runtime = require("openclaw/plugin-sdk/error-runtime");
15
18
  let openclaw_plugin_sdk_retry_runtime = require("openclaw/plugin-sdk/retry-runtime");
16
19
  let node_crypto = require("node:crypto");
17
20
  node_crypto = require_rolldown_runtime.__toESM(node_crypto, 1);
18
21
  let node_path = require("node:path");
19
22
  node_path = require_rolldown_runtime.__toESM(node_path, 1);
20
23
  let openclaw_plugin_sdk_runtime_env = require("openclaw/plugin-sdk/runtime-env");
24
+ let openclaw_plugin_sdk_markdown_table_runtime = require("openclaw/plugin-sdk/markdown-table-runtime");
21
25
  let openclaw_plugin_sdk_blob_runtime = require("openclaw/plugin-sdk/blob-runtime");
22
26
  let openclaw_plugin_sdk_global_singleton = require("openclaw/plugin-sdk/global-singleton");
23
- let openclaw_plugin_sdk_error_runtime = require("openclaw/plugin-sdk/error-runtime");
27
+ let openclaw_plugin_sdk_expect_runtime = require("openclaw/plugin-sdk/expect-runtime");
24
28
  let openclaw_plugin_sdk_reply_chunking = require("openclaw/plugin-sdk/reply-chunking");
25
29
  let openclaw_plugin_sdk_web_media = require("openclaw/plugin-sdk/web-media");
26
30
  let openclaw_plugin_sdk_media_runtime = require("openclaw/plugin-sdk/media-runtime");
@@ -635,6 +639,7 @@ function serializeMarkdownDestination(href) {
635
639
  return `<${href.replace(/([\\<>])/gu, "\\$1")}>`;
636
640
  }
637
641
  function blankBlockEnd(text, index) {
642
+ if (text[index] !== "\n" && text[index] !== "\r") return;
638
643
  const match = /^(?:\r?\n)[ \t]*(?:\r?\n)/u.exec(text.slice(index));
639
644
  return match ? index + match[0].length : void 0;
640
645
  }
@@ -692,136 +697,25 @@ function protectDelimitedMarkdown(text, opener, tokenPrefix, values) {
692
697
  }
693
698
  return protectedText + text.slice(cursor);
694
699
  }
695
- function parseQuotePrefix(line) {
696
- let cursor = 0;
697
- let depth = 0;
698
- while (cursor < line.length) {
699
- const checkpoint = cursor;
700
- let spaces = 0;
701
- while (spaces < 3 && line[cursor] === " ") {
702
- cursor += 1;
703
- spaces += 1;
704
- }
705
- if (line[cursor] !== ">") {
706
- cursor = checkpoint;
707
- break;
708
- }
709
- cursor += 1;
710
- depth += 1;
711
- if (line[cursor] === " " || line[cursor] === " ") cursor += 1;
712
- }
713
- return {
714
- content: line.slice(cursor).replace(/\r$/u, ""),
715
- depth,
716
- prefix: line.slice(0, cursor)
717
- };
718
- }
719
- function isTableDelimiterLine(content) {
720
- const cells = content.trim().replace(/^\|/u, "").replace(/\|$/u, "").split("|").map((cell) => cell.trim());
721
- return cells.length > 0 && cells.every((cell) => /^:?-+:?$/u.test(cell));
722
- }
723
- function protectRawTablesInSegment(text, tokenPrefix, rawTables) {
724
- const lines = text.split("\n");
725
- const output = [];
726
- for (let index = 0; index < lines.length;) {
727
- const line = lines[index] ?? "";
728
- const header = parseQuotePrefix(line);
729
- const delimiter = parseQuotePrefix(lines[index + 1] ?? "");
730
- if (header.content.includes("|") && delimiter.depth === header.depth && isTableDelimiterLine(delimiter.content)) {
731
- let end = index + 2;
732
- while (end < lines.length) {
733
- const row = parseQuotePrefix(lines[end] ?? "");
734
- if (row.depth !== header.depth || !row.content.trim() || isInterruptingBlock(lines[end] ?? "")) break;
735
- end += 1;
736
- }
737
- const table = lines.slice(index, end).join("\n");
738
- if ((0, openclaw_plugin_sdk_text_chunking.convertMarkdownTables)(table, "code") !== table) {
739
- const tableIndex = rawTables.push(table.slice(header.prefix.length)) - 1;
740
- output.push(`${header.prefix}${tokenPrefix}t${tableIndex}${TOKEN_END}`);
741
- index = end;
742
- continue;
743
- }
744
- for (let lineIndex = index; lineIndex < end; lineIndex += 1) output.push(lines[lineIndex] ?? "");
745
- index = end;
746
- continue;
747
- }
748
- output.push(line);
749
- index += 1;
750
- }
751
- return output.join("\n");
752
- }
753
- function isInterruptingBlock(line) {
754
- const content = parseQuotePrefix(line).content;
755
- return /^[ \t]{0,3}(?:#{1,6}(?:[ \t]|$)|`{3,}|~{3,}|(?:[-+*]|\d+[.)])[ \t]+)/u.test(content);
756
- }
757
- function leadingQuoteDepth(line) {
758
- return parseQuotePrefix(line).depth;
759
- }
760
- function parseFenceLine(line) {
761
- const match = /^((?: {0,3}>[ \t]?)*)(?:((?:[-+*]|\d+[.)])[ \t]+))?( {0,3})(`{3,}|~{3,})(.*)$/u.exec(line);
762
- const marker = match?.[4];
763
- const trailing = match?.[5] ?? "";
764
- if (!marker || marker.startsWith("`") && trailing.includes("`")) return;
765
- return {
766
- marker,
767
- quoteDepth: match?.[1]?.match(/>/gu)?.length ?? 0,
768
- trailing,
769
- listIndent: match?.[2]?.length ?? 0,
770
- indent: match?.[3]?.length ?? 0
771
- };
772
- }
773
- function protectRawTablesOutsideFences(text, tokenPrefix, rawTables) {
700
+ function protectRawTables(text, tokenPrefix, rawTables) {
701
+ if (!text.includes("|")) return text;
702
+ const { tables } = (0, openclaw_plugin_sdk_text_chunking.markdownToIRWithMeta)(text, {
703
+ autolink: false,
704
+ linkify: false,
705
+ tableMode: "block"
706
+ });
774
707
  let result = "";
775
- let outsideStart = 0;
776
- let fenceStart;
777
- let active;
778
- let listContextIndent = 0;
779
- let offset = 0;
780
- while (offset <= text.length) {
781
- const nextNewline = text.indexOf("\n", offset);
782
- const lineEnd = nextNewline < 0 ? text.length : nextNewline;
783
- const line = text.slice(offset, lineEnd).replace(/\r$/u, "");
784
- let fence = parseFenceLine(line);
785
- const lineQuoteDepth = leadingQuoteDepth(line);
786
- const lineWithoutQuotes = line.replace(/^(?:[ \t]*>[ \t]?)+/u, "");
787
- const lineIndent = /^[ \t]*/u.exec(lineWithoutQuotes)?.[0].length ?? 0;
788
- const listMarkerIndent = /^((?:[-+*]|\d+[.)])[ \t]+)/u.exec(lineWithoutQuotes)?.[1]?.length;
789
- if (listMarkerIndent) listContextIndent = listMarkerIndent;
790
- else if (line.trim() && lineIndent < listContextIndent && !fence) listContextIndent = 0;
791
- if (fence && fence.listIndent === 0 && listContextIndent > 0 && fence.indent >= listContextIndent) fence = {
792
- ...fence,
793
- listIndent: listContextIndent
794
- };
795
- const listOutdented = Boolean(active?.listIndent && line.trim() && lineIndent < active.listIndent && !fence);
796
- if (active && (active.quoteDepth > lineQuoteDepth || listOutdented)) {
797
- result += text.slice(fenceStart, offset);
798
- outsideStart = offset;
799
- active = void 0;
800
- fenceStart = void 0;
801
- }
802
- if (!active && fence) {
803
- result += protectRawTablesInSegment(text.slice(outsideStart, offset), tokenPrefix, rawTables);
804
- fenceStart = offset;
805
- active = {
806
- marker: fence.marker,
807
- quoteDepth: fence.quoteDepth,
808
- listIndent: fence.listIndent
809
- };
810
- } else if (active && fence && fence.marker[0] === active.marker[0] && fence.marker.length >= active.marker.length && fence.quoteDepth === active.quoteDepth && /^[ \t]*$/u.test(fence.trailing)) {
811
- const fenceEnd = nextNewline < 0 ? lineEnd : nextNewline + 1;
812
- result += text.slice(fenceStart, fenceEnd);
813
- outsideStart = fenceEnd;
814
- active = void 0;
815
- fenceStart = void 0;
816
- }
817
- if (nextNewline < 0) break;
818
- offset = nextNewline + 1;
819
- }
820
- if (active && fenceStart !== void 0) {
821
- result += text.slice(fenceStart);
822
- return result;
708
+ let cursor = 0;
709
+ for (const table of tables) {
710
+ const source = (0, openclaw_plugin_sdk_expect_runtime.expectDefined)((0, openclaw_plugin_sdk_markdown_table_runtime.getMarkdownTableSource)(table), "Markdown table source");
711
+ const lineStart = Math.max(text.lastIndexOf("\n", source.start - 1), text.lastIndexOf("\r", source.start - 1)) + 1;
712
+ const start = lineStart + (/^(?: {0,3}>[ \t]?)*/u.exec(text.slice(lineStart, source.start))?.[0] ?? "").length;
713
+ const end = source.end + (text.slice(source.end, source.end + 2) === "\r\n" ? 1 : 0);
714
+ const index = rawTables.push(text.slice(start, end)) - 1;
715
+ result += text.slice(cursor, start) + `${tokenPrefix}t${index}${TOKEN_END}`;
716
+ cursor = end;
823
717
  }
824
- return result + protectRawTablesInSegment(text.slice(outsideStart), tokenPrefix, rawTables);
718
+ return result + text.slice(cursor);
825
719
  }
826
720
  function protectMSTeamsCode(ir, tokenPrefix, code, protectedValues) {
827
721
  const codeSpans = ir.styles.filter((span) => span.style === "code" || span.style === "code_block");
@@ -877,7 +771,7 @@ function formatMSTeamsMarkdown(markdown, tableMode) {
877
771
  return `${tokenPrefix}h${index}${TOKEN_END}`;
878
772
  }), "![", `${tokenPrefix}i`, images), "@[", `${tokenPrefix}m`, mentions);
879
773
  const tableInput = (0, openclaw_plugin_sdk_text_chunking.convertMarkdownTables)(mentionsProtected, tableMode);
880
- const protectedMarkdown = (tableMode === "off" ? protectRawTablesOutsideFences(tableInput, tokenPrefix, rawTables) : tableInput).replace(ESCAPED_MARKDOWN_RE, (escaped) => {
774
+ const protectedMarkdown = (tableMode === "off" ? protectRawTables(tableInput, tokenPrefix, rawTables) : tableInput).replace(ESCAPED_MARKDOWN_RE, (escaped) => {
881
775
  const index = escapedMarkdown.push(escaped) - 1;
882
776
  return `${tokenPrefix}e${index}${TOKEN_END}`;
883
777
  });
@@ -957,6 +851,19 @@ function buildTeamsFileInfoCard(file) {
957
851
  const GRAPH_ROOT = "https://graph.microsoft.com/v1.0";
958
852
  const GRAPH_BETA = "https://graph.microsoft.com/beta";
959
853
  const GRAPH_SCOPE = "https://graph.microsoft.com";
854
+ async function requestSharePoint(url, init, params) {
855
+ const { response, release } = await (0, openclaw_plugin_sdk_ssrf_runtime.fetchWithSsrFGuard)({
856
+ url,
857
+ init,
858
+ fetchImpl: params.fetchFn,
859
+ mode: "trusted_env_proxy",
860
+ beforeRequest: () => require_resolve_allowlist.assertMSTeamsSendHandoff(params),
861
+ maxRedirects: 20,
862
+ allowCrossOriginUnsafeRedirectReplay: true,
863
+ auditContext: "msteams.graph-upload"
864
+ });
865
+ return (0, openclaw_plugin_sdk_fetch_runtime.responseWithRelease)(response, release);
866
+ }
960
867
  function requireMSTeamsSharePointSiteId(siteId) {
961
868
  const normalized = siteId?.trim();
962
869
  if (!normalized) throw new Error("channels.msteams.sharePointSiteId is required to send files to group chats or channels");
@@ -978,7 +885,6 @@ async function getGraphAccessToken(tokenProvider) {
978
885
  * @param params.siteId - SharePoint site ID (e.g., "contoso.sharepoint.com,guid1,guid2")
979
886
  */
980
887
  async function uploadToSharePoint(params) {
981
- const fetchFn = params.fetchFn ?? fetch;
982
888
  const uploadPath = `/OpenClawShared/${encodeURIComponent(params.filename)}`;
983
889
  const uploadUrl = `${GRAPH_ROOT}/sites/${params.siteId}/drive/root:${uploadPath}:/content?@microsoft.graph.conflictBehavior=rename`;
984
890
  const timeoutMs = require_resolve_allowlist.resolveMSTeamsSharePointUploadTimeoutMs(params.buffer.length);
@@ -986,8 +892,10 @@ async function uploadToSharePoint(params) {
986
892
  label: SHAREPOINT_UPLOAD_TIMEOUT_LABEL,
987
893
  timeoutMs,
988
894
  work: async (signal) => {
895
+ require_resolve_allowlist.assertMSTeamsSendHandoff(params);
989
896
  const token = await getGraphAccessToken(params.tokenProvider);
990
- const res = await fetchFn(uploadUrl, {
897
+ require_resolve_allowlist.assertMSTeamsSendHandoff(params);
898
+ const res = await requestSharePoint(uploadUrl, {
991
899
  method: "PUT",
992
900
  headers: {
993
901
  "User-Agent": require_resolve_allowlist.buildUserAgent(),
@@ -996,7 +904,7 @@ async function uploadToSharePoint(params) {
996
904
  },
997
905
  body: new Blob([(0, openclaw_plugin_sdk_blob_runtime.bufferToBlobPart)(params.buffer)]),
998
906
  signal
999
- });
907
+ }, params);
1000
908
  if (!res.ok) throw await require_resolve_allowlist.createMSTeamsHttpError(res, "SharePoint upload failed");
1001
909
  return await (0, openclaw_plugin_sdk_provider_http.readProviderJsonResponse)(res, "msteams.graph-upload.uploadSharePointFile", { chunkTimeoutMs: timeoutMs });
1002
910
  }
@@ -1016,18 +924,19 @@ async function uploadToSharePoint(params) {
1016
924
  * @param params.itemId - The driveItem ID (returned from upload)
1017
925
  */
1018
926
  async function getDriveItemProperties(params) {
1019
- const fetchFn = params.fetchFn ?? fetch;
1020
927
  const data = await require_resolve_allowlist.withMSTeamsAbortableRequestTimeout({
1021
928
  label: SHAREPOINT_REQUEST_TIMEOUT_LABEL,
1022
929
  work: async (signal) => {
930
+ require_resolve_allowlist.assertMSTeamsSendHandoff(params);
1023
931
  const token = await getGraphAccessToken(params.tokenProvider);
1024
- const res = await fetchFn(`${GRAPH_ROOT}/sites/${params.siteId}/drive/items/${params.itemId}?$select=eTag,webDavUrl,name`, {
932
+ require_resolve_allowlist.assertMSTeamsSendHandoff(params);
933
+ const res = await requestSharePoint(`${GRAPH_ROOT}/sites/${params.siteId}/drive/items/${params.itemId}?$select=eTag,webDavUrl,name`, {
1025
934
  headers: {
1026
935
  "User-Agent": require_resolve_allowlist.buildUserAgent(),
1027
936
  Authorization: `Bearer ${token}`
1028
937
  },
1029
938
  signal
1030
- });
939
+ }, params);
1031
940
  if (!res.ok) throw await require_resolve_allowlist.createMSTeamsHttpError(res, "Get driveItem properties failed");
1032
941
  return await (0, openclaw_plugin_sdk_provider_http.readProviderJsonResponse)(res, "msteams.graph-upload.getDriveItemProperties");
1033
942
  }
@@ -1044,18 +953,19 @@ async function getDriveItemProperties(params) {
1044
953
  * Used to create sharing links scoped to only the chat participants.
1045
954
  */
1046
955
  async function getChatMembers(params) {
1047
- const fetchFn = params.fetchFn ?? fetch;
1048
956
  return await require_resolve_allowlist.withMSTeamsAbortableRequestTimeout({
1049
957
  label: SHAREPOINT_REQUEST_TIMEOUT_LABEL,
1050
958
  work: async (signal) => {
959
+ require_resolve_allowlist.assertMSTeamsSendHandoff(params);
1051
960
  const token = await getGraphAccessToken(params.tokenProvider);
1052
- const res = await fetchFn(`${GRAPH_ROOT}/chats/${params.chatId}/members`, {
961
+ require_resolve_allowlist.assertMSTeamsSendHandoff(params);
962
+ const res = await requestSharePoint(`${GRAPH_ROOT}/chats/${params.chatId}/members`, {
1053
963
  headers: {
1054
964
  "User-Agent": require_resolve_allowlist.buildUserAgent(),
1055
965
  Authorization: `Bearer ${token}`
1056
966
  },
1057
967
  signal
1058
- });
968
+ }, params);
1059
969
  if (!res.ok) {
1060
970
  const message = res.status === 403 ? "Get chat members failed; verify Graph chat-member permissions and tenant access policies" : "Get chat members failed";
1061
971
  throw await require_resolve_allowlist.createMSTeamsHttpError(res, message);
@@ -1070,7 +980,6 @@ async function getChatMembers(params) {
1070
980
  * For per-user scope, uses beta API with recipients.
1071
981
  */
1072
982
  async function createSharePointSharingLink(params) {
1073
- const fetchFn = params.fetchFn ?? fetch;
1074
983
  const scope = params.scope ?? "organization";
1075
984
  const apiRoot = scope === "users" ? GRAPH_BETA : GRAPH_ROOT;
1076
985
  const body = {
@@ -1081,8 +990,10 @@ async function createSharePointSharingLink(params) {
1081
990
  const data = await require_resolve_allowlist.withMSTeamsAbortableRequestTimeout({
1082
991
  label: SHAREPOINT_REQUEST_TIMEOUT_LABEL,
1083
992
  work: async (signal) => {
993
+ require_resolve_allowlist.assertMSTeamsSendHandoff(params);
1084
994
  const token = await getGraphAccessToken(params.tokenProvider);
1085
- const res = await fetchFn(`${apiRoot}/sites/${params.siteId}/drive/items/${params.itemId}/createLink`, {
995
+ require_resolve_allowlist.assertMSTeamsSendHandoff(params);
996
+ const res = await requestSharePoint(`${apiRoot}/sites/${params.siteId}/drive/items/${params.itemId}/createLink`, {
1086
997
  method: "POST",
1087
998
  headers: {
1088
999
  "User-Agent": require_resolve_allowlist.buildUserAgent(),
@@ -1091,7 +1002,7 @@ async function createSharePointSharingLink(params) {
1091
1002
  },
1092
1003
  body: JSON.stringify(body),
1093
1004
  signal
1094
- });
1005
+ }, params);
1095
1006
  if (!res.ok) throw await require_resolve_allowlist.createMSTeamsHttpError(res, "Create SharePoint sharing link failed");
1096
1007
  return await (0, openclaw_plugin_sdk_provider_http.readProviderJsonResponse)(res, "msteams.graph-upload.createSharePointSharingLink");
1097
1008
  }
@@ -1116,7 +1027,8 @@ async function uploadAndShareSharePoint(params) {
1116
1027
  contentType: params.contentType,
1117
1028
  tokenProvider: params.tokenProvider,
1118
1029
  siteId: params.siteId,
1119
- fetchFn: params.fetchFn
1030
+ fetchFn: params.fetchFn,
1031
+ assertDirectAdapterHandoff: params.assertDirectAdapterHandoff
1120
1032
  });
1121
1033
  let scope = "organization";
1122
1034
  let recipientObjectIds;
@@ -1124,7 +1036,8 @@ async function uploadAndShareSharePoint(params) {
1124
1036
  const members = await getChatMembers({
1125
1037
  chatId: params.chatId,
1126
1038
  tokenProvider: params.tokenProvider,
1127
- fetchFn: params.fetchFn
1039
+ fetchFn: params.fetchFn,
1040
+ assertDirectAdapterHandoff: params.assertDirectAdapterHandoff
1128
1041
  });
1129
1042
  if (members.length === 0) throw new Error("MS Teams chat member lookup returned no recipients");
1130
1043
  scope = "users";
@@ -1136,7 +1049,8 @@ async function uploadAndShareSharePoint(params) {
1136
1049
  tokenProvider: params.tokenProvider,
1137
1050
  scope,
1138
1051
  recipientObjectIds,
1139
- fetchFn: params.fetchFn
1052
+ fetchFn: params.fetchFn,
1053
+ assertDirectAdapterHandoff: params.assertDirectAdapterHandoff
1140
1054
  });
1141
1055
  return {
1142
1056
  itemId: uploaded.id,
@@ -1236,13 +1150,13 @@ function isValidTeamsId(id) {
1236
1150
  * Returns both the formatted text with <at> tags and the entities array.
1237
1151
  */
1238
1152
  function parseMentions(text) {
1239
- const mentionPattern = /@\[([^\]]+)\]\(([^)]+)\)/g;
1153
+ const mentionPattern = /@\[((?:\\[\s\S]|[^\]\\])+)\]\(([^)]+)\)/g;
1240
1154
  const entities = [];
1241
1155
  return {
1242
1156
  text: text.replace(mentionPattern, (match, name, id) => {
1243
1157
  const trimmedId = id.trim();
1244
1158
  if (!isValidTeamsId(trimmedId)) return match;
1245
- const trimmedName = name.trim();
1159
+ const trimmedName = name.replace(/\\([\\[\]])/g, "$1").trim();
1246
1160
  const mentionTag = `<at>${trimmedName}</at>`;
1247
1161
  entities.push({
1248
1162
  type: "mention",
@@ -1390,24 +1304,28 @@ function mergeReferenceIntoActivity(activity, ref) {
1390
1304
  };
1391
1305
  }
1392
1306
  async function sendMSTeamsActivityWithReference(app, source, activity, options) {
1393
- const ref = buildSdkConversationReference(source, options);
1394
- const activities = (await getApiClientForReference(app, ref)).conversations.activities(ref.conversation.id);
1395
- const activityWithRef = mergeReferenceIntoActivity(options?.quoteActivityId ? await quoteMSTeamsActivity(activity, options.quoteActivityId) : activity, ref);
1396
- const isTargeted = activityWithRef.recipient?.isTargeted === true;
1397
- if (isTargeted && ref.conversation.conversationType === "personal") throw new Error("Targeted messages are not supported in 1:1 (personal) chats.");
1398
- const activityId = typeof activityWithRef.id === "string" ? activityWithRef.id : void 0;
1399
- if (activityId) {
1400
- const res = isTargeted && activities.updateTargeted ? await activities.updateTargeted(activityId, activityWithRef) : await activities.update(activityId, activityWithRef);
1307
+ return require_resolve_allowlist.withMSTeamsConnectorHandoff(options ?? {}, async (handoff) => {
1308
+ require_resolve_allowlist.assertMSTeamsSendHandoff(handoff);
1309
+ const ref = buildSdkConversationReference(source, options);
1310
+ const activities = (await getApiClientForReference(app, ref)).conversations.activities(ref.conversation.id);
1311
+ const activityWithRef = mergeReferenceIntoActivity(options?.quoteActivityId ? await quoteMSTeamsActivity(activity, options.quoteActivityId) : activity, ref);
1312
+ const isTargeted = activityWithRef.recipient?.isTargeted === true;
1313
+ if (isTargeted && ref.conversation.conversationType === "personal") throw new Error("Targeted messages are not supported in 1:1 (personal) chats.");
1314
+ const activityId = typeof activityWithRef.id === "string" ? activityWithRef.id : void 0;
1315
+ require_resolve_allowlist.assertMSTeamsSendHandoff(handoff);
1316
+ if (activityId) {
1317
+ const res = isTargeted && activities.updateTargeted ? await activities.updateTargeted(activityId, activityWithRef) : await activities.update(activityId, activityWithRef);
1318
+ return {
1319
+ ...activityWithRef,
1320
+ ...res && typeof res === "object" ? res : {}
1321
+ };
1322
+ }
1323
+ const res = isTargeted && activities.createTargeted ? await activities.createTargeted(activityWithRef) : await activities.create(activityWithRef);
1401
1324
  return {
1402
1325
  ...activityWithRef,
1403
- ...res && typeof res === "object" ? res : {}
1326
+ ...res
1404
1327
  };
1405
- }
1406
- const res = isTargeted && activities.createTargeted ? await activities.createTargeted(activityWithRef) : await activities.create(activityWithRef);
1407
- return {
1408
- ...activityWithRef,
1409
- ...res
1410
- };
1328
+ });
1411
1329
  }
1412
1330
  async function updateMSTeamsActivityWithReference(app, source, activityId, activity, options) {
1413
1331
  const ref = buildSdkConversationReference(source, options);
@@ -1566,6 +1484,7 @@ async function buildActivity(msg, conversationRef, tokenProvider, sharePointSite
1566
1484
  thresholdBytes: FILE_CONSENT_THRESHOLD_BYTES
1567
1485
  })) {
1568
1486
  const conversationId = conversationRef.conversation?.id ?? "unknown";
1487
+ require_resolve_allowlist.assertMSTeamsSendHandoff(options);
1569
1488
  const { activity: consentActivity, uploadId } = prepareFileConsentActivity({
1570
1489
  media: {
1571
1490
  buffer: media.buffer,
@@ -1582,17 +1501,20 @@ async function buildActivity(msg, conversationRef, tokenProvider, sharePointSite
1582
1501
  const siteId = requireMSTeamsSharePointSiteId(sharePointSiteId);
1583
1502
  if (!tokenProvider) throw new Error("MS Teams Graph token provider unavailable for SharePoint file send");
1584
1503
  const chatId = conversationRef.conversation?.id;
1504
+ const uploaded = await uploadAndShareSharePoint({
1505
+ assertDirectAdapterHandoff: options?.assertDirectAdapterHandoff,
1506
+ buffer: media.buffer,
1507
+ filename: fileName,
1508
+ contentType,
1509
+ tokenProvider,
1510
+ siteId,
1511
+ chatId: chatId ?? void 0,
1512
+ usePerUserSharing: conversationType === "groupchat"
1513
+ });
1585
1514
  activity.attachments = [buildTeamsFileInfoCard(await getDriveItemProperties({
1515
+ assertDirectAdapterHandoff: options?.assertDirectAdapterHandoff,
1586
1516
  siteId,
1587
- itemId: (await uploadAndShareSharePoint({
1588
- buffer: media.buffer,
1589
- filename: fileName,
1590
- contentType,
1591
- tokenProvider,
1592
- siteId,
1593
- chatId: chatId ?? void 0,
1594
- usePerUserSharing: conversationType === "groupchat"
1595
- })).itemId,
1517
+ itemId: uploaded.itemId,
1596
1518
  tokenProvider
1597
1519
  }))];
1598
1520
  return activity;
@@ -1640,9 +1562,14 @@ async function sendMSTeamsMessages(params) {
1640
1562
  let response;
1641
1563
  try {
1642
1564
  response = await sendWithRetry(async () => {
1643
- activity ??= await buildActivity(message, params.conversationRef, params.tokenProvider, params.sharePointSiteId, params.mediaMaxBytes, { feedbackLoopEnabled: params.feedbackLoopEnabled });
1565
+ require_resolve_allowlist.assertMSTeamsSendHandoff(params);
1566
+ activity ??= await buildActivity(message, params.conversationRef, params.tokenProvider, params.sharePointSiteId, params.mediaMaxBytes, {
1567
+ feedbackLoopEnabled: params.feedbackLoopEnabled,
1568
+ assertDirectAdapterHandoff: params.assertDirectAdapterHandoff
1569
+ });
1644
1570
  pendingUploadId ??= typeof activity["_pendingUploadId"] === "string" ? activity["_pendingUploadId"] : void 0;
1645
1571
  delete activity["_pendingUploadId"];
1572
+ require_resolve_allowlist.assertMSTeamsSendHandoff(params);
1646
1573
  providerDispatchStarted = true;
1647
1574
  return await sendFn(activity);
1648
1575
  }, {
@@ -1650,10 +1577,11 @@ async function sendMSTeamsMessages(params) {
1650
1577
  messageCount: messages.length
1651
1578
  });
1652
1579
  } catch (error) {
1653
- if (!providerDispatchStarted) throw new openclaw_plugin_sdk_error_runtime.PlatformMessageNotDispatchedError(error instanceof Error ? error.message : "Teams activity preparation failed", { cause: error });
1580
+ if (!providerDispatchStarted && !(error instanceof openclaw_plugin_sdk_error_runtime.PlatformMessageNotDispatchedError)) throw new openclaw_plugin_sdk_error_runtime.PlatformMessageNotDispatchedError(error instanceof Error ? error.message : "Teams activity preparation failed", { cause: error });
1654
1581
  throw error;
1655
1582
  }
1656
1583
  const messageId = extractMessageId(response) ?? "unknown";
1584
+ await params.onMessageSent?.(messageId, messageIndex);
1657
1585
  if (pendingUploadId && messageId !== "unknown") setPendingUploadActivityId(pendingUploadId, messageId);
1658
1586
  return messageId;
1659
1587
  };
@@ -1672,6 +1600,8 @@ async function sendMSTeamsMessages(params) {
1672
1600
  }
1673
1601
  const isChannel = params.conversationRef.conversation?.conversationType === "channel";
1674
1602
  const sendFn = (activity) => sendMSTeamsActivityWithReference(params.app, baseRef, activity, {
1603
+ assertDirectAdapterHandoff: params.assertDirectAdapterHandoff,
1604
+ onPlatformSendDispatch: params.onPlatformSendDispatch,
1675
1605
  threadActivityId: isChannel ? threadActivityId : void 0,
1676
1606
  serviceUrlBoundary: params.serviceUrlBoundary
1677
1607
  });
@@ -1681,7 +1611,7 @@ async function sendMSTeamsMessages(params) {
1681
1611
  if (params.replyStyle === "thread") {
1682
1612
  const ctx = params.context;
1683
1613
  if (!ctx) return await sendProactively(messages, 0, resolvedThreadId);
1684
- const sendFn = ctx.sendActivity;
1614
+ const sendFn = (activity) => require_resolve_allowlist.withMSTeamsConnectorHandoff(params, () => ctx.sendActivity(activity));
1685
1615
  const messageIds = [];
1686
1616
  for (const [idx, message] of messages.entries()) {
1687
1617
  const result = await withRevokedProxyFallback({
@@ -1,4 +1,4 @@
1
- const require_resolve_allowlist = require("./resolve-allowlist-CoKmLXYe.cjs");
1
+ const require_resolve_allowlist = require("./resolve-allowlist-CHzaaWiC.cjs");
2
2
  let openclaw_plugin_sdk_runtime_env = require("openclaw/plugin-sdk/runtime-env");
3
3
  let openclaw_plugin_sdk_provider_auth = require("openclaw/plugin-sdk/provider-auth");
4
4
  let openclaw_plugin_sdk_provider_auth_runtime = require("openclaw/plugin-sdk/provider-auth-runtime");
@@ -224,7 +224,6 @@ const MSTEAMS_SQLITE_MAX_POLL_ROWS = 2e3;
224
224
  const MSTEAMS_POLL_VOTE_BUCKET_COUNT = 32;
225
225
  const MSTEAMS_MAX_POLL_VOTE_BUCKET_ROWS = 1001 * MSTEAMS_POLL_VOTE_BUCKET_COUNT;
226
226
  const MSTEAMS_POLL_TTL_MS = 2592e6;
227
- const POLL_MUTATION_KEY = "polls";
228
227
  function normalizeChoiceValue(value) {
229
228
  if (typeof value === "string") {
230
229
  const trimmed = value.trim();
@@ -404,8 +403,11 @@ function createMSTeamsPollStoreState(params) {
404
403
  for (const row of await voteBucketStore.entries()) if (row.value.pollId === pollId) Object.assign(votes, row.value.votes);
405
404
  return votes;
406
405
  };
407
- const deletePollVotes = async (pollId) => {
408
- for (const row of await voteBucketStore.entries()) if (row.value.pollId === pollId) await voteBucketStore.delete(row.key);
406
+ const deletePollVotes = async (pollId, cachedRows) => {
407
+ for (const row of cachedRows?.values() ?? await voteBucketStore.entries()) if (row.value.pollId === pollId) {
408
+ await voteBucketStore.delete(row.key);
409
+ cachedRows?.delete(row.key);
410
+ }
409
411
  };
410
412
  const registerPollVotes = async (pollId, votes, updatedAt) => {
411
413
  const buckets = /* @__PURE__ */ new Map();
@@ -450,11 +452,16 @@ function createMSTeamsPollStoreState(params) {
450
452
  };
451
453
  };
452
454
  const prunePollStoreToLimit = async () => {
455
+ let voteRows;
456
+ const deletePrunedPollVotes = async (pollId) => {
457
+ voteRows ??= new Map((await voteBucketStore.entries()).map((row) => [row.key, row]));
458
+ await deletePollVotes(pollId, voteRows);
459
+ };
453
460
  const rows = [];
454
461
  for (const row of await pollStore.entries()) {
455
462
  if (!pruneExpired({ [row.key]: row.value })[row.key]) {
456
463
  await pollStore.delete(row.key);
457
- await deletePollVotes(row.value.id);
464
+ await deletePrunedPollVotes(row.value.id);
458
465
  continue;
459
466
  }
460
467
  rows.push(row);
@@ -465,11 +472,11 @@ function createMSTeamsPollStoreState(params) {
465
472
  });
466
473
  for (const row of sorted.slice(0, rows.length - MSTEAMS_MAX_POLLS)) {
467
474
  await pollStore.delete(row.key);
468
- await deletePollVotes(row.value.id);
475
+ await deletePrunedPollVotes(row.value.id);
469
476
  }
470
477
  };
471
478
  const createPoll = async (poll) => {
472
- await withMSTeamsSqliteMutationLock(params, POLL_MUTATION_KEY, async () => {
479
+ await withMSTeamsSqliteMutationLock(params, MSTEAMS_POLLS_NAMESPACE, async () => {
473
480
  const { metadata, votes } = splitMSTeamsPoll(poll);
474
481
  await pollStore.register(buildMSTeamsPollStateKey(poll.id), toPluginJsonValue(metadata));
475
482
  await deletePollVotes(poll.id);
@@ -484,7 +491,7 @@ function createMSTeamsPollStoreState(params) {
484
491
  return await reconstructPoll(poll);
485
492
  };
486
493
  const recordVote = async (vote) => {
487
- return await withMSTeamsSqliteMutationLock(params, POLL_MUTATION_KEY, async () => {
494
+ return await withMSTeamsSqliteMutationLock(params, MSTEAMS_POLLS_NAMESPACE, async () => {
488
495
  const pollKey = buildMSTeamsPollStateKey(vote.pollId);
489
496
  const poll = await pollStore.lookup(pollKey);
490
497
  if (!poll) return null;
@@ -1,4 +1,4 @@
1
- const require_resolve_allowlist = require("./resolve-allowlist-CoKmLXYe.cjs");
1
+ const require_resolve_allowlist = require("./resolve-allowlist-CHzaaWiC.cjs");
2
2
  let openclaw_plugin_sdk_html_entity_runtime = require("openclaw/plugin-sdk/html-entity-runtime");
3
3
  //#region extensions/msteams/src/graph-thread.ts
4
4
  /**