@openclaw/msteams 2026.5.14-beta.1 → 2026.5.14-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.
package/dist/api.js CHANGED
@@ -1,3 +1,3 @@
1
- import { t as msteamsPlugin } from "./channel-C7J7iUD1.js";
2
- import { i as msteamsSetupAdapter, n as openDelegatedOAuthUrl, r as createMSTeamsSetupWizardBase, t as msteamsSetupWizard } from "./setup-surface-D9_2tf9Q.js";
1
+ import { i as msteamsSetupAdapter, n as openDelegatedOAuthUrl, r as createMSTeamsSetupWizardBase, t as msteamsSetupWizard } from "./setup-surface-CQrMX-nJ.js";
2
+ import { t as msteamsPlugin } from "./channel-C5CVTygn.js";
3
3
  export { createMSTeamsSetupWizardBase, msteamsPlugin, msteamsSetupAdapter, msteamsSetupWizard, openDelegatedOAuthUrl };
@@ -1,9 +1,7 @@
1
- import { o as buildProbeChannelStatusSummary, r as PAIRING_APPROVED_MESSAGE, s as chunkTextForOutbound, t as DEFAULT_ACCOUNT_ID, u as createDefaultChannelRuntimeState } from "./runtime-api-C3EIaIpt.js";
2
- import { h as resolveMSTeamsCredentials } from "./graph-users-OieoCBxW.js";
3
- import { a as parseMSTeamsTeamChannelInput, c as resolveMSTeamsUserAllowlist, i as parseMSTeamsConversationId, n as normalizeMSTeamsMessagingTarget, r as normalizeMSTeamsUserInput, s as resolveMSTeamsChannelAllowlist, t as looksLikeMSTeamsTargetId } from "./resolve-allowlist-DWp32o4l.js";
1
+ import { O as resolveNestedAllowlistDecision, S as normalizeChannelSlug, T as resolveChannelEntryMatchWithFallback, _ as isDangerousNameMatchingEnabled, i as buildChannelKeyCandidates, k as resolveToolsBySender, o as buildProbeChannelStatusSummary, r as PAIRING_APPROVED_MESSAGE, s as chunkTextForOutbound, t as DEFAULT_ACCOUNT_ID, u as createDefaultChannelRuntimeState, w as resolveAllowlistMatchSimple } from "./runtime-api-C3EIaIpt.js";
2
+ import { h as resolveMSTeamsCredentials } from "./graph-users-ChPPxUzD.js";
3
+ import { a as looksLikeMSTeamsTargetId, c as parseMSTeamsConversationId, d as resolveMSTeamsUserAllowlist, i as msteamsSetupAdapter, l as parseMSTeamsTeamChannelInput, o as normalizeMSTeamsMessagingTarget, s as normalizeMSTeamsUserInput, t as msteamsSetupWizard, u as resolveMSTeamsChannelAllowlist } from "./setup-surface-CQrMX-nJ.js";
4
4
  import { t as MSTeamsChannelConfigSchema } from "./config-schema-DwOEthCC.js";
5
- import { n as resolveMSTeamsGroupToolPolicy } from "./policy-bM71GXRd.js";
6
- import { i as msteamsSetupAdapter, t as msteamsSetupWizard } from "./setup-surface-D9_2tf9Q.js";
7
5
  import { describeAccountSnapshot } from "openclaw/plugin-sdk/account-helpers";
8
6
  import { formatAllowFromLowercase } from "openclaw/plugin-sdk/allow-from";
9
7
  import { createTopLevelChannelConfigAdapter } from "openclaw/plugin-sdk/channel-config-helpers";
@@ -67,6 +65,138 @@ const collectMSTeamsMutableAllowlistWarnings = createDangerousNameMatchingMutabl
67
65
  }]
68
66
  });
69
67
  //#endregion
68
+ //#region extensions/msteams/src/policy.ts
69
+ function resolveMSTeamsRouteConfig(params) {
70
+ const teamId = params.teamId?.trim();
71
+ const teamName = params.teamName?.trim();
72
+ const conversationId = params.conversationId?.trim();
73
+ const channelName = params.channelName?.trim();
74
+ const teams = params.cfg?.teams ?? {};
75
+ const allowlistConfigured = Object.keys(teams).length > 0;
76
+ const teamMatch = resolveChannelEntryMatchWithFallback({
77
+ entries: teams,
78
+ keys: buildChannelKeyCandidates(teamId, params.allowNameMatching ? teamName : void 0, params.allowNameMatching && teamName ? normalizeChannelSlug(teamName) : void 0),
79
+ wildcardKey: "*",
80
+ normalizeKey: normalizeChannelSlug
81
+ });
82
+ const teamConfig = teamMatch.entry;
83
+ const channels = teamConfig?.channels ?? {};
84
+ const channelAllowlistConfigured = Object.keys(channels).length > 0;
85
+ const channelMatch = resolveChannelEntryMatchWithFallback({
86
+ entries: channels,
87
+ keys: buildChannelKeyCandidates(conversationId, params.allowNameMatching ? channelName : void 0, params.allowNameMatching && channelName ? normalizeChannelSlug(channelName) : void 0),
88
+ wildcardKey: "*",
89
+ normalizeKey: normalizeChannelSlug
90
+ });
91
+ const channelConfig = channelMatch.entry;
92
+ return {
93
+ teamConfig,
94
+ channelConfig,
95
+ allowlistConfigured,
96
+ allowed: resolveNestedAllowlistDecision({
97
+ outerConfigured: allowlistConfigured,
98
+ outerMatched: Boolean(teamConfig),
99
+ innerConfigured: channelAllowlistConfigured,
100
+ innerMatched: Boolean(channelConfig)
101
+ }),
102
+ teamKey: teamMatch.matchKey ?? teamMatch.key,
103
+ channelKey: channelMatch.matchKey ?? channelMatch.key,
104
+ channelMatchKey: channelMatch.matchKey,
105
+ channelMatchSource: channelMatch.matchSource === "direct" || channelMatch.matchSource === "wildcard" ? channelMatch.matchSource : void 0
106
+ };
107
+ }
108
+ function resolveMSTeamsGroupToolPolicy(params) {
109
+ const cfg = params.cfg.channels?.msteams;
110
+ if (!cfg) return;
111
+ const groupId = params.groupId?.trim();
112
+ const groupChannel = params.groupChannel?.trim();
113
+ const groupSpace = params.groupSpace?.trim();
114
+ const allowNameMatching = isDangerousNameMatchingEnabled(cfg);
115
+ const resolved = resolveMSTeamsRouteConfig({
116
+ cfg,
117
+ teamId: groupSpace,
118
+ teamName: groupSpace,
119
+ conversationId: groupId,
120
+ channelName: groupChannel,
121
+ allowNameMatching
122
+ });
123
+ if (resolved.channelConfig) {
124
+ const senderPolicy = resolveToolsBySender({
125
+ toolsBySender: resolved.channelConfig.toolsBySender,
126
+ senderId: params.senderId,
127
+ senderName: params.senderName,
128
+ senderUsername: params.senderUsername,
129
+ senderE164: params.senderE164
130
+ });
131
+ if (senderPolicy) return senderPolicy;
132
+ if (resolved.channelConfig.tools) return resolved.channelConfig.tools;
133
+ const teamSenderPolicy = resolveToolsBySender({
134
+ toolsBySender: resolved.teamConfig?.toolsBySender,
135
+ senderId: params.senderId,
136
+ senderName: params.senderName,
137
+ senderUsername: params.senderUsername,
138
+ senderE164: params.senderE164
139
+ });
140
+ if (teamSenderPolicy) return teamSenderPolicy;
141
+ return resolved.teamConfig?.tools;
142
+ }
143
+ if (resolved.teamConfig) {
144
+ const teamSenderPolicy = resolveToolsBySender({
145
+ toolsBySender: resolved.teamConfig.toolsBySender,
146
+ senderId: params.senderId,
147
+ senderName: params.senderName,
148
+ senderUsername: params.senderUsername,
149
+ senderE164: params.senderE164
150
+ });
151
+ if (teamSenderPolicy) return teamSenderPolicy;
152
+ if (resolved.teamConfig.tools) return resolved.teamConfig.tools;
153
+ }
154
+ if (!groupId) return;
155
+ const channelCandidates = buildChannelKeyCandidates(groupId, allowNameMatching ? groupChannel : void 0, allowNameMatching && groupChannel ? normalizeChannelSlug(groupChannel) : void 0);
156
+ for (const teamConfig of Object.values(cfg.teams ?? {})) {
157
+ const match = resolveChannelEntryMatchWithFallback({
158
+ entries: teamConfig?.channels ?? {},
159
+ keys: channelCandidates,
160
+ wildcardKey: "*",
161
+ normalizeKey: normalizeChannelSlug
162
+ });
163
+ if (match.entry) {
164
+ const senderPolicy = resolveToolsBySender({
165
+ toolsBySender: match.entry.toolsBySender,
166
+ senderId: params.senderId,
167
+ senderName: params.senderName,
168
+ senderUsername: params.senderUsername,
169
+ senderE164: params.senderE164
170
+ });
171
+ if (senderPolicy) return senderPolicy;
172
+ if (match.entry.tools) return match.entry.tools;
173
+ const teamSenderPolicy = resolveToolsBySender({
174
+ toolsBySender: teamConfig?.toolsBySender,
175
+ senderId: params.senderId,
176
+ senderName: params.senderName,
177
+ senderUsername: params.senderUsername,
178
+ senderE164: params.senderE164
179
+ });
180
+ if (teamSenderPolicy) return teamSenderPolicy;
181
+ return teamConfig?.tools;
182
+ }
183
+ }
184
+ }
185
+ function resolveMSTeamsAllowlistMatch(params) {
186
+ return resolveAllowlistMatchSimple(params);
187
+ }
188
+ function resolveMSTeamsReplyPolicy(params) {
189
+ if (params.isDirectMessage) return {
190
+ requireMention: false,
191
+ replyStyle: "thread"
192
+ };
193
+ const requireMention = params.channelConfig?.requireMention ?? params.teamConfig?.requireMention ?? params.globalConfig?.requireMention ?? true;
194
+ return {
195
+ requireMention,
196
+ replyStyle: params.channelConfig?.replyStyle ?? params.teamConfig?.replyStyle ?? params.globalConfig?.replyStyle ?? (requireMention ? "thread" : "top-level")
197
+ };
198
+ }
199
+ //#endregion
70
200
  //#region extensions/msteams/src/presentation.ts
71
201
  function buildMSTeamsPresentationCard(params) {
72
202
  const body = [];
@@ -183,7 +313,7 @@ const collectMSTeamsSecurityWarnings = createAllowlistProviderGroupPolicyWarning
183
313
  resolveGroupPolicy: ({ cfg }) => cfg.channels?.msteams?.groupPolicy,
184
314
  collect: ({ groupPolicy }) => groupPolicy === "open" ? ["- MS Teams groups: groupPolicy=\"open\" allows any member to trigger (mention-gated). Set channels.msteams.groupPolicy=\"allowlist\" + channels.msteams.groupAllowFrom to restrict senders."] : []
185
315
  });
186
- const loadMSTeamsChannelRuntime = createLazyRuntimeNamedExport(() => import("./channel.runtime-B14HY4Hr.js"), "msTeamsChannelRuntime");
316
+ const loadMSTeamsChannelRuntime = createLazyRuntimeNamedExport(() => import("./channel.runtime-fqvE_yLN.js"), "msTeamsChannelRuntime");
187
317
  const resolveMSTeamsChannelConfig = (cfg) => ({
188
318
  allowFrom: cfg.channels?.msteams?.allowFrom,
189
319
  defaultTo: cfg.channels?.msteams?.defaultTo
@@ -965,7 +1095,7 @@ const msteamsPlugin = createChatChannelPlugin({
965
1095
  })
966
1096
  }),
967
1097
  gateway: { startAccount: async (ctx) => {
968
- const { monitorMSTeamsProvider } = await import("./src-CBRN2aXw.js");
1098
+ const { monitorMSTeamsProvider } = await import("./src-CYZq-lQ4.js");
969
1099
  const port = ctx.cfg.channels?.msteams?.webhook?.port ?? 3978;
970
1100
  ctx.setStatus({
971
1101
  accountId: ctx.accountId,
@@ -1006,4 +1136,4 @@ const msteamsPlugin = createChatChannelPlugin({
1006
1136
  outbound: msteamsChannelOutbound
1007
1137
  });
1008
1138
  //#endregion
1009
- export { msteamsPlugin as t };
1139
+ export { resolveMSTeamsRouteConfig as i, resolveMSTeamsAllowlistMatch as n, resolveMSTeamsReplyPolicy as r, msteamsPlugin as t };
@@ -1,2 +1,2 @@
1
- import { t as msteamsPlugin } from "./channel-C7J7iUD1.js";
1
+ import { t as msteamsPlugin } from "./channel-C5CVTygn.js";
2
2
  export { msteamsPlugin };
@@ -1,6 +1,6 @@
1
1
  import { s as chunkTextForOutbound } from "./runtime-api-C3EIaIpt.js";
2
- import { a as fetchGraphJson, c as normalizeQuery, d as postGraphJson, f as resolveGraphToken, i as fetchGraphAbsoluteUrl, l as patchGraphJson, n as deleteGraphRequest, o as listChannelsForTeam, r as escapeOData, s as listTeamsByName, t as searchGraphUsers, u as postGraphBetaJson } from "./graph-users-OieoCBxW.js";
3
- import { S as createMSTeamsConversationStoreFs, a as sendMessageMSTeams, b as createMSTeamsPollStoreFs, i as sendAdaptiveCardMSTeams, n as deleteMessageMSTeams, o as sendPollMSTeams, r as editMessageMSTeams, t as probeMSTeams } from "./probe-D3LwpZwU.js";
2
+ import { a as fetchGraphJson, c as normalizeQuery, d as postGraphJson, f as resolveGraphToken, i as fetchGraphAbsoluteUrl, l as patchGraphJson, n as deleteGraphRequest, o as listChannelsForTeam, r as escapeOData, s as listTeamsByName, t as searchGraphUsers, u as postGraphBetaJson } from "./graph-users-ChPPxUzD.js";
3
+ import { S as createMSTeamsConversationStoreFs, a as sendMessageMSTeams, b as createMSTeamsPollStoreFs, i as sendAdaptiveCardMSTeams, n as deleteMessageMSTeams, o as sendPollMSTeams, r as editMessageMSTeams, t as probeMSTeams } from "./probe-I2DM0U-s.js";
4
4
  import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime";
5
5
  import { createAttachedChannelResultAdapter } from "openclaw/plugin-sdk/channel-send-result";
6
6
  import { resolveOutboundSendDep } from "openclaw/plugin-sdk/outbound-send-deps";
@@ -1,2 +1,2 @@
1
- import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries } from "./secret-contract-BuoEXmPS.js";
1
+ import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries } from "./secret-contract-DDPQm4fE.js";
2
2
  export { collectRuntimeConfigAssignments, secretTargetRegistryEntries };
@@ -1,8 +1,9 @@
1
1
  import { M as getMSTeamsRuntime, h as fetchWithSsrFGuard$1 } from "./runtime-api-C3EIaIpt.js";
2
- import { n as refreshMSTeamsDelegatedTokens } from "./oauth.token-xxpoLWy5.js";
2
+ import { n as refreshMSTeamsDelegatedTokens } from "./oauth.token-mUfXUE0j.js";
3
3
  import { createRequire } from "node:module";
4
4
  import { isRecord as isRecord$2, normalizeLowercaseStringOrEmpty, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
5
5
  import { fetchWithSsrFGuard } from "openclaw/plugin-sdk/ssrf-runtime";
6
+ import { readProviderJsonResponse } from "openclaw/plugin-sdk/provider-http";
6
7
  import { Buffer } from "node:buffer";
7
8
  import { lookup } from "node:dns/promises";
8
9
  import { buildHostnameAllowlistPolicyFromSuffixAllowlist, isHttpsUrlAllowedByHostnameSuffixAllowlist, isPrivateIpAddress, normalizeHostnameSuffixAllowlist } from "openclaw/plugin-sdk/ssrf-policy";
@@ -1195,6 +1196,12 @@ async function resolveDelegatedAccessToken(params) {
1195
1196
  //#endregion
1196
1197
  //#region extensions/msteams/src/graph.ts
1197
1198
  const GRAPH_BETA = "https://graph.microsoft.com/beta";
1199
+ const NULL_BODY_STATUSES = new Set([
1200
+ 101,
1201
+ 204,
1202
+ 205,
1203
+ 304
1204
+ ]);
1198
1205
  function normalizeQuery(value) {
1199
1206
  return value?.trim() ?? "";
1200
1207
  }
@@ -1203,25 +1210,41 @@ function escapeOData(value) {
1203
1210
  }
1204
1211
  async function requestGraph(params) {
1205
1212
  const hasBody = params.body !== void 0;
1206
- const res = await fetch(`${params.root ?? "https://graph.microsoft.com/v1.0"}${params.path}`, {
1207
- method: params.method,
1208
- headers: {
1209
- "User-Agent": buildUserAgent(),
1210
- Authorization: `Bearer ${params.token}`,
1211
- ...hasBody ? { "Content-Type": "application/json" } : {},
1212
- ...params.headers
1213
+ const url = `${params.root ?? "https://graph.microsoft.com/v1.0"}${params.path}`;
1214
+ const currentFetch = globalThis.fetch;
1215
+ const { response, release } = await fetchWithSsrFGuard$1({
1216
+ url,
1217
+ fetchImpl: async (input, guardedInit) => await currentFetch(input, guardedInit),
1218
+ init: {
1219
+ method: params.method,
1220
+ headers: {
1221
+ "User-Agent": buildUserAgent(),
1222
+ Authorization: `Bearer ${params.token}`,
1223
+ ...hasBody ? { "Content-Type": "application/json" } : {},
1224
+ ...params.headers
1225
+ },
1226
+ body: hasBody ? JSON.stringify(params.body) : void 0
1213
1227
  },
1214
- body: hasBody ? JSON.stringify(params.body) : void 0
1228
+ auditContext: "msteams.graph"
1215
1229
  });
1216
- if (!res.ok) {
1217
- const text = await res.text().catch(() => "");
1218
- throw new Error(`${params.errorPrefix ?? "Graph"} ${params.path} failed (${res.status}): ${text || "unknown error"}`);
1230
+ try {
1231
+ if (!response.ok) {
1232
+ const text = await response.text().catch(() => "");
1233
+ throw new Error(`${params.errorPrefix ?? "Graph"} ${params.path} failed (${response.status}): ${text || "unknown error"}`);
1234
+ }
1235
+ const body = NULL_BODY_STATUSES.has(response.status) ? null : await response.arrayBuffer();
1236
+ return new Response(body, {
1237
+ status: response.status,
1238
+ statusText: response.statusText,
1239
+ headers: new Headers(response.headers)
1240
+ });
1241
+ } finally {
1242
+ await release();
1219
1243
  }
1220
- return res;
1221
1244
  }
1222
- async function readOptionalGraphJson(res) {
1245
+ async function readOptionalGraphJson(res, label) {
1223
1246
  if (res.status === 204 || res.headers?.get?.("content-length") === "0") return;
1224
- return await res.json();
1247
+ return await readProviderJsonResponse(res, label);
1225
1248
  }
1226
1249
  async function fetchGraphJson(params) {
1227
1250
  return await readOptionalGraphJson(await requestGraph({
@@ -1230,7 +1253,7 @@ async function fetchGraphJson(params) {
1230
1253
  method: params.method,
1231
1254
  body: params.body,
1232
1255
  headers: params.headers
1233
- }));
1256
+ }), `Graph ${params.path} failed`);
1234
1257
  }
1235
1258
  /**
1236
1259
  * Fetch JSON from an absolute Graph API URL (for example @odata.nextLink
@@ -1251,7 +1274,7 @@ async function fetchGraphAbsoluteUrl(params) {
1251
1274
  const text = await response.text().catch(() => "");
1252
1275
  throw new Error(`Graph ${params.url} failed (${response.status}): ${text || "unknown error"}`);
1253
1276
  }
1254
- return await response.json();
1277
+ return await readProviderJsonResponse(response, `Graph ${params.url} failed`);
1255
1278
  } finally {
1256
1279
  await release();
1257
1280
  }
@@ -1325,7 +1348,7 @@ async function postGraphJson(params) {
1325
1348
  method: "POST",
1326
1349
  body: params.body,
1327
1350
  errorPrefix: "Graph POST"
1328
- }));
1351
+ }), `Graph POST ${params.path} failed`);
1329
1352
  }
1330
1353
  async function postGraphBetaJson(params) {
1331
1354
  return readOptionalGraphJson(await requestGraph({
@@ -1335,7 +1358,7 @@ async function postGraphBetaJson(params) {
1335
1358
  root: GRAPH_BETA,
1336
1359
  body: params.body,
1337
1360
  errorPrefix: "Graph beta POST"
1338
- }));
1361
+ }), `Graph beta POST ${params.path} failed`);
1339
1362
  }
1340
1363
  async function deleteGraphRequest(params) {
1341
1364
  await requestGraph({
@@ -1346,15 +1369,13 @@ async function deleteGraphRequest(params) {
1346
1369
  });
1347
1370
  }
1348
1371
  async function patchGraphJson(params) {
1349
- const res = await requestGraph({
1372
+ return readOptionalGraphJson(await requestGraph({
1350
1373
  token: params.token,
1351
1374
  path: params.path,
1352
1375
  method: "PATCH",
1353
1376
  body: params.body,
1354
1377
  errorPrefix: "Graph PATCH"
1355
- });
1356
- if (res.status === 204 || res.headers.get("content-length") === "0") return;
1357
- return await res.json();
1378
+ }), `Graph PATCH ${params.path} failed`);
1358
1379
  }
1359
1380
  async function listChannelsForTeam(token, teamId) {
1360
1381
  const { items } = await fetchAllGraphPages({
@@ -1,4 +1,4 @@
1
- import { a as MSTEAMS_OAUTH_CALLBACK_PORT, i as MSTEAMS_OAUTH_CALLBACK_PATH, o as MSTEAMS_OAUTH_REDIRECT_URI, r as MSTEAMS_DEFAULT_DELEGATED_SCOPES, s as buildMSTeamsAuthEndpoint, t as exchangeMSTeamsCodeForTokens } from "./oauth.token-xxpoLWy5.js";
1
+ import { a as MSTEAMS_OAUTH_CALLBACK_PORT, i as MSTEAMS_OAUTH_CALLBACK_PATH, o as MSTEAMS_OAUTH_REDIRECT_URI, r as MSTEAMS_DEFAULT_DELEGATED_SCOPES, s as buildMSTeamsAuthEndpoint, t as exchangeMSTeamsCodeForTokens } from "./oauth.token-mUfXUE0j.js";
2
2
  import { generateHexPkceVerifierChallenge } from "openclaw/plugin-sdk/provider-auth";
3
3
  import { generateOAuthState, parseOAuthCallbackInput, waitForLocalOAuthCallback } from "openclaw/plugin-sdk/provider-auth-runtime";
4
4
  import { isWSL2Sync } from "openclaw/plugin-sdk/runtime-env";
@@ -1,4 +1,5 @@
1
1
  import { fetchWithSsrFGuard } from "openclaw/plugin-sdk/ssrf-runtime";
2
+ import { readProviderJsonResponse } from "openclaw/plugin-sdk/provider-http";
2
3
  //#region extensions/msteams/src/oauth.shared.ts
3
4
  const MSTEAMS_OAUTH_REDIRECT_URI = "http://localhost:8086/oauth2callback";
4
5
  const MSTEAMS_OAUTH_CALLBACK_PORT = 8086;
@@ -51,7 +52,7 @@ async function fetchMSTeamsTokens(params) {
51
52
  const errorText = await response.text();
52
53
  throw new Error(`MSTeams ${params.failureLabel} failed (${response.status}): ${errorText}`);
53
54
  }
54
- return await response.json();
55
+ return await readProviderJsonResponse(response, `MSTeams ${params.failureLabel} failed`);
55
56
  } finally {
56
57
  await release();
57
58
  }
@@ -1,6 +1,6 @@
1
1
  import { C as normalizeStringEntries, E as resolveChannelMediaMaxBytes, M as getMSTeamsRuntime, d as detectMime, g as getFileExtension, m as extractOriginalFilename, p as extensionForMime, y as loadOutboundMediaFromUrl } from "./runtime-api-C3EIaIpt.js";
2
- import { C as loadMSTeamsSdkWithAuth, D as formatMSTeamsSendErrorHint, E as classifyMSTeamsSendError, O as formatUnknownError, S as createMSTeamsTokenProvider, _ as resolveMSTeamsStorePath, h as resolveMSTeamsCredentials, k as isRevokedProxyError, m as loadDelegatedTokens, w as buildUserAgent, x as createMSTeamsAdapter, y as readAccessToken } from "./graph-users-OieoCBxW.js";
3
- import { i as resolveMSTeamsRouteConfig, r as resolveMSTeamsReplyPolicy } from "./policy-bM71GXRd.js";
2
+ import { C as loadMSTeamsSdkWithAuth, D as formatMSTeamsSendErrorHint, E as classifyMSTeamsSendError, O as formatUnknownError, S as createMSTeamsTokenProvider, _ as resolveMSTeamsStorePath, h as resolveMSTeamsCredentials, k as isRevokedProxyError, m as loadDelegatedTokens, w as buildUserAgent, x as createMSTeamsAdapter, y as readAccessToken } from "./graph-users-ChPPxUzD.js";
3
+ import { i as resolveMSTeamsRouteConfig, r as resolveMSTeamsReplyPolicy } from "./channel-C5CVTygn.js";
4
4
  import { createMessageReceiptFromOutboundResults } from "openclaw/plugin-sdk/channel-message";
5
5
  import { isRecord, normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
6
6
  import { withFileLock } from "openclaw/plugin-sdk/file-lock";
@@ -1,2 +1,2 @@
1
- import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries, t as channelSecrets } from "./secret-contract-BuoEXmPS.js";
1
+ import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries, t as channelSecrets } from "./secret-contract-DDPQm4fE.js";
2
2
  export { channelSecrets, collectRuntimeConfigAssignments, secretTargetRegistryEntries };
@@ -1,6 +1,6 @@
1
- import { h as resolveMSTeamsCredentials } from "./graph-users-OieoCBxW.js";
1
+ import { h as resolveMSTeamsCredentials } from "./graph-users-ChPPxUzD.js";
2
+ import { i as msteamsSetupAdapter, t as msteamsSetupWizard } from "./setup-surface-CQrMX-nJ.js";
2
3
  import { t as MSTeamsChannelConfigSchema } from "./config-schema-DwOEthCC.js";
3
- import { i as msteamsSetupAdapter, t as msteamsSetupWizard } from "./setup-surface-D9_2tf9Q.js";
4
4
  import { describeAccountSnapshot } from "openclaw/plugin-sdk/account-helpers";
5
5
  import { formatAllowFromLowercase } from "openclaw/plugin-sdk/allow-from";
6
6
  import { createTopLevelChannelConfigAdapter } from "openclaw/plugin-sdk/channel-config-helpers";
@@ -1,7 +1,223 @@
1
- import { O as formatUnknownError, g as saveDelegatedTokens, h as resolveMSTeamsCredentials, p as hasConfiguredMSTeamsCredentials, v as normalizeSecretInputString } from "./graph-users-OieoCBxW.js";
2
- import { c as resolveMSTeamsUserAllowlist, o as parseMSTeamsTeamEntry, s as resolveMSTeamsChannelAllowlist } from "./resolve-allowlist-DWp32o4l.js";
1
+ import { O as formatUnknownError, c as normalizeQuery, f as resolveGraphToken, g as saveDelegatedTokens, h as resolveMSTeamsCredentials, o as listChannelsForTeam, p as hasConfiguredMSTeamsCredentials, s as listTeamsByName, t as searchGraphUsers, v as normalizeSecretInputString } from "./graph-users-ChPPxUzD.js";
2
+ import { mapAllowlistResolutionInputs } from "openclaw/plugin-sdk/allow-from";
3
+ import { normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString } from "openclaw/plugin-sdk/string-coerce-runtime";
3
4
  import { DEFAULT_ACCOUNT_ID, createStandardChannelSetupStatus, createTopLevelChannelAllowFromSetter, createTopLevelChannelDmPolicy, createTopLevelChannelGroupPolicySetter, mergeAllowFromEntries, splitSetupEntries } from "openclaw/plugin-sdk/setup";
4
5
  import { formatDocsLink } from "openclaw/plugin-sdk/setup-tools";
6
+ //#region extensions/msteams/src/resolve-allowlist.ts
7
+ function stripProviderPrefix(raw) {
8
+ return raw.replace(/^(msteams|teams):/i, "");
9
+ }
10
+ function normalizeMSTeamsMessagingTarget(raw) {
11
+ let trimmed = raw.trim();
12
+ if (!trimmed) return;
13
+ trimmed = stripProviderPrefix(trimmed).trim();
14
+ if (/^conversation:/i.test(trimmed)) {
15
+ const id = trimmed.slice(13).trim();
16
+ return id ? `conversation:${id}` : void 0;
17
+ }
18
+ if (/^user:/i.test(trimmed)) {
19
+ const id = trimmed.slice(5).trim();
20
+ return id ? `user:${id}` : void 0;
21
+ }
22
+ return trimmed || void 0;
23
+ }
24
+ function normalizeMSTeamsUserInput(raw) {
25
+ return stripProviderPrefix(raw).replace(/^(user|conversation):/i, "").trim();
26
+ }
27
+ function parseMSTeamsConversationId(raw) {
28
+ const trimmed = stripProviderPrefix(raw).trim();
29
+ if (!/^conversation:/i.test(trimmed)) return null;
30
+ return trimmed.slice(13).trim();
31
+ }
32
+ /**
33
+ * Detect whether a raw target string looks like a Microsoft Teams conversation
34
+ * or user id that cron announce delivery and other explicit-target paths can
35
+ * forward verbatim to the channel adapter.
36
+ *
37
+ * Accepts both prefixed and bare formats:
38
+ * - `conversation:<id>` — explicit conversation prefix
39
+ * - `user:<aad-guid>` — user id (16+ hex chars, UUID-like)
40
+ * - `19:abc@thread.tacv2` / `19:abc@thread.skype` — channel / legacy group
41
+ * - `19:{userId}_{appId}@unq.gbl.spaces` — Graph 1:1 chat thread format
42
+ * - `a:1xxx` — Bot Framework personal (1:1) chat id
43
+ * - `8:orgid:xxx` — Bot Framework org-scoped personal chat id
44
+ * - `29:xxx` — Bot Framework user id
45
+ *
46
+ * Display-name user targets such as `user:John Smith` intentionally return
47
+ * false so that the Graph API directory lookup still runs for them.
48
+ */
49
+ function looksLikeMSTeamsTargetId(raw) {
50
+ const trimmed = raw.trim();
51
+ if (!trimmed) return false;
52
+ if (/^conversation:/i.test(trimmed)) return true;
53
+ if (/^user:/i.test(trimmed)) {
54
+ const id = trimmed.slice(5).trim();
55
+ return /^[0-9a-fA-F-]{16,}$/.test(id);
56
+ }
57
+ if (/^19:.+@thread\.(tacv2|skype)$/i.test(trimmed)) return true;
58
+ if (/^19:.+@unq\.gbl\.spaces$/i.test(trimmed)) return true;
59
+ if (/^a:1[A-Za-z0-9_-]+$/i.test(trimmed)) return true;
60
+ if (/^8:orgid:[A-Za-z0-9-]+$/i.test(trimmed)) return true;
61
+ if (/^29:[A-Za-z0-9_-]+$/i.test(trimmed)) return true;
62
+ return /@thread\b/i.test(trimmed);
63
+ }
64
+ function normalizeMSTeamsTeamKey(raw) {
65
+ return stripProviderPrefix(raw).replace(/^team:/i, "").trim() || void 0;
66
+ }
67
+ function normalizeMSTeamsChannelKey(raw) {
68
+ return (raw?.trim().replace(/^#/, "").trim() ?? "") || void 0;
69
+ }
70
+ function normalizeMSTeamsConversationTargetId(raw) {
71
+ const trimmed = stripProviderPrefix(raw).trim();
72
+ return parseMSTeamsConversationId(trimmed) ?? trimmed;
73
+ }
74
+ function looksLikeMSTeamsThreadConversationId(raw) {
75
+ const normalized = normalizeMSTeamsConversationTargetId(raw);
76
+ return /^19:.+@thread\./i.test(normalized);
77
+ }
78
+ function parseMSTeamsTeamChannelInput(raw) {
79
+ const trimmed = stripProviderPrefix(raw).trim();
80
+ if (!trimmed) return {};
81
+ const parts = trimmed.split("/");
82
+ const team = normalizeMSTeamsTeamKey(parts[0] ?? "");
83
+ const channel = parts.length > 1 ? normalizeMSTeamsChannelKey(parts.slice(1).join("/")) : void 0;
84
+ return {
85
+ ...team ? { team } : {},
86
+ ...channel ? { channel } : {}
87
+ };
88
+ }
89
+ function parseMSTeamsTeamEntry(raw) {
90
+ const { team, channel } = parseMSTeamsTeamChannelInput(raw);
91
+ if (!team) return null;
92
+ return {
93
+ teamKey: team,
94
+ ...channel ? { channelKey: channel } : {}
95
+ };
96
+ }
97
+ async function resolveMSTeamsChannelAllowlist(params) {
98
+ let tokenPromise;
99
+ const getToken = () => {
100
+ tokenPromise ??= resolveGraphToken(params.cfg);
101
+ return tokenPromise;
102
+ };
103
+ return await mapAllowlistResolutionInputs({
104
+ inputs: params.entries,
105
+ mapInput: async (input) => {
106
+ const { team, channel } = parseMSTeamsTeamChannelInput(input);
107
+ if (!team) return {
108
+ input,
109
+ resolved: false
110
+ };
111
+ if (looksLikeMSTeamsThreadConversationId(team)) {
112
+ const teamId = normalizeMSTeamsConversationTargetId(team);
113
+ if (!channel) return {
114
+ input,
115
+ resolved: true,
116
+ teamId,
117
+ teamName: teamId
118
+ };
119
+ if (!looksLikeMSTeamsThreadConversationId(channel)) return {
120
+ input,
121
+ resolved: false,
122
+ teamId,
123
+ teamName: teamId,
124
+ note: "channel id required for conversation-id team"
125
+ };
126
+ const channelId = normalizeMSTeamsConversationTargetId(channel);
127
+ return {
128
+ input,
129
+ resolved: true,
130
+ teamId,
131
+ teamName: teamId,
132
+ channelId,
133
+ channelName: channelId
134
+ };
135
+ }
136
+ const token = await getToken();
137
+ const teams = /^[0-9a-fA-F-]{16,}$/.test(team) ? [{
138
+ id: team,
139
+ displayName: team
140
+ }] : await listTeamsByName(token, team);
141
+ if (teams.length === 0) return {
142
+ input,
143
+ resolved: false,
144
+ note: "team not found"
145
+ };
146
+ const teamMatch = teams[0];
147
+ const graphTeamId = teamMatch.id?.trim();
148
+ const teamName = teamMatch.displayName?.trim() || team;
149
+ if (!graphTeamId) return {
150
+ input,
151
+ resolved: false,
152
+ note: "team id missing"
153
+ };
154
+ let teamChannels = [];
155
+ try {
156
+ teamChannels = await listChannelsForTeam(token, graphTeamId);
157
+ } catch {}
158
+ const teamId = teamChannels.find((ch) => normalizeOptionalLowercaseString(ch.displayName) === "general")?.id?.trim() || graphTeamId;
159
+ if (!channel) return {
160
+ input,
161
+ resolved: true,
162
+ teamId,
163
+ teamName,
164
+ note: teams.length > 1 ? "multiple teams; chose first" : void 0
165
+ };
166
+ const normalizedChannel = normalizeOptionalLowercaseString(channel);
167
+ const channelMatch = teamChannels.find((item) => item.id === channel) ?? teamChannels.find((item) => normalizeOptionalLowercaseString(item.displayName) === normalizedChannel) ?? teamChannels.find((item) => normalizeLowercaseStringOrEmpty(item.displayName ?? "").includes(normalizedChannel ?? ""));
168
+ if (!channelMatch?.id) return {
169
+ input,
170
+ resolved: false,
171
+ note: "channel not found"
172
+ };
173
+ return {
174
+ input,
175
+ resolved: true,
176
+ teamId,
177
+ teamName,
178
+ channelId: channelMatch.id,
179
+ channelName: channelMatch.displayName ?? channel,
180
+ note: teamChannels.length > 1 ? "multiple channels; chose first" : void 0
181
+ };
182
+ }
183
+ });
184
+ }
185
+ async function resolveMSTeamsUserAllowlist(params) {
186
+ const token = await resolveGraphToken(params.cfg);
187
+ return await mapAllowlistResolutionInputs({
188
+ inputs: params.entries,
189
+ mapInput: async (input) => {
190
+ const query = normalizeQuery(normalizeMSTeamsUserInput(input));
191
+ if (!query) return {
192
+ input,
193
+ resolved: false
194
+ };
195
+ if (/^[0-9a-fA-F-]{16,}$/.test(query)) return {
196
+ input,
197
+ resolved: true,
198
+ id: query
199
+ };
200
+ const users = await searchGraphUsers({
201
+ token,
202
+ query,
203
+ top: 10
204
+ });
205
+ const match = users[0];
206
+ if (!match?.id) return {
207
+ input,
208
+ resolved: false
209
+ };
210
+ return {
211
+ input,
212
+ resolved: true,
213
+ id: match.id,
214
+ name: match.displayName ?? void 0,
215
+ note: users.length > 1 ? "multiple matches; chose first" : void 0
216
+ };
217
+ }
218
+ });
219
+ }
220
+ //#endregion
5
221
  //#region extensions/msteams/src/setup-core.ts
6
222
  const msteamsSetupAdapter = {
7
223
  resolveAccountId: () => DEFAULT_ACCOUNT_ID,
@@ -271,7 +487,7 @@ const msteamsSetupWizard = {
271
487
  }
272
488
  };
273
489
  try {
274
- const { loginMSTeamsDelegated } = await import("./oauth-BWJyilR1.js");
490
+ const { loginMSTeamsDelegated } = await import("./oauth-DsVj42gA.js");
275
491
  const progress = params.prompter.progress("MSTeams Delegated OAuth");
276
492
  saveDelegatedTokens(await loginMSTeamsDelegated({
277
493
  isRemote: true,
@@ -310,4 +526,4 @@ const msteamsSetupWizard = {
310
526
  })
311
527
  };
312
528
  //#endregion
313
- export { msteamsSetupAdapter as i, openDelegatedOAuthUrl as n, createMSTeamsSetupWizardBase as r, msteamsSetupWizard as t };
529
+ export { looksLikeMSTeamsTargetId as a, parseMSTeamsConversationId as c, resolveMSTeamsUserAllowlist as d, msteamsSetupAdapter as i, parseMSTeamsTeamChannelInput as l, openDelegatedOAuthUrl as n, normalizeMSTeamsMessagingTarget as o, createMSTeamsSetupWizardBase as r, normalizeMSTeamsUserInput as s, msteamsSetupWizard as t, resolveMSTeamsChannelAllowlist as u };
@@ -1,8 +1,8 @@
1
1
  import { A as summarizeMapping, D as resolveDefaultGroupPolicy, E as resolveChannelMediaMaxBytes, M as getMSTeamsRuntime, N as getOptionalMSTeamsRuntime, _ as isDangerousNameMatchingEnabled, a as buildMediaPayload, b as logTypingFailure, c as createChannelMessageReplyPipeline, f as dispatchReplyFromConfigWithSettledDispatcher$1, l as createChannelPairingController, n as DEFAULT_WEBHOOK_MAX_BODY_BYTES, t as DEFAULT_ACCOUNT_ID, v as keepHttpServerTaskAlive, x as mergeAllowlist } from "./runtime-api-C3EIaIpt.js";
2
- import { A as ATTACHMENT_TAG_RE, B as isLikelyImageAttachment, C as loadMSTeamsSdkWithAuth, D as formatMSTeamsSendErrorHint, E as classifyMSTeamsSendError, F as estimateBase64DecodedBytes, G as resolveAttachmentFetchPolicy, H as isUrlAllowed, I as extractHtmlFromAttachment, J as safeFetchWithPolicy, K as resolveMediaSsrfPolicy, L as extractInlineImageCandidates, M as IMG_SRC_RE, N as applyAuthorizationHeaderForUrl, O as formatUnknownError, P as encodeGraphShareId, R as inferPlaceholder, S as createMSTeamsTokenProvider, T as ensureUserAgentHeader, U as normalizeContentType, V as isRecord$1, W as readNestedString, X as tryBuildGraphSharesUrlForSharedLink, Y as safeHostForUrl, _ as resolveMSTeamsStorePath, a as fetchGraphJson, b as createBotFrameworkJwtValidator, h as resolveMSTeamsCredentials, j as GRAPH_ROOT, q as resolveRequestUrl, w as buildUserAgent, x as createMSTeamsAdapter, z as isDownloadableAttachment } from "./graph-users-OieoCBxW.js";
3
- import { c as resolveMSTeamsUserAllowlist, s as resolveMSTeamsChannelAllowlist } from "./resolve-allowlist-DWp32o4l.js";
4
- import { i as resolveMSTeamsRouteConfig, r as resolveMSTeamsReplyPolicy, t as resolveMSTeamsAllowlistMatch } from "./policy-bM71GXRd.js";
5
- import { C as readJsonFile, S as createMSTeamsConversationStoreFs, T as writeJsonFile, _ as buildFileInfoCard, b as createMSTeamsPollStoreFs, c as renderReplyPayloadsToMessages, d as withRevokedProxyFallback, f as resolveGraphChatId, g as removePendingUploadFs, h as getPendingUploadFs, l as sendMSTeamsMessages, m as removePendingUpload, p as getPendingUpload, s as buildConversationReference, u as AI_GENERATED_ENTITY, v as parseFileConsentInvoke, w as withFileLock, x as extractMSTeamsPollVote, y as uploadToConsentUrl } from "./probe-D3LwpZwU.js";
2
+ import { A as ATTACHMENT_TAG_RE, B as isLikelyImageAttachment, C as loadMSTeamsSdkWithAuth, D as formatMSTeamsSendErrorHint, E as classifyMSTeamsSendError, F as estimateBase64DecodedBytes, G as resolveAttachmentFetchPolicy, H as isUrlAllowed, I as extractHtmlFromAttachment, J as safeFetchWithPolicy, K as resolveMediaSsrfPolicy, L as extractInlineImageCandidates, M as IMG_SRC_RE, N as applyAuthorizationHeaderForUrl, O as formatUnknownError, P as encodeGraphShareId, R as inferPlaceholder, S as createMSTeamsTokenProvider, T as ensureUserAgentHeader, U as normalizeContentType, V as isRecord$1, W as readNestedString, X as tryBuildGraphSharesUrlForSharedLink, Y as safeHostForUrl, _ as resolveMSTeamsStorePath, a as fetchGraphJson, b as createBotFrameworkJwtValidator, h as resolveMSTeamsCredentials, j as GRAPH_ROOT, q as resolveRequestUrl, w as buildUserAgent, x as createMSTeamsAdapter, z as isDownloadableAttachment } from "./graph-users-ChPPxUzD.js";
3
+ import { d as resolveMSTeamsUserAllowlist, u as resolveMSTeamsChannelAllowlist } from "./setup-surface-CQrMX-nJ.js";
4
+ import { i as resolveMSTeamsRouteConfig, n as resolveMSTeamsAllowlistMatch, r as resolveMSTeamsReplyPolicy } from "./channel-C5CVTygn.js";
5
+ import { C as readJsonFile, S as createMSTeamsConversationStoreFs, T as writeJsonFile, _ as buildFileInfoCard, b as createMSTeamsPollStoreFs, c as renderReplyPayloadsToMessages, d as withRevokedProxyFallback, f as resolveGraphChatId, g as removePendingUploadFs, h as getPendingUploadFs, l as sendMSTeamsMessages, m as removePendingUpload, p as getPendingUpload, s as buildConversationReference, u as AI_GENERATED_ENTITY, v as parseFileConsentInvoke, w as withFileLock, x as extractMSTeamsPollVote, y as uploadToConsentUrl } from "./probe-I2DM0U-s.js";
6
6
  import { formatAllowlistMatchMeta } from "openclaw/plugin-sdk/allow-from";
7
7
  import { createLiveMessageState, createPreviewMessageReceipt, defineFinalizableLivePreviewAdapter, deliverWithFinalizableLivePreviewAdapter, markLiveMessageFinalized } from "openclaw/plugin-sdk/channel-message";
8
8
  import { normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString, readStringValue } from "openclaw/plugin-sdk/string-coerce-runtime";
package/dist/test-api.js CHANGED
@@ -1,2 +1,2 @@
1
- import { t as msteamsPlugin } from "./channel-C7J7iUD1.js";
1
+ import { t as msteamsPlugin } from "./channel-C5CVTygn.js";
2
2
  export { msteamsPlugin };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw/msteams",
3
- "version": "2026.5.14-beta.1",
3
+ "version": "2026.5.14-beta.2",
4
4
  "description": "OpenClaw Microsoft Teams channel plugin",
5
5
  "repository": {
6
6
  "type": "git",
@@ -9,8 +9,8 @@
9
9
  "type": "module",
10
10
  "dependencies": {
11
11
  "@azure/identity": "4.13.1",
12
- "@microsoft/teams.api": "2.0.10",
13
- "@microsoft/teams.apps": "2.0.10",
12
+ "@microsoft/teams.api": "2.0.11",
13
+ "@microsoft/teams.apps": "2.0.11",
14
14
  "express": "5.2.1",
15
15
  "jsonwebtoken": "9.0.3",
16
16
  "jwks-rsa": "4.0.1",
@@ -22,7 +22,7 @@
22
22
  "openclaw": "workspace:*"
23
23
  },
24
24
  "peerDependencies": {
25
- "openclaw": ">=2026.5.14-beta.1"
25
+ "openclaw": ">=2026.5.14-beta.2"
26
26
  },
27
27
  "peerDependenciesMeta": {
28
28
  "openclaw": {
@@ -58,10 +58,10 @@
58
58
  "minHostVersion": ">=2026.4.10"
59
59
  },
60
60
  "compat": {
61
- "pluginApi": ">=2026.5.14-beta.1"
61
+ "pluginApi": ">=2026.5.14-beta.2"
62
62
  },
63
63
  "build": {
64
- "openclawVersion": "2026.5.14-beta.1"
64
+ "openclawVersion": "2026.5.14-beta.2"
65
65
  },
66
66
  "release": {
67
67
  "publishToClawHub": true,
@@ -1,134 +0,0 @@
1
- import { O as resolveNestedAllowlistDecision, S as normalizeChannelSlug, T as resolveChannelEntryMatchWithFallback, _ as isDangerousNameMatchingEnabled, i as buildChannelKeyCandidates, k as resolveToolsBySender, w as resolveAllowlistMatchSimple } from "./runtime-api-C3EIaIpt.js";
2
- //#region extensions/msteams/src/policy.ts
3
- function resolveMSTeamsRouteConfig(params) {
4
- const teamId = params.teamId?.trim();
5
- const teamName = params.teamName?.trim();
6
- const conversationId = params.conversationId?.trim();
7
- const channelName = params.channelName?.trim();
8
- const teams = params.cfg?.teams ?? {};
9
- const allowlistConfigured = Object.keys(teams).length > 0;
10
- const teamMatch = resolveChannelEntryMatchWithFallback({
11
- entries: teams,
12
- keys: buildChannelKeyCandidates(teamId, params.allowNameMatching ? teamName : void 0, params.allowNameMatching && teamName ? normalizeChannelSlug(teamName) : void 0),
13
- wildcardKey: "*",
14
- normalizeKey: normalizeChannelSlug
15
- });
16
- const teamConfig = teamMatch.entry;
17
- const channels = teamConfig?.channels ?? {};
18
- const channelAllowlistConfigured = Object.keys(channels).length > 0;
19
- const channelMatch = resolveChannelEntryMatchWithFallback({
20
- entries: channels,
21
- keys: buildChannelKeyCandidates(conversationId, params.allowNameMatching ? channelName : void 0, params.allowNameMatching && channelName ? normalizeChannelSlug(channelName) : void 0),
22
- wildcardKey: "*",
23
- normalizeKey: normalizeChannelSlug
24
- });
25
- const channelConfig = channelMatch.entry;
26
- return {
27
- teamConfig,
28
- channelConfig,
29
- allowlistConfigured,
30
- allowed: resolveNestedAllowlistDecision({
31
- outerConfigured: allowlistConfigured,
32
- outerMatched: Boolean(teamConfig),
33
- innerConfigured: channelAllowlistConfigured,
34
- innerMatched: Boolean(channelConfig)
35
- }),
36
- teamKey: teamMatch.matchKey ?? teamMatch.key,
37
- channelKey: channelMatch.matchKey ?? channelMatch.key,
38
- channelMatchKey: channelMatch.matchKey,
39
- channelMatchSource: channelMatch.matchSource === "direct" || channelMatch.matchSource === "wildcard" ? channelMatch.matchSource : void 0
40
- };
41
- }
42
- function resolveMSTeamsGroupToolPolicy(params) {
43
- const cfg = params.cfg.channels?.msteams;
44
- if (!cfg) return;
45
- const groupId = params.groupId?.trim();
46
- const groupChannel = params.groupChannel?.trim();
47
- const groupSpace = params.groupSpace?.trim();
48
- const allowNameMatching = isDangerousNameMatchingEnabled(cfg);
49
- const resolved = resolveMSTeamsRouteConfig({
50
- cfg,
51
- teamId: groupSpace,
52
- teamName: groupSpace,
53
- conversationId: groupId,
54
- channelName: groupChannel,
55
- allowNameMatching
56
- });
57
- if (resolved.channelConfig) {
58
- const senderPolicy = resolveToolsBySender({
59
- toolsBySender: resolved.channelConfig.toolsBySender,
60
- senderId: params.senderId,
61
- senderName: params.senderName,
62
- senderUsername: params.senderUsername,
63
- senderE164: params.senderE164
64
- });
65
- if (senderPolicy) return senderPolicy;
66
- if (resolved.channelConfig.tools) return resolved.channelConfig.tools;
67
- const teamSenderPolicy = resolveToolsBySender({
68
- toolsBySender: resolved.teamConfig?.toolsBySender,
69
- senderId: params.senderId,
70
- senderName: params.senderName,
71
- senderUsername: params.senderUsername,
72
- senderE164: params.senderE164
73
- });
74
- if (teamSenderPolicy) return teamSenderPolicy;
75
- return resolved.teamConfig?.tools;
76
- }
77
- if (resolved.teamConfig) {
78
- const teamSenderPolicy = resolveToolsBySender({
79
- toolsBySender: resolved.teamConfig.toolsBySender,
80
- senderId: params.senderId,
81
- senderName: params.senderName,
82
- senderUsername: params.senderUsername,
83
- senderE164: params.senderE164
84
- });
85
- if (teamSenderPolicy) return teamSenderPolicy;
86
- if (resolved.teamConfig.tools) return resolved.teamConfig.tools;
87
- }
88
- if (!groupId) return;
89
- const channelCandidates = buildChannelKeyCandidates(groupId, allowNameMatching ? groupChannel : void 0, allowNameMatching && groupChannel ? normalizeChannelSlug(groupChannel) : void 0);
90
- for (const teamConfig of Object.values(cfg.teams ?? {})) {
91
- const match = resolveChannelEntryMatchWithFallback({
92
- entries: teamConfig?.channels ?? {},
93
- keys: channelCandidates,
94
- wildcardKey: "*",
95
- normalizeKey: normalizeChannelSlug
96
- });
97
- if (match.entry) {
98
- const senderPolicy = resolveToolsBySender({
99
- toolsBySender: match.entry.toolsBySender,
100
- senderId: params.senderId,
101
- senderName: params.senderName,
102
- senderUsername: params.senderUsername,
103
- senderE164: params.senderE164
104
- });
105
- if (senderPolicy) return senderPolicy;
106
- if (match.entry.tools) return match.entry.tools;
107
- const teamSenderPolicy = resolveToolsBySender({
108
- toolsBySender: teamConfig?.toolsBySender,
109
- senderId: params.senderId,
110
- senderName: params.senderName,
111
- senderUsername: params.senderUsername,
112
- senderE164: params.senderE164
113
- });
114
- if (teamSenderPolicy) return teamSenderPolicy;
115
- return teamConfig?.tools;
116
- }
117
- }
118
- }
119
- function resolveMSTeamsAllowlistMatch(params) {
120
- return resolveAllowlistMatchSimple(params);
121
- }
122
- function resolveMSTeamsReplyPolicy(params) {
123
- if (params.isDirectMessage) return {
124
- requireMention: false,
125
- replyStyle: "thread"
126
- };
127
- const requireMention = params.channelConfig?.requireMention ?? params.teamConfig?.requireMention ?? params.globalConfig?.requireMention ?? true;
128
- return {
129
- requireMention,
130
- replyStyle: params.channelConfig?.replyStyle ?? params.teamConfig?.replyStyle ?? params.globalConfig?.replyStyle ?? (requireMention ? "thread" : "top-level")
131
- };
132
- }
133
- //#endregion
134
- export { resolveMSTeamsRouteConfig as i, resolveMSTeamsGroupToolPolicy as n, resolveMSTeamsReplyPolicy as r, resolveMSTeamsAllowlistMatch as t };
@@ -1,219 +0,0 @@
1
- import { c as normalizeQuery, f as resolveGraphToken, o as listChannelsForTeam, s as listTeamsByName, t as searchGraphUsers } from "./graph-users-OieoCBxW.js";
2
- import { mapAllowlistResolutionInputs } from "openclaw/plugin-sdk/allow-from";
3
- import { normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString } from "openclaw/plugin-sdk/string-coerce-runtime";
4
- //#region extensions/msteams/src/resolve-allowlist.ts
5
- function stripProviderPrefix(raw) {
6
- return raw.replace(/^(msteams|teams):/i, "");
7
- }
8
- function normalizeMSTeamsMessagingTarget(raw) {
9
- let trimmed = raw.trim();
10
- if (!trimmed) return;
11
- trimmed = stripProviderPrefix(trimmed).trim();
12
- if (/^conversation:/i.test(trimmed)) {
13
- const id = trimmed.slice(13).trim();
14
- return id ? `conversation:${id}` : void 0;
15
- }
16
- if (/^user:/i.test(trimmed)) {
17
- const id = trimmed.slice(5).trim();
18
- return id ? `user:${id}` : void 0;
19
- }
20
- return trimmed || void 0;
21
- }
22
- function normalizeMSTeamsUserInput(raw) {
23
- return stripProviderPrefix(raw).replace(/^(user|conversation):/i, "").trim();
24
- }
25
- function parseMSTeamsConversationId(raw) {
26
- const trimmed = stripProviderPrefix(raw).trim();
27
- if (!/^conversation:/i.test(trimmed)) return null;
28
- return trimmed.slice(13).trim();
29
- }
30
- /**
31
- * Detect whether a raw target string looks like a Microsoft Teams conversation
32
- * or user id that cron announce delivery and other explicit-target paths can
33
- * forward verbatim to the channel adapter.
34
- *
35
- * Accepts both prefixed and bare formats:
36
- * - `conversation:<id>` — explicit conversation prefix
37
- * - `user:<aad-guid>` — user id (16+ hex chars, UUID-like)
38
- * - `19:abc@thread.tacv2` / `19:abc@thread.skype` — channel / legacy group
39
- * - `19:{userId}_{appId}@unq.gbl.spaces` — Graph 1:1 chat thread format
40
- * - `a:1xxx` — Bot Framework personal (1:1) chat id
41
- * - `8:orgid:xxx` — Bot Framework org-scoped personal chat id
42
- * - `29:xxx` — Bot Framework user id
43
- *
44
- * Display-name user targets such as `user:John Smith` intentionally return
45
- * false so that the Graph API directory lookup still runs for them.
46
- */
47
- function looksLikeMSTeamsTargetId(raw) {
48
- const trimmed = raw.trim();
49
- if (!trimmed) return false;
50
- if (/^conversation:/i.test(trimmed)) return true;
51
- if (/^user:/i.test(trimmed)) {
52
- const id = trimmed.slice(5).trim();
53
- return /^[0-9a-fA-F-]{16,}$/.test(id);
54
- }
55
- if (/^19:.+@thread\.(tacv2|skype)$/i.test(trimmed)) return true;
56
- if (/^19:.+@unq\.gbl\.spaces$/i.test(trimmed)) return true;
57
- if (/^a:1[A-Za-z0-9_-]+$/i.test(trimmed)) return true;
58
- if (/^8:orgid:[A-Za-z0-9-]+$/i.test(trimmed)) return true;
59
- if (/^29:[A-Za-z0-9_-]+$/i.test(trimmed)) return true;
60
- return /@thread\b/i.test(trimmed);
61
- }
62
- function normalizeMSTeamsTeamKey(raw) {
63
- return stripProviderPrefix(raw).replace(/^team:/i, "").trim() || void 0;
64
- }
65
- function normalizeMSTeamsChannelKey(raw) {
66
- return (raw?.trim().replace(/^#/, "").trim() ?? "") || void 0;
67
- }
68
- function normalizeMSTeamsConversationTargetId(raw) {
69
- const trimmed = stripProviderPrefix(raw).trim();
70
- return parseMSTeamsConversationId(trimmed) ?? trimmed;
71
- }
72
- function looksLikeMSTeamsThreadConversationId(raw) {
73
- const normalized = normalizeMSTeamsConversationTargetId(raw);
74
- return /^19:.+@thread\./i.test(normalized);
75
- }
76
- function parseMSTeamsTeamChannelInput(raw) {
77
- const trimmed = stripProviderPrefix(raw).trim();
78
- if (!trimmed) return {};
79
- const parts = trimmed.split("/");
80
- const team = normalizeMSTeamsTeamKey(parts[0] ?? "");
81
- const channel = parts.length > 1 ? normalizeMSTeamsChannelKey(parts.slice(1).join("/")) : void 0;
82
- return {
83
- ...team ? { team } : {},
84
- ...channel ? { channel } : {}
85
- };
86
- }
87
- function parseMSTeamsTeamEntry(raw) {
88
- const { team, channel } = parseMSTeamsTeamChannelInput(raw);
89
- if (!team) return null;
90
- return {
91
- teamKey: team,
92
- ...channel ? { channelKey: channel } : {}
93
- };
94
- }
95
- async function resolveMSTeamsChannelAllowlist(params) {
96
- let tokenPromise;
97
- const getToken = () => {
98
- tokenPromise ??= resolveGraphToken(params.cfg);
99
- return tokenPromise;
100
- };
101
- return await mapAllowlistResolutionInputs({
102
- inputs: params.entries,
103
- mapInput: async (input) => {
104
- const { team, channel } = parseMSTeamsTeamChannelInput(input);
105
- if (!team) return {
106
- input,
107
- resolved: false
108
- };
109
- if (looksLikeMSTeamsThreadConversationId(team)) {
110
- const teamId = normalizeMSTeamsConversationTargetId(team);
111
- if (!channel) return {
112
- input,
113
- resolved: true,
114
- teamId,
115
- teamName: teamId
116
- };
117
- if (!looksLikeMSTeamsThreadConversationId(channel)) return {
118
- input,
119
- resolved: false,
120
- teamId,
121
- teamName: teamId,
122
- note: "channel id required for conversation-id team"
123
- };
124
- const channelId = normalizeMSTeamsConversationTargetId(channel);
125
- return {
126
- input,
127
- resolved: true,
128
- teamId,
129
- teamName: teamId,
130
- channelId,
131
- channelName: channelId
132
- };
133
- }
134
- const token = await getToken();
135
- const teams = /^[0-9a-fA-F-]{16,}$/.test(team) ? [{
136
- id: team,
137
- displayName: team
138
- }] : await listTeamsByName(token, team);
139
- if (teams.length === 0) return {
140
- input,
141
- resolved: false,
142
- note: "team not found"
143
- };
144
- const teamMatch = teams[0];
145
- const graphTeamId = teamMatch.id?.trim();
146
- const teamName = teamMatch.displayName?.trim() || team;
147
- if (!graphTeamId) return {
148
- input,
149
- resolved: false,
150
- note: "team id missing"
151
- };
152
- let teamChannels = [];
153
- try {
154
- teamChannels = await listChannelsForTeam(token, graphTeamId);
155
- } catch {}
156
- const teamId = teamChannels.find((ch) => normalizeOptionalLowercaseString(ch.displayName) === "general")?.id?.trim() || graphTeamId;
157
- if (!channel) return {
158
- input,
159
- resolved: true,
160
- teamId,
161
- teamName,
162
- note: teams.length > 1 ? "multiple teams; chose first" : void 0
163
- };
164
- const normalizedChannel = normalizeOptionalLowercaseString(channel);
165
- const channelMatch = teamChannels.find((item) => item.id === channel) ?? teamChannels.find((item) => normalizeOptionalLowercaseString(item.displayName) === normalizedChannel) ?? teamChannels.find((item) => normalizeLowercaseStringOrEmpty(item.displayName ?? "").includes(normalizedChannel ?? ""));
166
- if (!channelMatch?.id) return {
167
- input,
168
- resolved: false,
169
- note: "channel not found"
170
- };
171
- return {
172
- input,
173
- resolved: true,
174
- teamId,
175
- teamName,
176
- channelId: channelMatch.id,
177
- channelName: channelMatch.displayName ?? channel,
178
- note: teamChannels.length > 1 ? "multiple channels; chose first" : void 0
179
- };
180
- }
181
- });
182
- }
183
- async function resolveMSTeamsUserAllowlist(params) {
184
- const token = await resolveGraphToken(params.cfg);
185
- return await mapAllowlistResolutionInputs({
186
- inputs: params.entries,
187
- mapInput: async (input) => {
188
- const query = normalizeQuery(normalizeMSTeamsUserInput(input));
189
- if (!query) return {
190
- input,
191
- resolved: false
192
- };
193
- if (/^[0-9a-fA-F-]{16,}$/.test(query)) return {
194
- input,
195
- resolved: true,
196
- id: query
197
- };
198
- const users = await searchGraphUsers({
199
- token,
200
- query,
201
- top: 10
202
- });
203
- const match = users[0];
204
- if (!match?.id) return {
205
- input,
206
- resolved: false
207
- };
208
- return {
209
- input,
210
- resolved: true,
211
- id: match.id,
212
- name: match.displayName ?? void 0,
213
- note: users.length > 1 ? "multiple matches; chose first" : void 0
214
- };
215
- }
216
- });
217
- }
218
- //#endregion
219
- export { parseMSTeamsTeamChannelInput as a, resolveMSTeamsUserAllowlist as c, parseMSTeamsConversationId as i, normalizeMSTeamsMessagingTarget as n, parseMSTeamsTeamEntry as o, normalizeMSTeamsUserInput as r, resolveMSTeamsChannelAllowlist as s, looksLikeMSTeamsTargetId as t };