@openclaw/msteams 2026.7.2-beta.5 → 2026.8.1-beta.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.
@@ -1,22 +1,24 @@
1
- const require_delegated_state = require("./delegated-state-DOSCHaAB.cjs");
1
+ const require_rolldown_runtime = require("./rolldown-runtime-D6vf50IK.cjs");
2
2
  const require_runtime = require("./runtime-gZTAuFux.cjs");
3
3
  require("./runtime-api.cjs");
4
- const require_resolve_allowlist = require("./resolve-allowlist-Dr_1sOJh.cjs");
5
- const require_setup_surface = require("./setup-surface-xVejKCJV.cjs");
6
- const require_polls = require("./polls-CWExq2xZ.cjs");
4
+ const require_resolve_allowlist = require("./resolve-allowlist-C6YcNC9a.cjs");
5
+ const require_setup_surface = require("./setup-surface-DAhGL2h8.cjs");
6
+ const require_polls = require("./polls-DvuJvaDG.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
9
  let openclaw_plugin_sdk_reply_payload = require("openclaw/plugin-sdk/reply-payload");
10
10
  let openclaw_plugin_sdk_text_chunking = require("openclaw/plugin-sdk/text-chunking");
11
+ let openclaw_plugin_sdk_html_entity_runtime = require("openclaw/plugin-sdk/html-entity-runtime");
11
12
  let openclaw_plugin_sdk_provider_http = require("openclaw/plugin-sdk/provider-http");
12
13
  let node_dns_promises = require("node:dns/promises");
13
14
  let openclaw_plugin_sdk_ssrf_policy = require("openclaw/plugin-sdk/ssrf-policy");
14
15
  let openclaw_plugin_sdk_text_utility_runtime = require("openclaw/plugin-sdk/text-utility-runtime");
15
- let openclaw_plugin_sdk_html_entity_runtime = require("openclaw/plugin-sdk/html-entity-runtime");
16
+ let openclaw_plugin_sdk_error_runtime = require("openclaw/plugin-sdk/error-runtime");
16
17
  let node_crypto = require("node:crypto");
17
- node_crypto = require_delegated_state.__toESM(node_crypto, 1);
18
+ node_crypto = require_rolldown_runtime.__toESM(node_crypto, 1);
18
19
  let node_path = require("node:path");
19
- node_path = require_delegated_state.__toESM(node_path, 1);
20
+ node_path = require_rolldown_runtime.__toESM(node_path, 1);
21
+ let openclaw_plugin_sdk_global_singleton = require("openclaw/plugin-sdk/global-singleton");
20
22
  let openclaw_plugin_sdk_reply_chunking = require("openclaw/plugin-sdk/reply-chunking");
21
23
  let openclaw_plugin_sdk_web_media = require("openclaw/plugin-sdk/web-media");
22
24
  let openclaw_plugin_sdk_media_runtime = require("openclaw/plugin-sdk/media-runtime");
@@ -449,9 +451,15 @@ async function setPendingUploadActivityIdFs(id, activityId, options) {
449
451
  * before upload. This module stores the file data temporarily until the user
450
452
  * accepts or declines, or until the TTL expires.
451
453
  */
452
- const pendingUploads = /* @__PURE__ */ new Map();
453
- /** Timer handles keyed by upload ID, cleared on explicit removal to prevent ghost cleanup */
454
- const pendingUploadTimers = /* @__PURE__ */ new Map();
454
+ const { pendingUploads, pendingUploadTimers } = (0, openclaw_plugin_sdk_global_singleton.resolveGlobalSingleton)(Symbol.for("openclaw.msteams.pendingUploadState"), () => ({
455
+ pendingUploads: /* @__PURE__ */ new Map(),
456
+ /** Timer handles keyed by upload ID, cleared on explicit removal to prevent ghost cleanup. */
457
+ pendingUploadTimers: /* @__PURE__ */ new Map()
458
+ }), (state) => {
459
+ for (const timer of state.pendingUploadTimers.values()) clearTimeout(timer);
460
+ state.pendingUploadTimers.clear();
461
+ state.pendingUploads.clear();
462
+ });
455
463
  /** TTL for pending uploads: 5 minutes */
456
464
  const PENDING_UPLOAD_TTL_MS = 300 * 1e3;
457
465
  /**
@@ -1088,12 +1096,14 @@ async function getGraphAccessToken(tokenProvider) {
1088
1096
  async function uploadToSharePoint(params) {
1089
1097
  const fetchFn = params.fetchFn ?? fetch;
1090
1098
  const uploadPath = `/OpenClawShared/${encodeURIComponent(params.filename)}`;
1099
+ const uploadUrl = `${GRAPH_ROOT}/sites/${params.siteId}/drive/root:${uploadPath}:/content?@microsoft.graph.conflictBehavior=rename`;
1100
+ const timeoutMs = require_resolve_allowlist.resolveMSTeamsSharePointUploadTimeoutMs(params.buffer.length);
1091
1101
  const data = await require_resolve_allowlist.withMSTeamsAbortableRequestTimeout({
1092
1102
  label: SHAREPOINT_UPLOAD_TIMEOUT_LABEL,
1093
- timeoutMs: require_resolve_allowlist.resolveMSTeamsSharePointUploadTimeoutMs(params.buffer.length),
1103
+ timeoutMs,
1094
1104
  work: async (signal) => {
1095
1105
  const token = await getGraphAccessToken(params.tokenProvider);
1096
- const res = await fetchFn(`${GRAPH_ROOT}/sites/${params.siteId}/drive/root:${uploadPath}:/content`, {
1106
+ const res = await fetchFn(uploadUrl, {
1097
1107
  method: "PUT",
1098
1108
  headers: {
1099
1109
  "User-Agent": require_resolve_allowlist.buildUserAgent(),
@@ -1104,7 +1114,7 @@ async function uploadToSharePoint(params) {
1104
1114
  signal
1105
1115
  });
1106
1116
  if (!res.ok) throw await require_resolve_allowlist.createMSTeamsHttpError(res, "SharePoint upload failed");
1107
- return await (0, openclaw_plugin_sdk_provider_http.readProviderJsonResponse)(res, "msteams.graph-upload.uploadSharePointFile");
1117
+ return await (0, openclaw_plugin_sdk_provider_http.readProviderJsonResponse)(res, "msteams.graph-upload.uploadSharePointFile", { chunkTimeoutMs: timeoutMs });
1108
1118
  }
1109
1119
  });
1110
1120
  if (!data.id || !data.webUrl || !data.name) throw new Error("SharePoint upload response missing required fields");
@@ -1277,8 +1287,12 @@ async function extractFilename(url) {
1277
1287
  }
1278
1288
  try {
1279
1289
  const pathname = new URL(url).pathname;
1280
- const basename = node_path.default.basename(pathname);
1281
- const existingExt = (0, openclaw_plugin_sdk_media_runtime.getFileExtension)(pathname);
1290
+ let basename = node_path.default.basename(pathname);
1291
+ if (basename.includes("%")) try {
1292
+ const decodedBasename = decodeURIComponent(basename);
1293
+ if (!decodedBasename.includes("/") && !decodedBasename.includes("\\") && !decodedBasename.includes("\0")) basename = decodedBasename;
1294
+ } catch {}
1295
+ const existingExt = (0, openclaw_plugin_sdk_media_runtime.getFileExtension)(basename);
1282
1296
  if (basename && existingExt) return basename;
1283
1297
  const mime = await getMimeType(url);
1284
1298
  const ext = (0, openclaw_plugin_sdk_media_runtime.extensionForMime)(mime) ?? ".bin";
@@ -1292,7 +1306,7 @@ async function extractFilename(url) {
1292
1306
  * Check if a URL refers to a local file path.
1293
1307
  */
1294
1308
  function isLocalPath(url) {
1295
- if (url.startsWith("file://") || url.startsWith("/") || url.startsWith("~")) return true;
1309
+ if (/^file:\/\//iu.test(url) || url.startsWith("/") || url.startsWith("~")) return true;
1296
1310
  if (url.startsWith("\\") && !url.startsWith("\\\\")) return true;
1297
1311
  if (/^[a-zA-Z]:[\\/]/.test(url)) return true;
1298
1312
  if (url.startsWith("\\\\")) return true;
@@ -1725,17 +1739,26 @@ async function sendMSTeamsMessages(params) {
1725
1739
  }
1726
1740
  throw new Error("unreachable Teams send retry loop exit");
1727
1741
  };
1742
+ let providerDispatchStarted = false;
1728
1743
  const sendMessageInContext = async (sendFn, message, messageIndex) => {
1729
1744
  let pendingUploadId;
1730
- const messageId = extractMessageId(await sendWithRetry(async () => {
1731
- const activity = await buildActivity(message, params.conversationRef, params.tokenProvider, params.sharePointSiteId, params.mediaMaxBytes, { feedbackLoopEnabled: params.feedbackLoopEnabled });
1732
- pendingUploadId = typeof activity["_pendingUploadId"] === "string" ? activity["_pendingUploadId"] : void 0;
1733
- if (pendingUploadId) delete activity["_pendingUploadId"];
1734
- return await sendFn(activity);
1735
- }, {
1736
- messageIndex,
1737
- messageCount: messages.length
1738
- })) ?? "unknown";
1745
+ let response;
1746
+ try {
1747
+ response = await sendWithRetry(async () => {
1748
+ const activity = await buildActivity(message, params.conversationRef, params.tokenProvider, params.sharePointSiteId, params.mediaMaxBytes, { feedbackLoopEnabled: params.feedbackLoopEnabled });
1749
+ pendingUploadId = typeof activity["_pendingUploadId"] === "string" ? activity["_pendingUploadId"] : void 0;
1750
+ if (pendingUploadId) delete activity["_pendingUploadId"];
1751
+ providerDispatchStarted = true;
1752
+ return await sendFn(activity);
1753
+ }, {
1754
+ messageIndex,
1755
+ messageCount: messages.length
1756
+ });
1757
+ } catch (error) {
1758
+ if (!providerDispatchStarted) throw new openclaw_plugin_sdk_error_runtime.PlatformMessageNotDispatchedError(error instanceof Error ? error.message : "Teams activity preparation failed", { cause: error });
1759
+ throw error;
1760
+ }
1761
+ const messageId = extractMessageId(response) ?? "unknown";
1739
1762
  if (pendingUploadId && messageId !== "unknown") setPendingUploadActivityId(pendingUploadId, messageId);
1740
1763
  return messageId;
1741
1764
  };
@@ -1745,7 +1768,13 @@ async function sendMSTeamsMessages(params) {
1745
1768
  return messageIds;
1746
1769
  };
1747
1770
  const sendProactively = async (batch, startIndex, threadActivityId) => {
1748
- const baseRef = buildConversationReference(params.conversationRef);
1771
+ let baseRef;
1772
+ try {
1773
+ baseRef = buildConversationReference(params.conversationRef);
1774
+ } catch (error) {
1775
+ if (providerDispatchStarted) throw error;
1776
+ throw new openclaw_plugin_sdk_error_runtime.PlatformMessageNotDispatchedError(error instanceof Error ? error.message : "Teams conversation preparation failed", { cause: error });
1777
+ }
1749
1778
  const isChannel = params.conversationRef.conversation?.conversationType === "channel";
1750
1779
  const sendFn = (activity) => sendMSTeamsActivityWithReference(params.app, baseRef, activity, {
1751
1780
  threadActivityId: isChannel ? threadActivityId : void 0,
@@ -1,4 +1,4 @@
1
- const require_resolve_allowlist = require("./resolve-allowlist-Dr_1sOJh.cjs");
1
+ const require_resolve_allowlist = require("./resolve-allowlist-C6YcNC9a.cjs");
2
2
  let openclaw_plugin_sdk_provider_auth = require("openclaw/plugin-sdk/provider-auth");
3
3
  let openclaw_plugin_sdk_provider_auth_runtime = require("openclaw/plugin-sdk/provider-auth-runtime");
4
4
  let openclaw_plugin_sdk_runtime_env = require("openclaw/plugin-sdk/runtime-env");
@@ -6,9 +6,6 @@ let openclaw_plugin_sdk_runtime_env = require("openclaw/plugin-sdk/runtime-env")
6
6
  function shouldUseManualOAuthFlow(isRemote) {
7
7
  return isRemote || (0, openclaw_plugin_sdk_runtime_env.isWSL2Sync)();
8
8
  }
9
- function generatePkce() {
10
- return (0, openclaw_plugin_sdk_provider_auth.generateHexPkceVerifierChallenge)();
11
- }
12
9
  function buildMSTeamsAuthUrl(params) {
13
10
  const scopes = params.scopes ?? require_resolve_allowlist.MSTEAMS_DEFAULT_DELEGATED_SCOPES;
14
11
  return `${require_resolve_allowlist.buildMSTeamsAuthEndpoint(params.tenantId)}?${new URLSearchParams({
@@ -22,24 +19,6 @@ function buildMSTeamsAuthUrl(params) {
22
19
  prompt: "consent"
23
20
  }).toString()}`;
24
21
  }
25
- function parseCallbackInput(input, _expectedState) {
26
- return (0, openclaw_plugin_sdk_provider_auth_runtime.parseOAuthCallbackInput)(input, {
27
- missingState: "Missing 'state' parameter in URL. Paste the full redirect URL.",
28
- invalidInput: "Paste the full redirect URL (including code and state parameters), not just the authorization code."
29
- });
30
- }
31
- async function waitForLocalCallback(params) {
32
- return await (0, openclaw_plugin_sdk_provider_auth_runtime.waitForLocalOAuthCallback)({
33
- expectedState: params.expectedState,
34
- timeoutMs: params.timeoutMs,
35
- port: require_resolve_allowlist.MSTEAMS_OAUTH_CALLBACK_PORT,
36
- callbackPath: require_resolve_allowlist.MSTEAMS_OAUTH_CALLBACK_PATH,
37
- redirectUri: require_resolve_allowlist.MSTEAMS_OAUTH_REDIRECT_URI,
38
- successTitle: "MSTeams Delegated OAuth complete",
39
- progressMessage: `Waiting for OAuth callback on ${require_resolve_allowlist.MSTEAMS_OAUTH_REDIRECT_URI}...`,
40
- onProgress: params.onProgress
41
- });
42
- }
43
22
  //#endregion
44
23
  //#region extensions/msteams/src/oauth.ts
45
24
  async function loginMSTeamsDelegated(ctx, params) {
@@ -54,7 +33,7 @@ async function loginMSTeamsDelegated(ctx, params) {
54
33
  `Sign in to grant delegated permissions for MSTeams.`,
55
34
  `The callback will be captured automatically on localhost:${require_resolve_allowlist.MSTEAMS_OAUTH_CALLBACK_PORT}.`
56
35
  ].join("\n"), "MSTeams Delegated OAuth");
57
- const { verifier, challenge } = generatePkce();
36
+ const { verifier, challenge } = (0, openclaw_plugin_sdk_provider_auth.generateHexPkceVerifierChallenge)();
58
37
  const state = (0, openclaw_plugin_sdk_provider_auth_runtime.generateOAuthState)();
59
38
  const authUrl = buildMSTeamsAuthUrl({
60
39
  tenantId: params.tenantId,
@@ -71,9 +50,14 @@ async function loginMSTeamsDelegated(ctx, params) {
71
50
  ctx.log(`\nOpen this URL in your browser:\n\n${authUrl}\n`);
72
51
  }
73
52
  try {
74
- const { code } = await waitForLocalCallback({
53
+ const { code } = await (0, openclaw_plugin_sdk_provider_auth_runtime.waitForLocalOAuthCallback)({
75
54
  expectedState: state,
76
55
  timeoutMs: 300 * 1e3,
56
+ port: require_resolve_allowlist.MSTEAMS_OAUTH_CALLBACK_PORT,
57
+ callbackPath: require_resolve_allowlist.MSTEAMS_OAUTH_CALLBACK_PATH,
58
+ redirectUri: require_resolve_allowlist.MSTEAMS_OAUTH_REDIRECT_URI,
59
+ successTitle: "MSTeams Delegated OAuth complete",
60
+ progressMessage: `Waiting for OAuth callback on ${require_resolve_allowlist.MSTEAMS_OAUTH_REDIRECT_URI}...`,
77
61
  onProgress: (msg) => ctx.progress.update(msg)
78
62
  });
79
63
  ctx.progress.update("Exchanging authorization code for tokens...");
@@ -97,7 +81,10 @@ async function manualFlow(ctx, authUrl, state, verifier, params, cause) {
97
81
  ctx.progress.update("OAuth URL ready");
98
82
  ctx.log(`\nOpen this URL in your LOCAL browser:\n\n${authUrl}\n`);
99
83
  ctx.progress.update("Waiting for you to paste the callback URL...");
100
- const parsed = parseCallbackInput(await ctx.prompt("Paste the redirect URL here: "), state);
84
+ const parsed = (0, openclaw_plugin_sdk_provider_auth_runtime.parseOAuthCallbackInput)(await ctx.prompt("Paste the redirect URL here: "), {
85
+ missingState: "Missing 'state' parameter in URL. Paste the full redirect URL.",
86
+ invalidInput: "Paste the full redirect URL (including code and state parameters), not just the authorization code."
87
+ });
101
88
  if ("error" in parsed) throw new Error(parsed.error, cause ? { cause } : void 0);
102
89
  if (parsed.state !== state) throw new Error("OAuth state mismatch - please try again", cause ? { cause } : void 0);
103
90
  ctx.progress.update("Exchanging authorization code for tokens...");
@@ -1,22 +1,19 @@
1
- const require_delegated_state = require("./delegated-state-DOSCHaAB.cjs");
1
+ const require_rolldown_runtime = require("./rolldown-runtime-D6vf50IK.cjs");
2
2
  const require_runtime = require("./runtime-gZTAuFux.cjs");
3
3
  let openclaw_plugin_sdk_string_coerce_runtime = require("openclaw/plugin-sdk/string-coerce-runtime");
4
4
  let openclaw_plugin_sdk_file_lock = require("openclaw/plugin-sdk/file-lock");
5
5
  let openclaw_plugin_sdk_number_runtime = require("openclaw/plugin-sdk/number-runtime");
6
6
  let node_crypto = require("node:crypto");
7
- node_crypto = require_delegated_state.__toESM(node_crypto, 1);
7
+ node_crypto = require_rolldown_runtime.__toESM(node_crypto, 1);
8
8
  let node_path = require("node:path");
9
- node_path = require_delegated_state.__toESM(node_path, 1);
9
+ node_path = require_rolldown_runtime.__toESM(node_path, 1);
10
10
  let openclaw_plugin_sdk_keyed_async_queue = require("openclaw/plugin-sdk/keyed-async-queue");
11
11
  //#region extensions/msteams/src/conversation-store-helpers.ts
12
12
  function normalizeStoredConversationId(raw) {
13
13
  return raw.split(";")[0] ?? raw;
14
14
  }
15
15
  function parseStoredConversationTimestamp(value) {
16
- if (!value) return null;
17
- const parsed = Date.parse(value);
18
- if (!Number.isFinite(parsed)) return null;
19
- return parsed;
16
+ return (0, openclaw_plugin_sdk_number_runtime.parseDateStringTimestampMs)(value) ?? null;
20
17
  }
21
18
  function toConversationStoreEntries(entries) {
22
19
  return Array.from(entries, ([conversationId, reference]) => ({
@@ -363,9 +360,7 @@ function createPollVoteBucketStateStore(params) {
363
360
  });
364
361
  }
365
362
  function parseTimestamp(value) {
366
- if (!value) return null;
367
- const parsed = Date.parse(value);
368
- return Number.isFinite(parsed) ? parsed : null;
363
+ return (0, openclaw_plugin_sdk_number_runtime.parseDateStringTimestampMs)(value) ?? null;
369
364
  }
370
365
  function pruneExpired(polls) {
371
366
  const cutoff = Date.now() - MSTEAMS_POLL_TTL_MS;
@@ -384,8 +379,7 @@ function selectRetainedMSTeamsPolls(polls) {
384
379
  }
385
380
  function normalizeMSTeamsPollSelections(poll, selections) {
386
381
  const maxSelections = Math.max(1, poll.maxSelections);
387
- const mapped = selections.map((entry) => (0, openclaw_plugin_sdk_number_runtime.parseStrictNonNegativeInteger)(entry)).filter((value) => value !== void 0).filter((value) => value >= 0 && value < poll.options.length).map((value) => String(value));
388
- return (0, openclaw_plugin_sdk_string_coerce_runtime.uniqueStrings)(maxSelections > 1 ? mapped.slice(0, maxSelections) : mapped.slice(0, 1));
382
+ return (0, openclaw_plugin_sdk_string_coerce_runtime.uniqueStrings)(selections.map((entry) => (0, openclaw_plugin_sdk_number_runtime.parseStrictNonNegativeInteger)(entry)).filter((value) => value !== void 0).filter((value) => value >= 0 && value < poll.options.length).map((value) => String(value))).slice(0, maxSelections);
389
383
  }
390
384
  function splitMSTeamsPoll(poll) {
391
385
  const { votes, ...metadata } = poll;
@@ -0,0 +1,36 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ let openclaw_plugin_sdk_qa_runner_runtime = require("openclaw/plugin-sdk/qa-runner-runtime");
3
+ //#region extensions/msteams/src/qa/cli.ts
4
+ const DEFAULT_MSTEAMS_QA_SCENARIOS = ["channel-canary"];
5
+ const loadMSTeamsQaAdapterRuntime = (0, openclaw_plugin_sdk_qa_runner_runtime.createLazyCliRuntimeLoader)(() => Promise.resolve().then(() => require("./adapter.runtime-DEYjslFX.cjs")));
6
+ async function runQaMSTeams(options) {
7
+ await (0, openclaw_plugin_sdk_qa_runner_runtime.runLiveTransportQaSuiteCommand)({
8
+ channelId: "msteams",
9
+ defaultProviderMode: "mock-openai",
10
+ options,
11
+ selectScenarioIds: ({ scenarioIds }) => scenarioIds?.length ? [...scenarioIds] : [...DEFAULT_MSTEAMS_QA_SCENARIOS]
12
+ });
13
+ }
14
+ //#endregion
15
+ //#region extensions/msteams/qa-runner-api.ts
16
+ const qaRunnerCliRegistrations = [(0, openclaw_plugin_sdk_qa_runner_runtime.createLiveTransportQaCliRegistration)({
17
+ commandName: "msteams",
18
+ adapterFactory: {
19
+ id: "msteams",
20
+ isolatesInstances: true,
21
+ matches: ({ channelId, driver }) => channelId === "msteams" && driver === "live",
22
+ async create(context) {
23
+ return await (await loadMSTeamsQaAdapterRuntime()).createMSTeamsQaTransportAdapter(context);
24
+ }
25
+ },
26
+ defaultProviderMode: "mock-openai",
27
+ description: "Run Microsoft Teams Gateway QA against a local Bot Framework mock",
28
+ providerModeHelp: "Provider mode: mock-openai, aimock, or live-frontier",
29
+ outputDirHelp: "Microsoft Teams QA artifact directory",
30
+ allowFailuresHelp: "Write artifacts without setting a failing exit code when scenarios fail",
31
+ scenarioHelp: "Run only the named Microsoft Teams QA scenario (repeatable)",
32
+ sutAccountHelp: "Normalized Microsoft Teams SUT account id in QA artifacts",
33
+ run: runQaMSTeams
34
+ })];
35
+ //#endregion
36
+ exports.qaRunnerCliRegistrations = qaRunnerCliRegistrations;