@openclaw/msteams 2026.5.7-beta.1 → 2026.5.9-beta.1
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 +2 -2
- package/dist/{channel-BOwKBAvY.js → channel-VjDbklu8.js} +45 -20
- package/dist/channel-plugin-api.js +1 -1
- package/dist/{channel.runtime-BC1ruIfN.js → channel.runtime-VrE9r2nS.js} +3 -3
- package/dist/{graph-users-9uQJepqr.js → graph-users-C9HaPg1v.js} +44 -24
- package/dist/{policy-DTnU2GR7.js → policy-D32Kf1ED.js} +1 -1
- package/dist/{probe-D_H8yFps.js → probe-Bs955MJZ.js} +83 -61
- package/dist/{resolve-allowlist-D41JSziq.js → resolve-allowlist-C23ohQKQ.js} +1 -1
- package/dist/{runtime-api-DV1iVMn1.js → runtime-api-D92XOrVf.js} +2 -2
- package/dist/runtime-api.js +2 -2
- package/dist/setup-plugin-api.js +2 -2
- package/dist/{setup-surface-BLkFQYIQ.js → setup-surface-BeztPcxk.js} +2 -2
- package/dist/{src-CP7V_TeZ.js → src-CiKTGSje.js} +137 -57
- package/dist/test-api.js +1 -1
- package/package.json +7 -7
package/dist/api.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { t as msteamsPlugin } from "./channel-
|
|
2
|
-
import { i as msteamsSetupAdapter, n as openDelegatedOAuthUrl, r as createMSTeamsSetupWizardBase, t as msteamsSetupWizard } from "./setup-surface-
|
|
1
|
+
import { t as msteamsPlugin } from "./channel-VjDbklu8.js";
|
|
2
|
+
import { i as msteamsSetupAdapter, n as openDelegatedOAuthUrl, r as createMSTeamsSetupWizardBase, t as msteamsSetupWizard } from "./setup-surface-BeztPcxk.js";
|
|
3
3
|
export { createMSTeamsSetupWizardBase, msteamsPlugin, msteamsSetupAdapter, msteamsSetupWizard, openDelegatedOAuthUrl };
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import { o as buildProbeChannelStatusSummary, r as PAIRING_APPROVED_MESSAGE, s as chunkTextForOutbound, t as DEFAULT_ACCOUNT_ID, u as createDefaultChannelRuntimeState } from "./runtime-api-
|
|
2
|
-
import { h as resolveMSTeamsCredentials } from "./graph-users-
|
|
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-
|
|
1
|
+
import { o as buildProbeChannelStatusSummary, r as PAIRING_APPROVED_MESSAGE, s as chunkTextForOutbound, t as DEFAULT_ACCOUNT_ID, u as createDefaultChannelRuntimeState } from "./runtime-api-D92XOrVf.js";
|
|
2
|
+
import { h as resolveMSTeamsCredentials } from "./graph-users-C9HaPg1v.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-C23ohQKQ.js";
|
|
4
4
|
import { t as MSTeamsChannelConfigSchema } from "./config-schema-DwOEthCC.js";
|
|
5
|
-
import { r as resolveMSTeamsGroupToolPolicy } from "./policy-
|
|
6
|
-
import { i as msteamsSetupAdapter, t as msteamsSetupWizard } from "./setup-surface-
|
|
5
|
+
import { r as resolveMSTeamsGroupToolPolicy } from "./policy-D32Kf1ED.js";
|
|
6
|
+
import { i as msteamsSetupAdapter, t as msteamsSetupWizard } from "./setup-surface-BeztPcxk.js";
|
|
7
7
|
import { describeAccountSnapshot } from "openclaw/plugin-sdk/account-helpers";
|
|
8
8
|
import { formatAllowFromLowercase } from "openclaw/plugin-sdk/allow-from";
|
|
9
9
|
import { createTopLevelChannelConfigAdapter } from "openclaw/plugin-sdk/channel-config-helpers";
|
|
10
10
|
import { buildChannelOutboundSessionRoute, createChatChannelPlugin, stripChannelTargetPrefix, stripTargetKindPrefix } from "openclaw/plugin-sdk/channel-core";
|
|
11
|
+
import { createChannelMessageAdapterFromOutbound } from "openclaw/plugin-sdk/channel-message";
|
|
11
12
|
import { createPairingPrefixStripper } from "openclaw/plugin-sdk/channel-pairing";
|
|
12
13
|
import { createAllowlistProviderGroupPolicyWarningCollector, createDangerousNameMatchingMutableAllowlistWarningCollector, projectConfigWarningCollector } from "openclaw/plugin-sdk/channel-policy";
|
|
13
14
|
import { createChannelDirectoryAdapter, createRuntimeDirectoryLiveAdapter, listDirectoryEntriesFromSources } from "openclaw/plugin-sdk/directory-runtime";
|
|
@@ -182,7 +183,7 @@ const collectMSTeamsSecurityWarnings = createAllowlistProviderGroupPolicyWarning
|
|
|
182
183
|
resolveGroupPolicy: ({ cfg }) => cfg.channels?.msteams?.groupPolicy,
|
|
183
184
|
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."] : []
|
|
184
185
|
});
|
|
185
|
-
const loadMSTeamsChannelRuntime = createLazyRuntimeNamedExport(() => import("./channel.runtime-
|
|
186
|
+
const loadMSTeamsChannelRuntime = createLazyRuntimeNamedExport(() => import("./channel.runtime-VrE9r2nS.js"), "msTeamsChannelRuntime");
|
|
186
187
|
const resolveMSTeamsChannelConfig = (cfg) => ({
|
|
187
188
|
allowFrom: cfg.channels?.msteams?.allowFrom,
|
|
188
189
|
defaultTo: cfg.channels?.msteams?.defaultTo
|
|
@@ -376,6 +377,41 @@ function describeMSTeamsMessageTool({ cfg }) {
|
|
|
376
377
|
} : null
|
|
377
378
|
};
|
|
378
379
|
}
|
|
380
|
+
const msteamsChannelOutbound = {
|
|
381
|
+
deliveryMode: "direct",
|
|
382
|
+
chunker: chunkTextForOutbound,
|
|
383
|
+
chunkerMode: "markdown",
|
|
384
|
+
textChunkLimit: 4e3,
|
|
385
|
+
pollMaxOptions: 12,
|
|
386
|
+
deliveryCapabilities: { durableFinal: {
|
|
387
|
+
text: true,
|
|
388
|
+
media: true,
|
|
389
|
+
messageSendingHooks: true
|
|
390
|
+
} },
|
|
391
|
+
...createRuntimeOutboundDelegates({
|
|
392
|
+
getRuntime: loadMSTeamsChannelRuntime,
|
|
393
|
+
sendText: { resolve: (runtime) => runtime.msteamsOutbound.sendText },
|
|
394
|
+
sendMedia: { resolve: (runtime) => runtime.msteamsOutbound.sendMedia },
|
|
395
|
+
sendPoll: { resolve: (runtime) => runtime.msteamsOutbound.sendPoll }
|
|
396
|
+
})
|
|
397
|
+
};
|
|
398
|
+
const msteamsMessageAdapter = createChannelMessageAdapterFromOutbound({
|
|
399
|
+
id: "msteams",
|
|
400
|
+
outbound: msteamsChannelOutbound,
|
|
401
|
+
live: {
|
|
402
|
+
capabilities: {
|
|
403
|
+
draftPreview: true,
|
|
404
|
+
previewFinalization: true,
|
|
405
|
+
progressUpdates: true,
|
|
406
|
+
nativeStreaming: true
|
|
407
|
+
},
|
|
408
|
+
finalizer: { capabilities: {
|
|
409
|
+
finalEdit: true,
|
|
410
|
+
normalFallback: true,
|
|
411
|
+
previewReceipt: true
|
|
412
|
+
} }
|
|
413
|
+
}
|
|
414
|
+
});
|
|
379
415
|
const msteamsPlugin = createChatChannelPlugin({
|
|
380
416
|
base: {
|
|
381
417
|
id: "msteams",
|
|
@@ -428,6 +464,7 @@ const msteamsPlugin = createChatChannelPlugin({
|
|
|
428
464
|
hint: "<conversationId|user:ID|conversation:ID>"
|
|
429
465
|
}
|
|
430
466
|
},
|
|
467
|
+
message: msteamsMessageAdapter,
|
|
431
468
|
directory: createChannelDirectoryAdapter({
|
|
432
469
|
self: async ({ cfg }) => {
|
|
433
470
|
const creds = resolveMSTeamsCredentials(cfg.channels?.msteams);
|
|
@@ -928,7 +965,7 @@ const msteamsPlugin = createChatChannelPlugin({
|
|
|
928
965
|
})
|
|
929
966
|
}),
|
|
930
967
|
gateway: { startAccount: async (ctx) => {
|
|
931
|
-
const { monitorMSTeamsProvider } = await import("./src-
|
|
968
|
+
const { monitorMSTeamsProvider } = await import("./src-CiKTGSje.js");
|
|
932
969
|
const port = ctx.cfg.channels?.msteams?.webhook?.port ?? 3978;
|
|
933
970
|
ctx.setStatus({
|
|
934
971
|
accountId: ctx.accountId,
|
|
@@ -966,19 +1003,7 @@ const msteamsPlugin = createChatChannelPlugin({
|
|
|
966
1003
|
hasRepliedRef
|
|
967
1004
|
};
|
|
968
1005
|
} },
|
|
969
|
-
outbound:
|
|
970
|
-
deliveryMode: "direct",
|
|
971
|
-
chunker: chunkTextForOutbound,
|
|
972
|
-
chunkerMode: "markdown",
|
|
973
|
-
textChunkLimit: 4e3,
|
|
974
|
-
pollMaxOptions: 12,
|
|
975
|
-
...createRuntimeOutboundDelegates({
|
|
976
|
-
getRuntime: loadMSTeamsChannelRuntime,
|
|
977
|
-
sendText: { resolve: (runtime) => runtime.msteamsOutbound.sendText },
|
|
978
|
-
sendMedia: { resolve: (runtime) => runtime.msteamsOutbound.sendMedia },
|
|
979
|
-
sendPoll: { resolve: (runtime) => runtime.msteamsOutbound.sendPoll }
|
|
980
|
-
})
|
|
981
|
-
}
|
|
1006
|
+
outbound: msteamsChannelOutbound
|
|
982
1007
|
});
|
|
983
1008
|
//#endregion
|
|
984
1009
|
export { msteamsPlugin as t };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as msteamsPlugin } from "./channel-
|
|
1
|
+
import { t as msteamsPlugin } from "./channel-VjDbklu8.js";
|
|
2
2
|
export { msteamsPlugin };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { s as chunkTextForOutbound } from "./runtime-api-
|
|
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-
|
|
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-
|
|
1
|
+
import { s as chunkTextForOutbound } from "./runtime-api-D92XOrVf.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-C9HaPg1v.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-Bs955MJZ.js";
|
|
4
4
|
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime";
|
|
5
5
|
import { createAttachedChannelResultAdapter } from "openclaw/plugin-sdk/channel-send-result";
|
|
6
6
|
import { resolveOutboundSendDep } from "openclaw/plugin-sdk/outbound-send-deps";
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
import { L as getMSTeamsRuntime, g as fetchWithSsrFGuard$1 } from "./runtime-api-
|
|
1
|
+
import { L as getMSTeamsRuntime, g as fetchWithSsrFGuard$1 } from "./runtime-api-D92XOrVf.js";
|
|
2
2
|
import { n as refreshMSTeamsDelegatedTokens } from "./oauth.token-xxpoLWy5.js";
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
|
-
import { isRecord as isRecord$
|
|
4
|
+
import { isRecord as isRecord$2, normalizeLowercaseStringOrEmpty, normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime";
|
|
5
5
|
import { fetchWithSsrFGuard } from "openclaw/plugin-sdk/ssrf-runtime";
|
|
6
6
|
import { Buffer } from "node:buffer";
|
|
7
7
|
import { lookup } from "node:dns/promises";
|
|
8
8
|
import { buildHostnameAllowlistPolicyFromSuffixAllowlist, isHttpsUrlAllowedByHostnameSuffixAllowlist, isPrivateIpAddress, normalizeHostnameSuffixAllowlist } from "openclaw/plugin-sdk/ssrf-policy";
|
|
9
|
-
import * as fs
|
|
10
|
-
import {
|
|
11
|
-
import path, { dirname } from "node:path";
|
|
9
|
+
import * as fs from "node:fs";
|
|
10
|
+
import { readFileSync } from "node:fs";
|
|
11
|
+
import path, { basename, dirname } from "node:path";
|
|
12
|
+
import { privateFileStoreSync } from "openclaw/plugin-sdk/security-runtime";
|
|
12
13
|
import { hasConfiguredSecretInput, normalizeResolvedSecretInputString, normalizeSecretInputString } from "openclaw/plugin-sdk/secret-input";
|
|
13
14
|
//#region extensions/msteams/src/attachments/shared.ts
|
|
14
15
|
const IMAGE_EXT_RE = /\.(avif|bmp|gif|heic|heif|jpe?g|png|tiff?|webp)$/i;
|
|
@@ -122,7 +123,7 @@ function tryBuildGraphSharesUrlForSharedLink(url) {
|
|
|
122
123
|
function readNestedString(value, keys) {
|
|
123
124
|
let current = value;
|
|
124
125
|
for (const key of keys) {
|
|
125
|
-
if (!isRecord$
|
|
126
|
+
if (!isRecord$2(current)) return;
|
|
126
127
|
current = current[key];
|
|
127
128
|
}
|
|
128
129
|
return normalizeOptionalString(current);
|
|
@@ -153,7 +154,7 @@ function isLikelyImageAttachment(att) {
|
|
|
153
154
|
const name = typeof att.name === "string" ? att.name : "";
|
|
154
155
|
if (contentType.startsWith("image/")) return true;
|
|
155
156
|
if (IMAGE_EXT_RE.test(name)) return true;
|
|
156
|
-
if (contentType === "application/vnd.microsoft.teams.file.download.info" && isRecord$
|
|
157
|
+
if (contentType === "application/vnd.microsoft.teams.file.download.info" && isRecord$2(att.content)) {
|
|
157
158
|
const fileType = typeof att.content.fileType === "string" ? att.content.fileType : "";
|
|
158
159
|
if (fileType && IMAGE_EXT_RE.test(`x.${fileType}`)) return true;
|
|
159
160
|
const fileName = typeof att.content.fileName === "string" ? att.content.fileName : "";
|
|
@@ -166,7 +167,7 @@ function isLikelyImageAttachment(att) {
|
|
|
166
167
|
* Used when downloading all files, not just images.
|
|
167
168
|
*/
|
|
168
169
|
function isDownloadableAttachment(att) {
|
|
169
|
-
if ((normalizeContentType(att.contentType) ?? "") === "application/vnd.microsoft.teams.file.download.info" && isRecord$
|
|
170
|
+
if ((normalizeContentType(att.contentType) ?? "") === "application/vnd.microsoft.teams.file.download.info" && isRecord$2(att.content) && typeof att.content.downloadUrl === "string") return true;
|
|
170
171
|
if (typeof att.contentUrl === "string" && att.contentUrl.trim()) return true;
|
|
171
172
|
return false;
|
|
172
173
|
}
|
|
@@ -176,7 +177,7 @@ function isHtmlAttachment(att) {
|
|
|
176
177
|
function extractHtmlFromAttachment(att) {
|
|
177
178
|
if (!isHtmlAttachment(att)) return;
|
|
178
179
|
if (typeof att.content === "string") return att.content;
|
|
179
|
-
if (!isRecord$
|
|
180
|
+
if (!isRecord$2(att.content)) return;
|
|
180
181
|
return typeof att.content.text === "string" ? att.content.text : typeof att.content.body === "string" ? att.content.body : typeof att.content.content === "string" ? att.content.content : void 0;
|
|
181
182
|
}
|
|
182
183
|
function isLikelyBase64Payload(value) {
|
|
@@ -387,7 +388,7 @@ async function safeFetchWithPolicy(params) {
|
|
|
387
388
|
}
|
|
388
389
|
//#endregion
|
|
389
390
|
//#region extensions/msteams/src/errors.ts
|
|
390
|
-
function isRecord(value) {
|
|
391
|
+
function isRecord$1(value) {
|
|
391
392
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
392
393
|
}
|
|
393
394
|
function formatUnknownError(err) {
|
|
@@ -405,7 +406,7 @@ function formatUnknownError(err) {
|
|
|
405
406
|
}
|
|
406
407
|
}
|
|
407
408
|
function extractStatusCode(err) {
|
|
408
|
-
if (!isRecord(err)) return null;
|
|
409
|
+
if (!isRecord$1(err)) return null;
|
|
409
410
|
const direct = err.statusCode ?? err.status;
|
|
410
411
|
if (typeof direct === "number" && Number.isFinite(direct)) return direct;
|
|
411
412
|
if (typeof direct === "string") {
|
|
@@ -413,7 +414,7 @@ function extractStatusCode(err) {
|
|
|
413
414
|
if (Number.isFinite(parsed)) return parsed;
|
|
414
415
|
}
|
|
415
416
|
const response = err.response;
|
|
416
|
-
if (isRecord(response)) {
|
|
417
|
+
if (isRecord$1(response)) {
|
|
417
418
|
const status = response.status;
|
|
418
419
|
if (typeof status === "number" && Number.isFinite(status)) return status;
|
|
419
420
|
if (typeof status === "string") {
|
|
@@ -424,20 +425,20 @@ function extractStatusCode(err) {
|
|
|
424
425
|
return null;
|
|
425
426
|
}
|
|
426
427
|
function extractErrorCode(err) {
|
|
427
|
-
if (!isRecord(err)) return null;
|
|
428
|
+
if (!isRecord$1(err)) return null;
|
|
428
429
|
const direct = err.code;
|
|
429
430
|
if (typeof direct === "string" && direct.trim()) return direct;
|
|
430
431
|
const response = err.response;
|
|
431
|
-
if (!isRecord(response)) return null;
|
|
432
|
+
if (!isRecord$1(response)) return null;
|
|
432
433
|
const body = response.body;
|
|
433
|
-
if (isRecord(body)) {
|
|
434
|
+
if (isRecord$1(body)) {
|
|
434
435
|
const error = body.error;
|
|
435
|
-
if (isRecord(error) && typeof error.code === "string" && error.code.trim()) return error.code;
|
|
436
|
+
if (isRecord$1(error) && typeof error.code === "string" && error.code.trim()) return error.code;
|
|
436
437
|
}
|
|
437
438
|
return null;
|
|
438
439
|
}
|
|
439
440
|
function extractRetryAfterMs(err) {
|
|
440
|
-
if (!isRecord(err)) return null;
|
|
441
|
+
if (!isRecord$1(err)) return null;
|
|
441
442
|
const direct = err.retryAfterMs ?? err.retry_after_ms;
|
|
442
443
|
if (typeof direct === "number" && Number.isFinite(direct) && direct >= 0) return direct;
|
|
443
444
|
const retryAfter = err.retryAfter ?? err.retry_after;
|
|
@@ -447,10 +448,10 @@ function extractRetryAfterMs(err) {
|
|
|
447
448
|
if (Number.isFinite(parsed) && parsed >= 0) return parsed * 1e3;
|
|
448
449
|
}
|
|
449
450
|
const response = err.response;
|
|
450
|
-
if (!isRecord(response)) return null;
|
|
451
|
+
if (!isRecord$1(response)) return null;
|
|
451
452
|
const headers = response.headers;
|
|
452
453
|
if (!headers) return null;
|
|
453
|
-
if (isRecord(headers)) {
|
|
454
|
+
if (isRecord$1(headers)) {
|
|
454
455
|
const raw = headers["retry-after"] ?? headers["Retry-After"];
|
|
455
456
|
if (typeof raw === "string") {
|
|
456
457
|
const parsed = Number.parseFloat(raw);
|
|
@@ -512,6 +513,13 @@ function classifyMSTeamsSendError(err) {
|
|
|
512
513
|
statusCode,
|
|
513
514
|
errorCode
|
|
514
515
|
};
|
|
516
|
+
if (statusCode == null) {
|
|
517
|
+
const networkCode = isRecord$1(err) && typeof err.code === "string" ? err.code : null;
|
|
518
|
+
if (networkCode === "ECONNREFUSED" || networkCode === "ENOTFOUND" || networkCode === "EHOSTUNREACH" || networkCode === "ETIMEDOUT" || networkCode === "ECONNRESET") return {
|
|
519
|
+
kind: "network",
|
|
520
|
+
errorCode: networkCode
|
|
521
|
+
};
|
|
522
|
+
}
|
|
515
523
|
return {
|
|
516
524
|
kind: "unknown",
|
|
517
525
|
statusCode: statusCode ?? void 0,
|
|
@@ -536,6 +544,7 @@ function formatMSTeamsSendErrorHint(classification) {
|
|
|
536
544
|
if (classification.errorCode === "ContentStreamNotAllowed") return "Teams expired the content stream; stop streaming earlier and fall back to normal message delivery";
|
|
537
545
|
if (classification.kind === "throttled") return "Teams throttled the bot; backing off may help";
|
|
538
546
|
if (classification.kind === "transient") return "transient Teams/Bot Framework error; retry may succeed";
|
|
547
|
+
if (classification.kind === "network") return "transport-level failure sending reply to Teams Bot Connector (smba.trafficmanager.net) — check egress firewall rules allow outbound HTTPS to smba.trafficmanager.net";
|
|
539
548
|
}
|
|
540
549
|
//#endregion
|
|
541
550
|
//#region extensions/msteams/src/user-agent.ts
|
|
@@ -617,7 +626,7 @@ function createFederatedApp(creds, sdk) {
|
|
|
617
626
|
if (!creds.certificatePath) throw new Error("Federated credentials require either a certificate path or managed identity.");
|
|
618
627
|
let privateKey;
|
|
619
628
|
try {
|
|
620
|
-
privateKey = fs
|
|
629
|
+
privateKey = fs.readFileSync(creds.certificatePath, "utf-8");
|
|
621
630
|
} catch (err) {
|
|
622
631
|
const msg = err instanceof Error ? err.message : String(err);
|
|
623
632
|
throw new Error(`Failed to read certificate file at '${creds.certificatePath}': ${msg}`, { cause: err });
|
|
@@ -1045,11 +1054,23 @@ async function createBotFrameworkJwtValidator(creds) {
|
|
|
1045
1054
|
if (!isJwtPayloadObject(verifiedPayload)) return false;
|
|
1046
1055
|
if (getAudienceClaims(verifiedPayload).includes(BOT_FRAMEWORK_GLOBAL_AUDIENCE) && !hasExpectedBotIdentity(verifiedPayload, creds.appId)) return false;
|
|
1047
1056
|
return true;
|
|
1048
|
-
} catch {
|
|
1057
|
+
} catch (err) {
|
|
1058
|
+
if (isJwksNetworkError(err)) throw err;
|
|
1049
1059
|
return false;
|
|
1050
1060
|
}
|
|
1051
1061
|
} };
|
|
1052
1062
|
}
|
|
1063
|
+
/**
|
|
1064
|
+
* Return true when the error originated from a network-level failure fetching
|
|
1065
|
+
* the JWKS endpoint (DNS resolution, connection refused, TLS handshake, etc.)
|
|
1066
|
+
* rather than from token verification logic.
|
|
1067
|
+
*/
|
|
1068
|
+
function isJwksNetworkError(err) {
|
|
1069
|
+
if (!(err instanceof Error)) return false;
|
|
1070
|
+
const code = err.code;
|
|
1071
|
+
if (code === "ECONNREFUSED" || code === "ENOTFOUND" || code === "EHOSTUNREACH" || code === "ETIMEDOUT" || code === "ECONNRESET") return true;
|
|
1072
|
+
return /jwks|key fetch|getSigningKey/i.test(err.message) && /network|fetch|connect/i.test(err.message);
|
|
1073
|
+
}
|
|
1053
1074
|
//#endregion
|
|
1054
1075
|
//#region extensions/msteams/src/token-response.ts
|
|
1055
1076
|
function readAccessToken(value) {
|
|
@@ -1135,8 +1156,7 @@ function loadDelegatedTokens() {
|
|
|
1135
1156
|
}
|
|
1136
1157
|
function saveDelegatedTokens(tokens) {
|
|
1137
1158
|
const tokenPath = resolveDelegatedTokenPath();
|
|
1138
|
-
|
|
1139
|
-
writeFileSync(tokenPath, JSON.stringify(tokens, null, 2), "utf8");
|
|
1159
|
+
privateFileStoreSync(dirname(tokenPath)).writeJson(basename(tokenPath), tokens);
|
|
1140
1160
|
}
|
|
1141
1161
|
async function resolveDelegatedAccessToken(params) {
|
|
1142
1162
|
const tokens = loadDelegatedTokens();
|
|
@@ -1351,4 +1371,4 @@ async function searchGraphUsers(params) {
|
|
|
1351
1371
|
})).value ?? [];
|
|
1352
1372
|
}
|
|
1353
1373
|
//#endregion
|
|
1354
|
-
export { ATTACHMENT_TAG_RE as A, isLikelyImageAttachment as B, loadMSTeamsSdkWithAuth as C, formatMSTeamsSendErrorHint as D, classifyMSTeamsSendError as E, estimateBase64DecodedBytes as F, resolveAttachmentFetchPolicy as G, isUrlAllowed as H, extractHtmlFromAttachment as I, safeFetchWithPolicy as J, resolveMediaSsrfPolicy as K, extractInlineImageCandidates as L, IMG_SRC_RE as M, applyAuthorizationHeaderForUrl as N, formatUnknownError as O, encodeGraphShareId as P, inferPlaceholder as R, createMSTeamsTokenProvider as S, ensureUserAgentHeader as T, normalizeContentType as U, isRecord$
|
|
1374
|
+
export { ATTACHMENT_TAG_RE as A, isLikelyImageAttachment as B, loadMSTeamsSdkWithAuth as C, formatMSTeamsSendErrorHint as D, classifyMSTeamsSendError as E, estimateBase64DecodedBytes as F, resolveAttachmentFetchPolicy as G, isUrlAllowed as H, extractHtmlFromAttachment as I, safeFetchWithPolicy as J, resolveMediaSsrfPolicy as K, extractInlineImageCandidates as L, IMG_SRC_RE as M, applyAuthorizationHeaderForUrl as N, formatUnknownError as O, encodeGraphShareId as P, inferPlaceholder as R, createMSTeamsTokenProvider as S, ensureUserAgentHeader as T, normalizeContentType as U, isRecord$2 as V, readNestedString as W, tryBuildGraphSharesUrlForSharedLink as X, safeHostForUrl as Y, resolveMSTeamsStorePath as _, fetchGraphJson as a, createBotFrameworkJwtValidator as b, normalizeQuery as c, postGraphJson as d, resolveGraphToken as f, saveDelegatedTokens as g, resolveMSTeamsCredentials as h, fetchGraphAbsoluteUrl as i, GRAPH_ROOT as j, isRevokedProxyError as k, patchGraphJson as l, loadDelegatedTokens as m, deleteGraphRequest as n, listChannelsForTeam as o, hasConfiguredMSTeamsCredentials as p, resolveRequestUrl as q, escapeOData as r, listTeamsByName as s, searchGraphUsers as t, postGraphBetaJson as u, normalizeSecretInputString as v, buildUserAgent as w, createMSTeamsAdapter as x, readAccessToken as y, isDownloadableAttachment as z };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { C as normalizeChannelSlug, D as resolveChannelEntryMatchWithFallback, E as resolveAllowlistMatchSimple, M as resolveNestedAllowlistDecision, P as resolveToolsBySender, i as buildChannelKeyCandidates, p as evaluateSenderGroupAccessForPolicy, v as isDangerousNameMatchingEnabled } from "./runtime-api-
|
|
1
|
+
import { C as normalizeChannelSlug, D as resolveChannelEntryMatchWithFallback, E as resolveAllowlistMatchSimple, M as resolveNestedAllowlistDecision, P as resolveToolsBySender, i as buildChannelKeyCandidates, p as evaluateSenderGroupAccessForPolicy, v as isDangerousNameMatchingEnabled } from "./runtime-api-D92XOrVf.js";
|
|
2
2
|
//#region extensions/msteams/src/policy.ts
|
|
3
3
|
function resolveMSTeamsRouteConfig(params) {
|
|
4
4
|
const teamId = params.teamId?.trim();
|
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
import { L as getMSTeamsRuntime, O as resolveChannelMediaMaxBytes, _ as getFileExtension, b as loadOutboundMediaFromUrl, d as detectMime, h as extractOriginalFilename, m as extensionForMime, w as normalizeStringEntries } from "./runtime-api-
|
|
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-
|
|
3
|
-
import {
|
|
1
|
+
import { L as getMSTeamsRuntime, O as resolveChannelMediaMaxBytes, _ as getFileExtension, b as loadOutboundMediaFromUrl, d as detectMime, h as extractOriginalFilename, m as extensionForMime, w as normalizeStringEntries } from "./runtime-api-D92XOrVf.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-C9HaPg1v.js";
|
|
3
|
+
import { a as resolveMSTeamsRouteConfig, i as resolveMSTeamsReplyPolicy } from "./policy-D32Kf1ED.js";
|
|
4
|
+
import { createMessageReceiptFromOutboundResults } from "openclaw/plugin-sdk/channel-message";
|
|
5
|
+
import { convertMarkdownTables, isRecord, normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString, sleep } from "openclaw/plugin-sdk/text-runtime";
|
|
4
6
|
import { withFileLock } from "openclaw/plugin-sdk/file-lock";
|
|
5
7
|
import { resolveSendableOutboundReplyParts } from "openclaw/plugin-sdk/reply-payload";
|
|
6
8
|
import { lookup } from "node:dns/promises";
|
|
7
|
-
import
|
|
9
|
+
import { isPrivateIpAddress } from "openclaw/plugin-sdk/ssrf-policy";
|
|
8
10
|
import path from "node:path";
|
|
11
|
+
import { pathExists } from "openclaw/plugin-sdk/security-runtime";
|
|
9
12
|
import { readJsonFileWithFallback, writeJsonFileAtomically } from "openclaw/plugin-sdk/json-store";
|
|
10
13
|
import crypto from "node:crypto";
|
|
11
14
|
import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/markdown-table-runtime";
|
|
@@ -72,11 +75,7 @@ async function writeJsonFile(filePath, value) {
|
|
|
72
75
|
await writeJsonFileAtomically(filePath, value);
|
|
73
76
|
}
|
|
74
77
|
async function ensureJsonFile(filePath, fallback) {
|
|
75
|
-
|
|
76
|
-
await fs.promises.access(filePath);
|
|
77
|
-
} catch {
|
|
78
|
-
await writeJsonFile(filePath, fallback);
|
|
79
|
-
}
|
|
78
|
+
if (!await pathExists(filePath)) await writeJsonFile(filePath, fallback);
|
|
80
79
|
}
|
|
81
80
|
async function withFileLock$1(filePath, fallback, fn) {
|
|
82
81
|
await ensureJsonFile(filePath, fallback);
|
|
@@ -182,14 +181,6 @@ function createMSTeamsConversationStoreFs(params) {
|
|
|
182
181
|
const STORE_FILENAME$1 = "msteams-polls.json";
|
|
183
182
|
const MAX_POLLS = 1e3;
|
|
184
183
|
const POLL_TTL_MS = 720 * 60 * 60 * 1e3;
|
|
185
|
-
function isRecord(value) {
|
|
186
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
187
|
-
}
|
|
188
|
-
function normalizeOptionalString$1(value) {
|
|
189
|
-
if (typeof value !== "string") return;
|
|
190
|
-
const trimmed = value.trim();
|
|
191
|
-
return trimmed ? trimmed : void 0;
|
|
192
|
-
}
|
|
193
184
|
function normalizeChoiceValue(value) {
|
|
194
185
|
if (typeof value === "string") {
|
|
195
186
|
const trimmed = value.trim();
|
|
@@ -214,7 +205,7 @@ function readNestedValue(value, keys) {
|
|
|
214
205
|
return current;
|
|
215
206
|
}
|
|
216
207
|
function readNestedString(value, keys) {
|
|
217
|
-
return normalizeOptionalString
|
|
208
|
+
return normalizeOptionalString(readNestedValue(value, keys));
|
|
218
209
|
}
|
|
219
210
|
function extractMSTeamsPollVote(activity) {
|
|
220
211
|
const value = activity?.value;
|
|
@@ -395,9 +386,6 @@ function createMSTeamsPollStoreFs(params) {
|
|
|
395
386
|
* - Building FileInfoCard attachments (to confirm upload completion)
|
|
396
387
|
* - Parsing fileConsent/invoke activities
|
|
397
388
|
*/
|
|
398
|
-
function normalizeLowercaseStringOrEmpty$1(value) {
|
|
399
|
-
return typeof value === "string" ? value.trim().toLowerCase() : "";
|
|
400
|
-
}
|
|
401
389
|
/**
|
|
402
390
|
* Allowlist of domains that are valid targets for file consent uploads.
|
|
403
391
|
* These are the Microsoft/SharePoint domains that Teams legitimately provides
|
|
@@ -418,31 +406,10 @@ const CONSENT_UPLOAD_HOST_ALLOWLIST = [
|
|
|
418
406
|
"graph.microsoft.cn"
|
|
419
407
|
];
|
|
420
408
|
/**
|
|
421
|
-
* Returns true if the given IPv4 or IPv6 address is
|
|
422
|
-
*
|
|
409
|
+
* Returns true if the given IPv4 or IPv6 address is private, internal, or
|
|
410
|
+
* special-use and must never be reached via consent uploads.
|
|
423
411
|
*/
|
|
424
|
-
|
|
425
|
-
const ipv4MappedMatch = /^::ffff:(\d+\.\d+\.\d+\.\d+)$/i.exec(ip);
|
|
426
|
-
if (ipv4MappedMatch) return isPrivateOrReservedIP(ipv4MappedMatch[1]);
|
|
427
|
-
const v4Parts = ip.split(".");
|
|
428
|
-
if (v4Parts.length === 4) {
|
|
429
|
-
const octets = v4Parts.map(Number);
|
|
430
|
-
if (octets.some((n) => !Number.isInteger(n) || n < 0 || n > 255)) return false;
|
|
431
|
-
const [a, b] = octets;
|
|
432
|
-
if (a === 10) return true;
|
|
433
|
-
if (a === 172 && b >= 16 && b <= 31) return true;
|
|
434
|
-
if (a === 192 && b === 168) return true;
|
|
435
|
-
if (a === 127) return true;
|
|
436
|
-
if (a === 169 && b === 254) return true;
|
|
437
|
-
if (a === 0) return true;
|
|
438
|
-
}
|
|
439
|
-
const normalized = normalizeLowercaseStringOrEmpty$1(ip);
|
|
440
|
-
if (normalized === "::1") return true;
|
|
441
|
-
if (normalized.startsWith("fe80:") || normalized.startsWith("fe80")) return true;
|
|
442
|
-
if (normalized.startsWith("fc") || normalized.startsWith("fd")) return true;
|
|
443
|
-
if (normalized === "::") return true;
|
|
444
|
-
return false;
|
|
445
|
-
}
|
|
412
|
+
const isPrivateOrReservedIP = isPrivateIpAddress;
|
|
446
413
|
/**
|
|
447
414
|
* Validate that a consent upload URL is safe to PUT to.
|
|
448
415
|
* Checks:
|
|
@@ -460,7 +427,7 @@ async function validateConsentUploadUrl(url, opts) {
|
|
|
460
427
|
throw new Error("Consent upload URL is not a valid URL");
|
|
461
428
|
}
|
|
462
429
|
if (parsed.protocol !== "https:") throw new Error(`Consent upload URL must use HTTPS, got ${parsed.protocol}`);
|
|
463
|
-
const hostname = normalizeLowercaseStringOrEmpty
|
|
430
|
+
const hostname = normalizeLowercaseStringOrEmpty(parsed.hostname);
|
|
464
431
|
if (!(opts?.allowlist ?? CONSENT_UPLOAD_HOST_ALLOWLIST).some((entry) => hostname === entry || hostname.endsWith(`.${entry}`))) throw new Error(`Consent upload URL hostname "${hostname}" is not in the allowed domains`);
|
|
465
432
|
const resolveFn = opts?.resolveFn ?? ((name) => lookup(name, { all: true }));
|
|
466
433
|
let resolved;
|
|
@@ -1554,7 +1521,7 @@ async function sendMSTeamsMessages(params) {
|
|
|
1554
1521
|
const resolvedThreadId = params.conversationRef.threadId ?? params.conversationRef.activityId;
|
|
1555
1522
|
if (params.replyStyle === "thread") {
|
|
1556
1523
|
const ctx = params.context;
|
|
1557
|
-
if (!ctx)
|
|
1524
|
+
if (!ctx) return await sendProactively(messages, 0, resolvedThreadId);
|
|
1558
1525
|
const messageIds = [];
|
|
1559
1526
|
for (const [idx, message] of messages.entries()) {
|
|
1560
1527
|
const result = await withRevokedProxyFallback({
|
|
@@ -1579,6 +1546,23 @@ async function sendMSTeamsMessages(params) {
|
|
|
1579
1546
|
}
|
|
1580
1547
|
//#endregion
|
|
1581
1548
|
//#region extensions/msteams/src/send-context.ts
|
|
1549
|
+
function resolveMSTeamsProactiveReplyStyle(params) {
|
|
1550
|
+
const threadRootId = params.ref.threadId ?? params.ref.activityId;
|
|
1551
|
+
if (params.conversationType !== "channel" || !threadRootId) return "top-level";
|
|
1552
|
+
const routeConfig = resolveMSTeamsRouteConfig({
|
|
1553
|
+
cfg: params.cfg,
|
|
1554
|
+
teamId: params.ref.teamId,
|
|
1555
|
+
conversationId: params.conversationId,
|
|
1556
|
+
allowNameMatching: false
|
|
1557
|
+
});
|
|
1558
|
+
const { replyStyle } = resolveMSTeamsReplyPolicy({
|
|
1559
|
+
isDirectMessage: false,
|
|
1560
|
+
globalConfig: params.cfg,
|
|
1561
|
+
teamConfig: routeConfig.teamConfig,
|
|
1562
|
+
channelConfig: routeConfig.channelConfig
|
|
1563
|
+
});
|
|
1564
|
+
return replyStyle;
|
|
1565
|
+
}
|
|
1582
1566
|
/**
|
|
1583
1567
|
* Parse the target value into a conversation reference lookup key.
|
|
1584
1568
|
* Supported formats:
|
|
@@ -1646,6 +1630,12 @@ async function resolveMSTeamsSendContext(params) {
|
|
|
1646
1630
|
if (storedConversationType === "personal") conversationType = "personal";
|
|
1647
1631
|
else if (storedConversationType === "channel") conversationType = "channel";
|
|
1648
1632
|
else conversationType = "groupChat";
|
|
1633
|
+
const replyStyle = resolveMSTeamsProactiveReplyStyle({
|
|
1634
|
+
cfg: msteamsCfg,
|
|
1635
|
+
conversationId,
|
|
1636
|
+
ref,
|
|
1637
|
+
conversationType
|
|
1638
|
+
});
|
|
1649
1639
|
const sharePointSiteId = msteamsCfg.sharePointSiteId;
|
|
1650
1640
|
const mediaMaxBytes = resolveChannelMediaMaxBytes({
|
|
1651
1641
|
cfg: params.cfg,
|
|
@@ -1678,6 +1668,7 @@ async function resolveMSTeamsSendContext(params) {
|
|
|
1678
1668
|
adapter,
|
|
1679
1669
|
log,
|
|
1680
1670
|
conversationType,
|
|
1671
|
+
replyStyle,
|
|
1681
1672
|
tokenProvider,
|
|
1682
1673
|
sharePointSiteId,
|
|
1683
1674
|
mediaMaxBytes,
|
|
@@ -1693,6 +1684,29 @@ const FILE_CONSENT_THRESHOLD_BYTES = 4 * 1024 * 1024;
|
|
|
1693
1684
|
* Higher than the default because OneDrive upload handles large files well.
|
|
1694
1685
|
*/
|
|
1695
1686
|
const MSTEAMS_MAX_MEDIA_BYTES = 100 * 1024 * 1024;
|
|
1687
|
+
function createMSTeamsSendReceipt(params) {
|
|
1688
|
+
return createMessageReceiptFromOutboundResults({
|
|
1689
|
+
kind: params.kind,
|
|
1690
|
+
results: params.platformMessageIds.map((messageId) => ({
|
|
1691
|
+
channel: "msteams",
|
|
1692
|
+
messageId,
|
|
1693
|
+
conversationId: params.conversationId
|
|
1694
|
+
}))
|
|
1695
|
+
});
|
|
1696
|
+
}
|
|
1697
|
+
function createMSTeamsSendResult(params) {
|
|
1698
|
+
const platformMessageIds = (params.platformMessageIds?.length ? [...params.platformMessageIds] : [params.messageId]).map((messageId) => messageId.trim()).filter((messageId) => messageId && messageId !== "unknown");
|
|
1699
|
+
return {
|
|
1700
|
+
messageId: params.messageId,
|
|
1701
|
+
conversationId: params.conversationId,
|
|
1702
|
+
receipt: createMSTeamsSendReceipt({
|
|
1703
|
+
conversationId: params.conversationId,
|
|
1704
|
+
platformMessageIds,
|
|
1705
|
+
kind: params.kind
|
|
1706
|
+
}),
|
|
1707
|
+
...params.pendingUploadId ? { pendingUploadId: params.pendingUploadId } : {}
|
|
1708
|
+
};
|
|
1709
|
+
}
|
|
1696
1710
|
/**
|
|
1697
1711
|
* Send a message to a Teams conversation or user.
|
|
1698
1712
|
*
|
|
@@ -1774,11 +1788,12 @@ async function sendMessageMSTeams(params) {
|
|
|
1774
1788
|
messageId,
|
|
1775
1789
|
uploadId
|
|
1776
1790
|
});
|
|
1777
|
-
return {
|
|
1791
|
+
return createMSTeamsSendResult({
|
|
1778
1792
|
messageId,
|
|
1779
1793
|
conversationId,
|
|
1794
|
+
kind: "card",
|
|
1780
1795
|
pendingUploadId: uploadId
|
|
1781
|
-
};
|
|
1796
|
+
});
|
|
1782
1797
|
}
|
|
1783
1798
|
if (conversationType === "personal") {
|
|
1784
1799
|
const base64 = media.buffer.toString("base64");
|
|
@@ -1833,10 +1848,11 @@ async function sendMessageMSTeams(params) {
|
|
|
1833
1848
|
messageId,
|
|
1834
1849
|
fileName: driveItem.name
|
|
1835
1850
|
});
|
|
1836
|
-
return {
|
|
1851
|
+
return createMSTeamsSendResult({
|
|
1837
1852
|
messageId,
|
|
1838
|
-
conversationId
|
|
1839
|
-
|
|
1853
|
+
conversationId,
|
|
1854
|
+
kind: "media"
|
|
1855
|
+
});
|
|
1840
1856
|
}
|
|
1841
1857
|
log.debug?.("uploading to OneDrive (no SharePoint site configured)", {
|
|
1842
1858
|
fileName,
|
|
@@ -1867,10 +1883,11 @@ async function sendMessageMSTeams(params) {
|
|
|
1867
1883
|
messageId,
|
|
1868
1884
|
shareUrl: uploaded.shareUrl
|
|
1869
1885
|
});
|
|
1870
|
-
return {
|
|
1886
|
+
return createMSTeamsSendResult({
|
|
1871
1887
|
messageId,
|
|
1872
|
-
conversationId
|
|
1873
|
-
|
|
1888
|
+
conversationId,
|
|
1889
|
+
kind: "media"
|
|
1890
|
+
});
|
|
1874
1891
|
} catch (err) {
|
|
1875
1892
|
const classification = classifyMSTeamsSendError(err);
|
|
1876
1893
|
const hint = formatMSTeamsSendErrorHint(classification);
|
|
@@ -1884,11 +1901,11 @@ async function sendMessageMSTeams(params) {
|
|
|
1884
1901
|
* Send a text message with optional base64 media URL.
|
|
1885
1902
|
*/
|
|
1886
1903
|
async function sendTextWithMedia(ctx, text, mediaUrl) {
|
|
1887
|
-
const { adapter, appId, conversationId, ref, log, tokenProvider, sharePointSiteId, mediaMaxBytes } = ctx;
|
|
1888
|
-
let
|
|
1904
|
+
const { adapter, appId, conversationId, ref, log, tokenProvider, sharePointSiteId, mediaMaxBytes, replyStyle } = ctx;
|
|
1905
|
+
let platformMessageIds;
|
|
1889
1906
|
try {
|
|
1890
|
-
|
|
1891
|
-
replyStyle
|
|
1907
|
+
platformMessageIds = await sendMSTeamsMessages({
|
|
1908
|
+
replyStyle,
|
|
1892
1909
|
adapter,
|
|
1893
1910
|
appId,
|
|
1894
1911
|
conversationRef: ref,
|
|
@@ -1913,14 +1930,19 @@ async function sendTextWithMedia(ctx, text, mediaUrl) {
|
|
|
1913
1930
|
const status = classification.statusCode ? ` (HTTP ${classification.statusCode})` : "";
|
|
1914
1931
|
throw new Error(`msteams send failed${status}: ${formatUnknownError(err)}${hint ? ` (${hint})` : ""}`, { cause: err });
|
|
1915
1932
|
}
|
|
1916
|
-
const messageId =
|
|
1933
|
+
const messageId = platformMessageIds[0] ?? "unknown";
|
|
1917
1934
|
log.info("sent proactive message", {
|
|
1918
1935
|
conversationId,
|
|
1919
1936
|
messageId
|
|
1920
1937
|
});
|
|
1921
1938
|
return {
|
|
1922
1939
|
messageId,
|
|
1923
|
-
conversationId
|
|
1940
|
+
conversationId,
|
|
1941
|
+
receipt: createMSTeamsSendReceipt({
|
|
1942
|
+
conversationId,
|
|
1943
|
+
platformMessageIds,
|
|
1944
|
+
kind: mediaUrl ? "media" : "text"
|
|
1945
|
+
})
|
|
1924
1946
|
};
|
|
1925
1947
|
}
|
|
1926
1948
|
async function sendProactiveActivityRaw({ adapter, appId, ref, activity }) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as normalizeQuery, f as resolveGraphToken, o as listChannelsForTeam, s as listTeamsByName, t as searchGraphUsers } from "./graph-users-
|
|
1
|
+
import { c as normalizeQuery, f as resolveGraphToken, o as listChannelsForTeam, s as listTeamsByName, t as searchGraphUsers } from "./graph-users-C9HaPg1v.js";
|
|
2
2
|
import { mapAllowlistResolutionInputs } from "openclaw/plugin-sdk/allow-from";
|
|
3
3
|
import { normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString } from "openclaw/plugin-sdk/text-runtime";
|
|
4
4
|
//#region extensions/msteams/src/resolve-allowlist.ts
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { mergeAllowlist, resolveAllowlistMatchSimple, summarizeMapping } from "openclaw/plugin-sdk/allow-from";
|
|
2
|
+
import { createChannelMessageReplyPipeline } from "openclaw/plugin-sdk/channel-message";
|
|
2
3
|
import { createChannelPairingController } from "openclaw/plugin-sdk/channel-pairing";
|
|
3
4
|
import { evaluateSenderGroupAccessForPolicy, readStoreAllowFromForDmPolicy, resolveDmGroupAccessWithLists, resolveEffectiveAllowFromLists, resolveSenderScopedGroupPolicy, resolveToolsBySender } from "openclaw/plugin-sdk/channel-policy";
|
|
4
5
|
import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/account-id";
|
|
5
6
|
import { logTypingFailure } from "openclaw/plugin-sdk/channel-logging";
|
|
6
|
-
import { createChannelReplyPipeline } from "openclaw/plugin-sdk/channel-reply-pipeline";
|
|
7
7
|
import { PAIRING_APPROVED_MESSAGE, buildProbeChannelStatusSummary, createDefaultChannelRuntimeState } from "openclaw/plugin-sdk/channel-status";
|
|
8
8
|
import { buildChannelKeyCandidates, normalizeChannelSlug, resolveChannelEntryMatchWithFallback, resolveNestedAllowlistDecision } from "openclaw/plugin-sdk/channel-targets";
|
|
9
9
|
import { isDangerousNameMatchingEnabled } from "openclaw/plugin-sdk/dangerous-name-runtime";
|
|
@@ -25,4 +25,4 @@ const { setRuntime: setMSTeamsRuntime, getRuntime: getMSTeamsRuntime, tryGetRunt
|
|
|
25
25
|
errorMessage: "MSTeams runtime not initialized"
|
|
26
26
|
});
|
|
27
27
|
//#endregion
|
|
28
|
-
export { resolveDmGroupAccessWithLists as A, normalizeChannelSlug as C, resolveChannelEntryMatchWithFallback as D, resolveAllowlistMatchSimple as E, summarizeMapping as F, withFileLock$1 as I, getMSTeamsRuntime as L, resolveNestedAllowlistDecision as M, resolveSenderScopedGroupPolicy as N, resolveChannelMediaMaxBytes as O, resolveToolsBySender as P, getOptionalMSTeamsRuntime as R, mergeAllowlist as S, readStoreAllowFromForDmPolicy as T, getFileExtension as _, buildMediaPayload as a, loadOutboundMediaFromUrl as b,
|
|
28
|
+
export { resolveDmGroupAccessWithLists as A, normalizeChannelSlug as C, resolveChannelEntryMatchWithFallback as D, resolveAllowlistMatchSimple as E, summarizeMapping as F, withFileLock$1 as I, getMSTeamsRuntime as L, resolveNestedAllowlistDecision as M, resolveSenderScopedGroupPolicy as N, resolveChannelMediaMaxBytes as O, resolveToolsBySender as P, getOptionalMSTeamsRuntime as R, mergeAllowlist as S, readStoreAllowFromForDmPolicy as T, getFileExtension as _, buildMediaPayload as a, loadOutboundMediaFromUrl as b, createChannelMessageReplyPipeline as c, detectMime as d, dispatchReplyFromConfigWithSettledDispatcher$1 as f, fetchWithSsrFGuard$1 as g, extractOriginalFilename as h, buildChannelKeyCandidates as i, resolveEffectiveAllowFromLists as j, resolveDefaultGroupPolicy as k, createChannelPairingController as l, extensionForMime as m, DEFAULT_WEBHOOK_MAX_BODY_BYTES as n, buildProbeChannelStatusSummary as o, evaluateSenderGroupAccessForPolicy as p, PAIRING_APPROVED_MESSAGE as r, chunkTextForOutbound as s, DEFAULT_ACCOUNT_ID as t, createDefaultChannelRuntimeState as u, isDangerousNameMatchingEnabled as v, normalizeStringEntries as w, logTypingFailure as x, keepHttpServerTaskAlive as y, setMSTeamsRuntime as z };
|
package/dist/runtime-api.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { A as resolveDmGroupAccessWithLists, C as normalizeChannelSlug, D as resolveChannelEntryMatchWithFallback, E as resolveAllowlistMatchSimple, F as summarizeMapping, I as withFileLock, M as resolveNestedAllowlistDecision, N as resolveSenderScopedGroupPolicy, O as resolveChannelMediaMaxBytes, P as resolveToolsBySender, S as mergeAllowlist, T as readStoreAllowFromForDmPolicy, _ as getFileExtension, a as buildMediaPayload, b as loadOutboundMediaFromUrl, c as
|
|
2
|
-
export { DEFAULT_ACCOUNT_ID, DEFAULT_WEBHOOK_MAX_BODY_BYTES, PAIRING_APPROVED_MESSAGE, buildChannelKeyCandidates, buildMediaPayload, buildProbeChannelStatusSummary, chunkTextForOutbound,
|
|
1
|
+
import { A as resolveDmGroupAccessWithLists, C as normalizeChannelSlug, D as resolveChannelEntryMatchWithFallback, E as resolveAllowlistMatchSimple, F as summarizeMapping, I as withFileLock, M as resolveNestedAllowlistDecision, N as resolveSenderScopedGroupPolicy, O as resolveChannelMediaMaxBytes, P as resolveToolsBySender, S as mergeAllowlist, T as readStoreAllowFromForDmPolicy, _ as getFileExtension, a as buildMediaPayload, b as loadOutboundMediaFromUrl, c as createChannelMessageReplyPipeline, d as detectMime, f as dispatchReplyFromConfigWithSettledDispatcher, g as fetchWithSsrFGuard, h as extractOriginalFilename, i as buildChannelKeyCandidates, j as resolveEffectiveAllowFromLists, k as resolveDefaultGroupPolicy, l as createChannelPairingController, m as extensionForMime, n as DEFAULT_WEBHOOK_MAX_BODY_BYTES, o as buildProbeChannelStatusSummary, p as evaluateSenderGroupAccessForPolicy, r as PAIRING_APPROVED_MESSAGE, s as chunkTextForOutbound, t as DEFAULT_ACCOUNT_ID, u as createDefaultChannelRuntimeState, v as isDangerousNameMatchingEnabled, w as normalizeStringEntries, x as logTypingFailure, y as keepHttpServerTaskAlive, z as setMSTeamsRuntime } from "./runtime-api-D92XOrVf.js";
|
|
2
|
+
export { DEFAULT_ACCOUNT_ID, DEFAULT_WEBHOOK_MAX_BODY_BYTES, PAIRING_APPROVED_MESSAGE, buildChannelKeyCandidates, buildMediaPayload, buildProbeChannelStatusSummary, chunkTextForOutbound, createChannelMessageReplyPipeline, createChannelPairingController, createDefaultChannelRuntimeState, detectMime, dispatchReplyFromConfigWithSettledDispatcher, evaluateSenderGroupAccessForPolicy, extensionForMime, extractOriginalFilename, fetchWithSsrFGuard, getFileExtension, isDangerousNameMatchingEnabled, keepHttpServerTaskAlive, loadOutboundMediaFromUrl, logTypingFailure, mergeAllowlist, normalizeChannelSlug, normalizeStringEntries, readStoreAllowFromForDmPolicy, resolveAllowlistMatchSimple, resolveChannelEntryMatchWithFallback, resolveChannelMediaMaxBytes, resolveDefaultGroupPolicy, resolveDmGroupAccessWithLists, resolveEffectiveAllowFromLists, resolveNestedAllowlistDecision, resolveSenderScopedGroupPolicy, resolveToolsBySender, setMSTeamsRuntime, summarizeMapping, withFileLock };
|
package/dist/setup-plugin-api.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { h as resolveMSTeamsCredentials } from "./graph-users-
|
|
1
|
+
import { h as resolveMSTeamsCredentials } from "./graph-users-C9HaPg1v.js";
|
|
2
2
|
import { t as MSTeamsChannelConfigSchema } from "./config-schema-DwOEthCC.js";
|
|
3
|
-
import { i as msteamsSetupAdapter, t as msteamsSetupWizard } from "./setup-surface-
|
|
3
|
+
import { i as msteamsSetupAdapter, t as msteamsSetupWizard } from "./setup-surface-BeztPcxk.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,5 +1,5 @@
|
|
|
1
|
-
import { O as formatUnknownError, g as saveDelegatedTokens, h as resolveMSTeamsCredentials, p as hasConfiguredMSTeamsCredentials, v as normalizeSecretInputString } from "./graph-users-
|
|
2
|
-
import { c as resolveMSTeamsUserAllowlist, o as parseMSTeamsTeamEntry, s as resolveMSTeamsChannelAllowlist } from "./resolve-allowlist-
|
|
1
|
+
import { O as formatUnknownError, g as saveDelegatedTokens, h as resolveMSTeamsCredentials, p as hasConfiguredMSTeamsCredentials, v as normalizeSecretInputString } from "./graph-users-C9HaPg1v.js";
|
|
2
|
+
import { c as resolveMSTeamsUserAllowlist, o as parseMSTeamsTeamEntry, s as resolveMSTeamsChannelAllowlist } from "./resolve-allowlist-C23ohQKQ.js";
|
|
3
3
|
import { DEFAULT_ACCOUNT_ID, createStandardChannelSetupStatus, createTopLevelChannelAllowFromSetter, createTopLevelChannelDmPolicy, createTopLevelChannelGroupPolicySetter, mergeAllowFromEntries, splitSetupEntries } from "openclaw/plugin-sdk/setup";
|
|
4
4
|
import { formatDocsLink } from "openclaw/plugin-sdk/setup-tools";
|
|
5
5
|
//#region extensions/msteams/src/setup-core.ts
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { A as resolveDmGroupAccessWithLists, F as summarizeMapping, L as getMSTeamsRuntime, N as resolveSenderScopedGroupPolicy, O as resolveChannelMediaMaxBytes, R as getOptionalMSTeamsRuntime, S as mergeAllowlist, T as readStoreAllowFromForDmPolicy, a as buildMediaPayload, c as
|
|
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, 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-
|
|
3
|
-
import { c as resolveMSTeamsUserAllowlist, s as resolveMSTeamsChannelAllowlist } from "./resolve-allowlist-
|
|
4
|
-
import { a as resolveMSTeamsRouteConfig, i as resolveMSTeamsReplyPolicy, n as resolveMSTeamsAllowlistMatch, t as isMSTeamsGroupAllowed } from "./policy-
|
|
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-
|
|
1
|
+
import { A as resolveDmGroupAccessWithLists, F as summarizeMapping, L as getMSTeamsRuntime, N as resolveSenderScopedGroupPolicy, O as resolveChannelMediaMaxBytes, R as getOptionalMSTeamsRuntime, S as mergeAllowlist, T as readStoreAllowFromForDmPolicy, a as buildMediaPayload, c as createChannelMessageReplyPipeline, f as dispatchReplyFromConfigWithSettledDispatcher$1, j as resolveEffectiveAllowFromLists, k as resolveDefaultGroupPolicy, l as createChannelPairingController, n as DEFAULT_WEBHOOK_MAX_BODY_BYTES, p as evaluateSenderGroupAccessForPolicy$1, t as DEFAULT_ACCOUNT_ID, v as isDangerousNameMatchingEnabled, x as logTypingFailure, y as keepHttpServerTaskAlive } from "./runtime-api-D92XOrVf.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-C9HaPg1v.js";
|
|
3
|
+
import { c as resolveMSTeamsUserAllowlist, s as resolveMSTeamsChannelAllowlist } from "./resolve-allowlist-C23ohQKQ.js";
|
|
4
|
+
import { a as resolveMSTeamsRouteConfig, i as resolveMSTeamsReplyPolicy, n as resolveMSTeamsAllowlistMatch, t as isMSTeamsGroupAllowed } from "./policy-D32Kf1ED.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-Bs955MJZ.js";
|
|
6
6
|
import { formatAllowlistMatchMeta } from "openclaw/plugin-sdk/allow-from";
|
|
7
|
+
import { createLiveMessageState, createPreviewMessageReceipt, defineFinalizableLivePreviewAdapter, deliverWithFinalizableLivePreviewAdapter, markLiveMessageFinalized } from "openclaw/plugin-sdk/channel-message";
|
|
7
8
|
import { normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString, readStringValue } from "openclaw/plugin-sdk/text-runtime";
|
|
8
9
|
import { createDraftStreamLoop } from "openclaw/plugin-sdk/channel-lifecycle";
|
|
9
10
|
import { readResponseWithLimit } from "openclaw/plugin-sdk/media-runtime";
|
|
@@ -11,14 +12,16 @@ import { dispatchReplyFromConfigWithSettledDispatcher, hasFinalInboundReplyDispa
|
|
|
11
12
|
import { fetchWithSsrFGuard } from "openclaw/plugin-sdk/ssrf-runtime";
|
|
12
13
|
import { Buffer as Buffer$1 } from "node:buffer";
|
|
13
14
|
import path from "node:path";
|
|
14
|
-
import
|
|
15
|
+
import { appendRegularFile } from "openclaw/plugin-sdk/security-runtime";
|
|
16
|
+
import { writeJsonFileAtomically } from "openclaw/plugin-sdk/json-store";
|
|
15
17
|
import { resolveThreadSessionKeys } from "openclaw/plugin-sdk/routing";
|
|
18
|
+
import fs from "node:fs/promises";
|
|
16
19
|
import { logInboundDrop, resolveInboundMentionDecision, resolveInboundSessionEnvelopeContext } from "openclaw/plugin-sdk/channel-inbound";
|
|
17
20
|
import { resolveDualTextControlCommandGate } from "openclaw/plugin-sdk/command-gating";
|
|
18
21
|
import { filterSupplementalContextItems, resolveChannelContextVisibilityMode, shouldIncludeSupplementalContext } from "openclaw/plugin-sdk/context-visibility-runtime";
|
|
19
22
|
import { evaluateSenderGroupAccessForPolicy } from "openclaw/plugin-sdk/group-access";
|
|
20
23
|
import { DEFAULT_GROUP_HISTORY_LIMIT, buildPendingHistoryContextFromMap, recordPendingHistoryEntryIfEnabled } from "openclaw/plugin-sdk/reply-history";
|
|
21
|
-
import {
|
|
24
|
+
import { buildChannelProgressDraftLine, buildChannelProgressDraftLineForEntry, createChannelProgressDraftGate, formatChannelProgressDraftText, isChannelProgressDraftWorkToolName, resolveChannelPreviewStreamMode, resolveChannelProgressDraftMaxLines, resolveChannelStreamingBlockEnabled, resolveChannelStreamingPreviewToolProgress } from "openclaw/plugin-sdk/channel-streaming";
|
|
22
25
|
//#region extensions/msteams/src/feedback-reflection-prompt.ts
|
|
23
26
|
/** Max chars of the thumbed-down response to include in the reflection prompt. */
|
|
24
27
|
const MAX_RESPONSE_CHARS = 500;
|
|
@@ -126,8 +129,7 @@ async function storeSessionLearning(params) {
|
|
|
126
129
|
let learnings = exists ? existingLearnings : legacyLearnings;
|
|
127
130
|
learnings.push(params.learning);
|
|
128
131
|
if (learnings.length > 10) learnings = learnings.slice(-10);
|
|
129
|
-
await
|
|
130
|
-
await fs.writeFile(learningsFile, JSON.stringify(learnings, null, 2), "utf-8");
|
|
132
|
+
await writeJsonFileAtomically(learningsFile, learnings);
|
|
131
133
|
if (!exists && legacyLearningsFile !== learningsFile) await fs.rm(legacyLearningsFile, { force: true }).catch(() => void 0);
|
|
132
134
|
}
|
|
133
135
|
//#endregion
|
|
@@ -842,7 +844,7 @@ function resolveDownloadCandidate(att) {
|
|
|
842
844
|
const contentType = normalizeContentType(att.contentType);
|
|
843
845
|
const name = normalizeOptionalString(att.name) ?? "";
|
|
844
846
|
if (contentType === "application/vnd.microsoft.teams.file.download.info") {
|
|
845
|
-
if (!isRecord(att.content)) return null;
|
|
847
|
+
if (!isRecord$1(att.content)) return null;
|
|
846
848
|
const downloadUrl = normalizeOptionalString(att.content.downloadUrl) ?? "";
|
|
847
849
|
if (!downloadUrl) return null;
|
|
848
850
|
const fileType = normalizeOptionalString(att.content.fileType) ?? "";
|
|
@@ -1612,6 +1614,7 @@ var TeamsHttpStream = class {
|
|
|
1612
1614
|
this.finalized = false;
|
|
1613
1615
|
this.streamFailed = false;
|
|
1614
1616
|
this.lastStreamedText = "";
|
|
1617
|
+
this.finalMessageId = void 0;
|
|
1615
1618
|
this.streamStartedAt = void 0;
|
|
1616
1619
|
this.sendActivity = options.sendActivity;
|
|
1617
1620
|
this.feedbackLoopEnabled = options.feedbackLoopEnabled ?? false;
|
|
@@ -1678,22 +1681,23 @@ var TeamsHttpStream = class {
|
|
|
1678
1681
|
* Finalize the stream — send the final message activity.
|
|
1679
1682
|
*/
|
|
1680
1683
|
async finalize() {
|
|
1681
|
-
if (this.finalized) return;
|
|
1684
|
+
if (this.finalized) return this.finalMessageId;
|
|
1682
1685
|
this.finalized = true;
|
|
1683
1686
|
this.stopped = true;
|
|
1684
1687
|
this.loop.stop();
|
|
1685
1688
|
await this.loop.waitForInFlight();
|
|
1686
|
-
if (!this.accumulatedText.trim()) return;
|
|
1689
|
+
if (!this.accumulatedText.trim()) return this.finalMessageId;
|
|
1687
1690
|
if (this.streamFailed) {
|
|
1688
1691
|
if (this.streamId) try {
|
|
1689
|
-
await this.sendActivity({
|
|
1692
|
+
const response = await this.sendActivity({
|
|
1690
1693
|
type: "message",
|
|
1691
1694
|
text: this.lastStreamedText || "",
|
|
1692
1695
|
channelData: { feedbackLoopEnabled: this.feedbackLoopEnabled },
|
|
1693
1696
|
entities: [AI_GENERATED_ENTITY, buildStreamInfoEntity(this.streamId, "final")]
|
|
1694
1697
|
});
|
|
1698
|
+
this.finalMessageId = extractId(response);
|
|
1695
1699
|
} catch {}
|
|
1696
|
-
return;
|
|
1700
|
+
return this.finalMessageId;
|
|
1697
1701
|
}
|
|
1698
1702
|
try {
|
|
1699
1703
|
const entities = [AI_GENERATED_ENTITY];
|
|
@@ -1704,11 +1708,13 @@ var TeamsHttpStream = class {
|
|
|
1704
1708
|
channelData: { feedbackLoopEnabled: this.feedbackLoopEnabled },
|
|
1705
1709
|
entities
|
|
1706
1710
|
};
|
|
1707
|
-
await this.sendActivity(finalActivity);
|
|
1711
|
+
const response = await this.sendActivity(finalActivity);
|
|
1712
|
+
this.finalMessageId = extractId(response);
|
|
1708
1713
|
} catch (err) {
|
|
1709
1714
|
this.streamFailed = true;
|
|
1710
1715
|
this.onError?.(err);
|
|
1711
1716
|
}
|
|
1717
|
+
return this.finalMessageId;
|
|
1712
1718
|
}
|
|
1713
1719
|
/** Whether streaming successfully delivered content (at least one chunk sent, not failed). */
|
|
1714
1720
|
get hasContent() {
|
|
@@ -1726,6 +1732,14 @@ var TeamsHttpStream = class {
|
|
|
1726
1732
|
get isFinalized() {
|
|
1727
1733
|
return this.finalized;
|
|
1728
1734
|
}
|
|
1735
|
+
/** Platform id returned by the final message activity, when available. */
|
|
1736
|
+
get messageId() {
|
|
1737
|
+
return this.finalMessageId;
|
|
1738
|
+
}
|
|
1739
|
+
/** Stream id returned by the first streaminfo activity, when available. */
|
|
1740
|
+
get previewStreamId() {
|
|
1741
|
+
return this.streamId;
|
|
1742
|
+
}
|
|
1729
1743
|
/** Whether streaming fell back (not used in this implementation). */
|
|
1730
1744
|
get isFallback() {
|
|
1731
1745
|
return false;
|
|
@@ -1781,6 +1795,13 @@ function createTeamsReplyStreamController(params) {
|
|
|
1781
1795
|
let progressLines = [];
|
|
1782
1796
|
let lastInformativeText = "";
|
|
1783
1797
|
let pendingFinalize;
|
|
1798
|
+
let liveState = createLiveMessageState({ canFinalizeInPlace: Boolean(stream) });
|
|
1799
|
+
const markStreamFinalized = () => {
|
|
1800
|
+
if (!stream || stream.isFailed) return;
|
|
1801
|
+
const messageId = stream.messageId ?? stream.previewStreamId;
|
|
1802
|
+
if (!messageId) return;
|
|
1803
|
+
liveState = markLiveMessageFinalized(liveState, createPreviewMessageReceipt({ id: messageId }));
|
|
1804
|
+
};
|
|
1784
1805
|
const renderInformativeUpdate = async () => {
|
|
1785
1806
|
if (!stream) return;
|
|
1786
1807
|
const informativeText = formatChannelProgressDraftText({
|
|
@@ -1806,9 +1827,12 @@ function createTeamsReplyStreamController(params) {
|
|
|
1806
1827
|
if (!stream || streamMode !== "progress") return;
|
|
1807
1828
|
if (options?.toolName !== void 0 && !isChannelProgressDraftWorkToolName(options.toolName)) return;
|
|
1808
1829
|
if (shouldStreamPreviewToolProgress) {
|
|
1809
|
-
const normalized = line
|
|
1830
|
+
const normalized = normalizeProgressLineIdentity(line);
|
|
1810
1831
|
if (normalized) {
|
|
1811
|
-
if (progressLines.at(-1) !== normalized)
|
|
1832
|
+
if (normalizeProgressLineIdentity(progressLines.at(-1)) !== normalized) {
|
|
1833
|
+
const progressLine = typeof line === "object" && line !== void 0 ? line : normalized;
|
|
1834
|
+
progressLines = [...progressLines, progressLine].slice(-resolveChannelProgressDraftMaxLines(params.msteamsConfig));
|
|
1835
|
+
}
|
|
1812
1836
|
}
|
|
1813
1837
|
}
|
|
1814
1838
|
await noteProgressWork();
|
|
@@ -1827,6 +1851,39 @@ function createTeamsReplyStreamController(params) {
|
|
|
1827
1851
|
text: remainingText
|
|
1828
1852
|
};
|
|
1829
1853
|
};
|
|
1854
|
+
const finalizeProgressPayload = async (payload, hasMedia) => {
|
|
1855
|
+
if (!stream || !payload.text) return payload;
|
|
1856
|
+
return (await deliverWithFinalizableLivePreviewAdapter({
|
|
1857
|
+
kind: "final",
|
|
1858
|
+
payload,
|
|
1859
|
+
liveState,
|
|
1860
|
+
adapter: defineFinalizableLivePreviewAdapter({
|
|
1861
|
+
draft: {
|
|
1862
|
+
flush: async () => {},
|
|
1863
|
+
clear: async () => {},
|
|
1864
|
+
id: () => stream.previewStreamId
|
|
1865
|
+
},
|
|
1866
|
+
buildFinalEdit: (candidate) => candidate.text ? { text: candidate.text } : void 0,
|
|
1867
|
+
editFinal: async (_previewId, edit) => {
|
|
1868
|
+
const finalized = await stream.replaceInformativeWithFinal(edit.text);
|
|
1869
|
+
informativeUpdateSent = false;
|
|
1870
|
+
if (!finalized || stream.isFailed) throw new Error("Teams progress stream finalization failed");
|
|
1871
|
+
},
|
|
1872
|
+
resolveFinalizedId: (previewId) => stream.messageId ?? stream.previewStreamId ?? previewId,
|
|
1873
|
+
createPreviewReceipt: (id) => createPreviewMessageReceipt({ id }),
|
|
1874
|
+
onPreviewFinalized: (_id, _receipt, state) => {
|
|
1875
|
+
liveState = state;
|
|
1876
|
+
},
|
|
1877
|
+
logPreviewEditFailure: (err) => {
|
|
1878
|
+
params.log.debug?.(`stream finalization failed: ${formatUnknownError(err)}`);
|
|
1879
|
+
}
|
|
1880
|
+
}),
|
|
1881
|
+
deliverNormally: async () => false
|
|
1882
|
+
})).kind === "preview-finalized" ? hasMedia ? {
|
|
1883
|
+
...payload,
|
|
1884
|
+
text: void 0
|
|
1885
|
+
} : void 0 : payload;
|
|
1886
|
+
};
|
|
1830
1887
|
return {
|
|
1831
1888
|
async onReplyStart() {},
|
|
1832
1889
|
async noteProgressWork(options) {
|
|
@@ -1851,13 +1908,7 @@ function createTeamsReplyStreamController(params) {
|
|
|
1851
1908
|
const hasMedia = Boolean(payload.mediaUrl || payload.mediaUrls?.length);
|
|
1852
1909
|
if (stream && streamMode === "progress" && informativeUpdateSent && !stream.isFinalized) {
|
|
1853
1910
|
if (!payload.text) return payload;
|
|
1854
|
-
|
|
1855
|
-
informativeUpdateSent = false;
|
|
1856
|
-
if (!finalized || stream.isFailed) return payload;
|
|
1857
|
-
return hasMedia ? {
|
|
1858
|
-
...payload,
|
|
1859
|
-
text: void 0
|
|
1860
|
-
} : void 0;
|
|
1911
|
+
return await finalizeProgressPayload(payload, hasMedia);
|
|
1861
1912
|
}
|
|
1862
1913
|
if (!stream || !streamReceivedTokens) return payload;
|
|
1863
1914
|
if (stream.isFailed) {
|
|
@@ -1866,7 +1917,9 @@ function createTeamsReplyStreamController(params) {
|
|
|
1866
1917
|
}
|
|
1867
1918
|
if (!stream.hasContent || stream.isFinalized) return payload;
|
|
1868
1919
|
streamReceivedTokens = false;
|
|
1869
|
-
pendingFinalize = stream.finalize()
|
|
1920
|
+
pendingFinalize = stream.finalize().then(() => {
|
|
1921
|
+
markStreamFinalized();
|
|
1922
|
+
});
|
|
1870
1923
|
if (!hasMedia) return;
|
|
1871
1924
|
return {
|
|
1872
1925
|
...payload,
|
|
@@ -1876,11 +1929,17 @@ function createTeamsReplyStreamController(params) {
|
|
|
1876
1929
|
async finalize() {
|
|
1877
1930
|
progressDraftGate.cancel();
|
|
1878
1931
|
await pendingFinalize;
|
|
1879
|
-
|
|
1932
|
+
if (!pendingFinalize) {
|
|
1933
|
+
await stream?.finalize();
|
|
1934
|
+
markStreamFinalized();
|
|
1935
|
+
}
|
|
1880
1936
|
},
|
|
1881
1937
|
hasStream() {
|
|
1882
1938
|
return Boolean(stream);
|
|
1883
1939
|
},
|
|
1940
|
+
liveState() {
|
|
1941
|
+
return liveState;
|
|
1942
|
+
},
|
|
1884
1943
|
/**
|
|
1885
1944
|
* Whether the Teams streaming card is currently receiving LLM tokens.
|
|
1886
1945
|
* Used to gate side-channel keepalive activity so we don't overlay plain
|
|
@@ -1905,6 +1964,9 @@ function createTeamsReplyStreamController(params) {
|
|
|
1905
1964
|
}
|
|
1906
1965
|
};
|
|
1907
1966
|
}
|
|
1967
|
+
function normalizeProgressLineIdentity(line) {
|
|
1968
|
+
return (typeof line === "string" ? line : line?.text)?.replace(/\s+/g, " ").trim() ?? "";
|
|
1969
|
+
}
|
|
1908
1970
|
//#endregion
|
|
1909
1971
|
//#region extensions/msteams/src/reply-dispatcher.ts
|
|
1910
1972
|
function createMSTeamsReplyDispatcher(params) {
|
|
@@ -1952,7 +2014,7 @@ function createMSTeamsReplyDispatcher(params) {
|
|
|
1952
2014
|
if (streamActiveRef.current()) return;
|
|
1953
2015
|
await rawSendTypingIndicator();
|
|
1954
2016
|
} : async () => {};
|
|
1955
|
-
const { onModelSelected, typingCallbacks, ...replyPipeline } =
|
|
2017
|
+
const { onModelSelected, typingCallbacks, ...replyPipeline } = createChannelMessageReplyPipeline({
|
|
1956
2018
|
cfg: params.cfg,
|
|
1957
2019
|
agentId: params.agentId,
|
|
1958
2020
|
channel: "msteams",
|
|
@@ -2145,7 +2207,7 @@ function createMSTeamsReplyDispatcher(params) {
|
|
|
2145
2207
|
...streamController.shouldSuppressDefaultToolProgressMessages() ? { suppressDefaultToolProgressMessages: true } : {},
|
|
2146
2208
|
...streamController.shouldStreamPreviewToolProgress() ? {
|
|
2147
2209
|
onToolStart: async (payload) => {
|
|
2148
|
-
await streamController.pushProgressLine(
|
|
2210
|
+
await streamController.pushProgressLine(buildChannelProgressDraftLineForEntry(msteamsCfg, {
|
|
2149
2211
|
event: "tool",
|
|
2150
2212
|
name: payload.name,
|
|
2151
2213
|
phase: payload.phase,
|
|
@@ -2153,7 +2215,7 @@ function createMSTeamsReplyDispatcher(params) {
|
|
|
2153
2215
|
}, payload.detailMode ? { detailMode: payload.detailMode } : void 0), { toolName: payload.name });
|
|
2154
2216
|
},
|
|
2155
2217
|
onItemEvent: async (payload) => {
|
|
2156
|
-
await streamController.pushProgressLine(
|
|
2218
|
+
await streamController.pushProgressLine(buildChannelProgressDraftLineForEntry(msteamsCfg, {
|
|
2157
2219
|
event: "item",
|
|
2158
2220
|
itemKind: payload.kind,
|
|
2159
2221
|
title: payload.title,
|
|
@@ -2167,7 +2229,7 @@ function createMSTeamsReplyDispatcher(params) {
|
|
|
2167
2229
|
},
|
|
2168
2230
|
onPlanUpdate: async (payload) => {
|
|
2169
2231
|
if (payload.phase !== "update") return;
|
|
2170
|
-
await streamController.pushProgressLine(
|
|
2232
|
+
await streamController.pushProgressLine(buildChannelProgressDraftLine({
|
|
2171
2233
|
event: "plan",
|
|
2172
2234
|
phase: payload.phase,
|
|
2173
2235
|
title: payload.title,
|
|
@@ -2177,7 +2239,7 @@ function createMSTeamsReplyDispatcher(params) {
|
|
|
2177
2239
|
},
|
|
2178
2240
|
onApprovalEvent: async (payload) => {
|
|
2179
2241
|
if (payload.phase !== "requested") return;
|
|
2180
|
-
await streamController.pushProgressLine(
|
|
2242
|
+
await streamController.pushProgressLine(buildChannelProgressDraftLine({
|
|
2181
2243
|
event: "approval",
|
|
2182
2244
|
phase: payload.phase,
|
|
2183
2245
|
title: payload.title,
|
|
@@ -2188,7 +2250,7 @@ function createMSTeamsReplyDispatcher(params) {
|
|
|
2188
2250
|
},
|
|
2189
2251
|
onCommandOutput: async (payload) => {
|
|
2190
2252
|
if (payload.phase !== "end") return;
|
|
2191
|
-
await streamController.pushProgressLine(
|
|
2253
|
+
await streamController.pushProgressLine(buildChannelProgressDraftLine({
|
|
2192
2254
|
event: "command-output",
|
|
2193
2255
|
phase: payload.phase,
|
|
2194
2256
|
title: payload.title,
|
|
@@ -2199,7 +2261,7 @@ function createMSTeamsReplyDispatcher(params) {
|
|
|
2199
2261
|
},
|
|
2200
2262
|
onPatchSummary: async (payload) => {
|
|
2201
2263
|
if (payload.phase !== "end") return;
|
|
2202
|
-
await streamController.pushProgressLine(
|
|
2264
|
+
await streamController.pushProgressLine(buildChannelProgressDraftLine({
|
|
2203
2265
|
event: "patch",
|
|
2204
2266
|
phase: payload.phase,
|
|
2205
2267
|
title: payload.title,
|
|
@@ -2430,7 +2492,7 @@ function extractTextFromHtmlAttachments(attachments) {
|
|
|
2430
2492
|
for (const attachment of attachments) {
|
|
2431
2493
|
if (attachment.contentType !== "text/html") continue;
|
|
2432
2494
|
const content = attachment.content;
|
|
2433
|
-
const raw = typeof content === "string" ? content : isRecord(content) && typeof content.text === "string" ? content.text : isRecord(content) && typeof content.body === "string" ? content.body : "";
|
|
2495
|
+
const raw = typeof content === "string" ? content : isRecord$1(content) && typeof content.text === "string" ? content.text : isRecord$1(content) && typeof content.body === "string" ? content.body : "";
|
|
2434
2496
|
if (!raw) continue;
|
|
2435
2497
|
const text = raw.replace(/<at[^>]*>.*?<\/at>/gis, " ").replace(/<a\b[^>]*href=["']([^"']+)["'][^>]*>(.*?)<\/a>/gis, "$2 $1").replace(/<br\s*\/?>/gi, "\n").replace(/<\/p>/gi, "\n").replace(/<[^>]+>/g, " ").replace(/ /gi, " ").replace(/&/gi, "&").replace(/\s+/g, " ").trim();
|
|
2436
2498
|
if (text) return text;
|
|
@@ -3021,7 +3083,7 @@ function createMSTeamsMessageHandler(deps) {
|
|
|
3021
3083
|
logVerboseMessage(`msteams: delivered ${finalCount} reply${finalCount === 1 ? "" : "ies"} to ${teamsTo}`);
|
|
3022
3084
|
} catch (err) {
|
|
3023
3085
|
log.error("dispatch failed", { error: formatUnknownError(err) });
|
|
3024
|
-
runtime.error
|
|
3086
|
+
runtime.error(`msteams dispatch failed: ${formatUnknownError(err)}`);
|
|
3025
3087
|
try {
|
|
3026
3088
|
await context.sendActivity("⚠️ Something went wrong. Please try again.");
|
|
3027
3089
|
} catch {}
|
|
@@ -3062,7 +3124,7 @@ function createMSTeamsMessageHandler(deps) {
|
|
|
3062
3124
|
});
|
|
3063
3125
|
},
|
|
3064
3126
|
onError: (err) => {
|
|
3065
|
-
runtime.error
|
|
3127
|
+
runtime.error(`msteams debounce flush failed: ${formatUnknownError(err)}`);
|
|
3066
3128
|
}
|
|
3067
3129
|
});
|
|
3068
3130
|
return async function handleTeamsMessage(context) {
|
|
@@ -3603,8 +3665,11 @@ async function handleFeedbackInvoke(context, deps) {
|
|
|
3603
3665
|
try {
|
|
3604
3666
|
const storePath = core.channel.session.resolveStorePath(deps.cfg.session?.store, { agentId: route.agentId });
|
|
3605
3667
|
const safeKey = route.sessionKey.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
3606
|
-
|
|
3607
|
-
|
|
3668
|
+
await appendRegularFile({
|
|
3669
|
+
filePath: path.join(storePath, `${safeKey}.jsonl`),
|
|
3670
|
+
content: `${JSON.stringify(feedbackEvent)}\n`,
|
|
3671
|
+
rejectSymlinkParents: true
|
|
3672
|
+
}).catch(() => {});
|
|
3608
3673
|
} catch {}
|
|
3609
3674
|
const conversationRef = {
|
|
3610
3675
|
activityId: activity.id,
|
|
@@ -3744,7 +3809,7 @@ function registerMSTeamsHandlers(handler, deps) {
|
|
|
3744
3809
|
try {
|
|
3745
3810
|
await handleTeamsMessage(context);
|
|
3746
3811
|
} catch (err) {
|
|
3747
|
-
deps.runtime.error
|
|
3812
|
+
deps.runtime.error(`msteams handler failed: ${formatUnknownError(err)}`);
|
|
3748
3813
|
}
|
|
3749
3814
|
await next();
|
|
3750
3815
|
});
|
|
@@ -3788,7 +3853,7 @@ function registerMSTeamsHandlers(handler, deps) {
|
|
|
3788
3853
|
try {
|
|
3789
3854
|
await handleReaction(context, "added");
|
|
3790
3855
|
} catch (err) {
|
|
3791
|
-
deps.runtime.error
|
|
3856
|
+
deps.runtime.error(`msteams reaction handler failed: ${String(err)}`);
|
|
3792
3857
|
}
|
|
3793
3858
|
await next();
|
|
3794
3859
|
});
|
|
@@ -3796,7 +3861,7 @@ function registerMSTeamsHandlers(handler, deps) {
|
|
|
3796
3861
|
try {
|
|
3797
3862
|
await handleReaction(context, "removed");
|
|
3798
3863
|
} catch (err) {
|
|
3799
|
-
deps.runtime.error
|
|
3864
|
+
deps.runtime.error(`msteams reaction handler failed: ${String(err)}`);
|
|
3800
3865
|
}
|
|
3801
3866
|
await next();
|
|
3802
3867
|
});
|
|
@@ -3941,7 +4006,17 @@ async function monitorMSTeamsProvider(opts) {
|
|
|
3941
4006
|
let allowFrom = msteamsCfg.allowFrom;
|
|
3942
4007
|
let groupAllowFrom = msteamsCfg.groupAllowFrom;
|
|
3943
4008
|
let teamsConfig = msteamsCfg.teams;
|
|
4009
|
+
const allowNameMatching = isDangerousNameMatchingEnabled(msteamsCfg);
|
|
3944
4010
|
const cleanAllowEntry = (entry) => entry.replace(/^(msteams|teams):/i, "").replace(/^user:/i, "").trim();
|
|
4011
|
+
const isStableUserId = (entry) => /^[0-9a-fA-F-]{16,}$/.test(entry);
|
|
4012
|
+
const cleanAllowEntries = (entries) => entries?.map((entry) => cleanAllowEntry(entry)).filter((entry) => entry && entry !== "*") ?? [];
|
|
4013
|
+
const mergeStableUserIds = (entries) => {
|
|
4014
|
+
const additions = cleanAllowEntries(entries).filter((entry) => isStableUserId(entry));
|
|
4015
|
+
return additions.length > 0 ? mergeAllowlist({
|
|
4016
|
+
existing: entries,
|
|
4017
|
+
additions
|
|
4018
|
+
}) : entries;
|
|
4019
|
+
};
|
|
3945
4020
|
const resolveAllowlistUsers = async (label, entries) => {
|
|
3946
4021
|
if (entries.length === 0) return {
|
|
3947
4022
|
additions: [],
|
|
@@ -3962,23 +4037,27 @@ async function monitorMSTeamsProvider(opts) {
|
|
|
3962
4037
|
};
|
|
3963
4038
|
};
|
|
3964
4039
|
try {
|
|
3965
|
-
|
|
3966
|
-
if (
|
|
3967
|
-
|
|
3968
|
-
|
|
3969
|
-
|
|
3970
|
-
additions
|
|
3971
|
-
|
|
3972
|
-
|
|
3973
|
-
if (Array.isArray(groupAllowFrom) && groupAllowFrom.length > 0) {
|
|
3974
|
-
const groupEntries = groupAllowFrom.map((entry) => cleanAllowEntry(entry)).filter((entry) => entry && entry !== "*");
|
|
3975
|
-
if (groupEntries.length > 0) {
|
|
3976
|
-
const { additions } = await resolveAllowlistUsers("msteams group users", groupEntries);
|
|
3977
|
-
groupAllowFrom = mergeAllowlist({
|
|
3978
|
-
existing: groupAllowFrom,
|
|
4040
|
+
allowFrom = mergeStableUserIds(allowFrom);
|
|
4041
|
+
if (Array.isArray(groupAllowFrom) && groupAllowFrom.length > 0) groupAllowFrom = mergeStableUserIds(groupAllowFrom);
|
|
4042
|
+
if (allowNameMatching) {
|
|
4043
|
+
const allowEntries = cleanAllowEntries(allowFrom).filter((entry) => !isStableUserId(entry));
|
|
4044
|
+
if (allowEntries.length > 0) {
|
|
4045
|
+
const { additions } = await resolveAllowlistUsers("msteams users", allowEntries);
|
|
4046
|
+
allowFrom = mergeAllowlist({
|
|
4047
|
+
existing: allowFrom,
|
|
3979
4048
|
additions
|
|
3980
4049
|
});
|
|
3981
4050
|
}
|
|
4051
|
+
if (Array.isArray(groupAllowFrom) && groupAllowFrom.length > 0) {
|
|
4052
|
+
const groupEntries = cleanAllowEntries(groupAllowFrom).filter((entry) => !isStableUserId(entry));
|
|
4053
|
+
if (groupEntries.length > 0) {
|
|
4054
|
+
const { additions } = await resolveAllowlistUsers("msteams group users", groupEntries);
|
|
4055
|
+
groupAllowFrom = mergeAllowlist({
|
|
4056
|
+
existing: groupAllowFrom,
|
|
4057
|
+
additions
|
|
4058
|
+
});
|
|
4059
|
+
}
|
|
4060
|
+
}
|
|
3982
4061
|
}
|
|
3983
4062
|
if (teamsConfig && Object.keys(teamsConfig).length > 0) {
|
|
3984
4063
|
const entries = [];
|
|
@@ -4046,7 +4125,7 @@ async function monitorMSTeamsProvider(opts) {
|
|
|
4046
4125
|
}
|
|
4047
4126
|
}
|
|
4048
4127
|
} catch (err) {
|
|
4049
|
-
runtime
|
|
4128
|
+
runtime?.error(`msteams resolve failed; falling back to raw config entries — allowlist members resolved via Graph may be missing. ${formatUnknownError(err)}`);
|
|
4050
4129
|
}
|
|
4051
4130
|
msteamsCfg = {
|
|
4052
4131
|
...msteamsCfg,
|
|
@@ -4116,7 +4195,8 @@ async function monitorMSTeamsProvider(opts) {
|
|
|
4116
4195
|
}
|
|
4117
4196
|
next();
|
|
4118
4197
|
}).catch((err) => {
|
|
4119
|
-
|
|
4198
|
+
if (err instanceof Error && /ECONNREFUSED|ENOTFOUND|EHOSTUNREACH|ETIMEDOUT|ECONNRESET/i.test(err.code ?? err.message)) runtime?.error(`msteams: JWKS key fetch failed — check egress to login.botframework.com:443 (firewall or DNS may be blocking it). Bot will 401 all inbound requests until this is resolved. Error: ${formatUnknownError(err)}`);
|
|
4199
|
+
else log.debug?.(`JWT validation error: ${formatUnknownError(err)}`);
|
|
4120
4200
|
res.status(401).json({ error: "Unauthorized" });
|
|
4121
4201
|
});
|
|
4122
4202
|
});
|
package/dist/test-api.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as msteamsPlugin } from "./channel-
|
|
1
|
+
import { t as msteamsPlugin } from "./channel-VjDbklu8.js";
|
|
2
2
|
export { msteamsPlugin };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/msteams",
|
|
3
|
-
"version": "2026.5.
|
|
3
|
+
"version": "2026.5.9-beta.1",
|
|
4
4
|
"description": "OpenClaw Microsoft Teams channel plugin",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -9,12 +9,12 @@
|
|
|
9
9
|
"type": "module",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"@azure/identity": "4.13.1",
|
|
12
|
-
"@microsoft/teams.api": "2.0.
|
|
13
|
-
"@microsoft/teams.apps": "2.0.
|
|
12
|
+
"@microsoft/teams.api": "2.0.10",
|
|
13
|
+
"@microsoft/teams.apps": "2.0.10",
|
|
14
14
|
"express": "5.2.1",
|
|
15
15
|
"jsonwebtoken": "9.0.3",
|
|
16
16
|
"jwks-rsa": "4.0.1",
|
|
17
|
-
"typebox": "1.1.
|
|
17
|
+
"typebox": "1.1.38"
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
20
20
|
"@openclaw/plugin-sdk": "workspace:*",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"openclaw": "workspace:*"
|
|
23
23
|
},
|
|
24
24
|
"peerDependencies": {
|
|
25
|
-
"openclaw": ">=2026.5.
|
|
25
|
+
"openclaw": ">=2026.5.9-beta.1"
|
|
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.
|
|
61
|
+
"pluginApi": ">=2026.5.9-beta.1"
|
|
62
62
|
},
|
|
63
63
|
"build": {
|
|
64
|
-
"openclawVersion": "2026.5.
|
|
64
|
+
"openclawVersion": "2026.5.9-beta.1"
|
|
65
65
|
},
|
|
66
66
|
"release": {
|
|
67
67
|
"publishToClawHub": true,
|