@openclaw/msteams 2026.2.17 → 2026.2.21

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/CHANGELOG.md CHANGED
@@ -1,125 +1,5 @@
1
1
  # Changelog
2
2
 
3
- ## 2026.2.17
4
-
5
- ### Changes
6
-
7
- - Version alignment with core OpenClaw release numbers.
8
-
9
- ## 2026.2.16
10
-
11
- ### Changes
12
-
13
- - Version alignment with core OpenClaw release numbers.
14
-
15
- ## 2026.2.15
16
-
17
- ### Changes
18
-
19
- - Version alignment with core OpenClaw release numbers.
20
-
21
- ## 2026.2.14
22
-
23
- ### Changes
24
-
25
- - Version alignment with core OpenClaw release numbers.
26
-
27
- ## 2026.2.13
28
-
29
- ### Changes
30
-
31
- - Version alignment with core OpenClaw release numbers.
32
-
33
- ## 2026.2.6-3
34
-
35
- ### Changes
36
-
37
- - Version alignment with core OpenClaw release numbers.
38
-
39
- ## 2026.2.6-2
40
-
41
- ### Changes
42
-
43
- - Version alignment with core OpenClaw release numbers.
44
-
45
- ## 2026.2.6
46
-
47
- ### Changes
48
-
49
- - Version alignment with core OpenClaw release numbers.
50
-
51
- ## 2026.2.4
52
-
53
- ### Changes
54
-
55
- - Version alignment with core OpenClaw release numbers.
56
-
57
- ## 2026.2.2
58
-
59
- ### Changes
60
-
61
- - Version alignment with core OpenClaw release numbers.
62
-
63
- ## 2026.1.31
64
-
65
- ### Changes
66
-
67
- - Version alignment with core OpenClaw release numbers.
68
-
69
- ## 2026.1.30
70
-
71
- ### Changes
72
-
73
- - Version alignment with core OpenClaw release numbers.
74
-
75
- ## 2026.1.29
76
-
77
- ### Changes
78
-
79
- - Version alignment with core OpenClaw release numbers.
80
-
81
- ## 2026.1.23
82
-
83
- ### Changes
84
-
85
- - Version alignment with core OpenClaw release numbers.
86
-
87
- ## 2026.1.22
88
-
89
- ### Changes
90
-
91
- - Version alignment with core OpenClaw release numbers.
92
-
93
- ## 2026.1.21
94
-
95
- ### Changes
96
-
97
- - Version alignment with core OpenClaw release numbers.
98
-
99
- ## 2026.1.20
100
-
101
- ### Changes
102
-
103
- - Version alignment with core OpenClaw release numbers.
104
-
105
- ## 2026.1.17-1
106
-
107
- ### Changes
108
-
109
- - Version alignment with core OpenClaw release numbers.
110
-
111
- ## 2026.1.17
112
-
113
- ### Changes
114
-
115
- - Version alignment with core OpenClaw release numbers.
116
-
117
- ## 2026.1.16
118
-
119
- ### Changes
120
-
121
- - Version alignment with core OpenClaw release numbers.
122
-
123
3
  ## 2026.1.15
124
4
 
125
5
  ### Features
package/package.json CHANGED
@@ -1,12 +1,10 @@
1
1
  {
2
2
  "name": "@openclaw/msteams",
3
- "version": "2026.2.17",
3
+ "version": "2026.2.21",
4
4
  "description": "OpenClaw Microsoft Teams channel plugin",
5
5
  "type": "module",
6
6
  "dependencies": {
7
- "@microsoft/agents-hosting": "^1.2.3",
8
- "@microsoft/agents-hosting-express": "^1.2.3",
9
- "@microsoft/agents-hosting-extensions-teams": "^1.2.3",
7
+ "@microsoft/agents-hosting": "^1.3.1",
10
8
  "express": "^5.2.1"
11
9
  },
12
10
  "devDependencies": {
package/src/channel.ts CHANGED
@@ -123,6 +123,7 @@ export const msteamsPlugin: ChannelPlugin<ResolvedMSTeamsAccount> = {
123
123
  .map((entry) => String(entry).trim())
124
124
  .filter(Boolean)
125
125
  .map((entry) => entry.toLowerCase()),
126
+ resolveDefaultTo: ({ cfg }) => cfg.channels?.msteams?.defaultTo?.trim() || undefined,
126
127
  },
127
128
  security: {
128
129
  collectWarnings: ({ cfg }) => {
@@ -24,7 +24,6 @@ export interface OneDriveUploadResult {
24
24
  /**
25
25
  * Upload a file to the user's OneDrive root folder.
26
26
  * For larger files, this uses the simple upload endpoint (up to 4MB).
27
- * TODO: For files >4MB, implement resumable upload session.
28
27
  */
29
28
  export async function uploadToOneDrive(params: {
30
29
  buffer: Buffer;
@@ -154,6 +154,10 @@ describe("msteams media-helpers", () => {
154
154
  expect(isLocalPath("\\\\server\\share\\image.png")).toBe(true);
155
155
  });
156
156
 
157
+ it("returns true for Windows rooted paths", () => {
158
+ expect(isLocalPath("\\tmp\\openclaw\\file.txt")).toBe(true);
159
+ });
160
+
157
161
  it("returns false for http URLs", () => {
158
162
  expect(isLocalPath("http://example.com/image.png")).toBe(false);
159
163
  expect(isLocalPath("https://example.com/image.png")).toBe(false);
@@ -69,6 +69,11 @@ export function isLocalPath(url: string): boolean {
69
69
  return true;
70
70
  }
71
71
 
72
+ // Windows rooted path on current drive (e.g. \tmp\file.txt)
73
+ if (url.startsWith("\\") && !url.startsWith("\\\\")) {
74
+ return true;
75
+ }
76
+
72
77
  // Windows drive-letter absolute path (e.g. C:\foo\bar.txt or C:/foo/bar.txt)
73
78
  if (/^[a-zA-Z]:[\\/]/.test(url)) {
74
79
  return true;
@@ -16,6 +16,7 @@ vi.mock("./graph-upload.js", async () => {
16
16
  };
17
17
  });
18
18
 
19
+ import { resolvePreferredOpenClawTmpDir } from "../../../src/infra/tmp-openclaw-dir.js";
19
20
  import {
20
21
  type MSTeamsAdapter,
21
22
  renderReplyPayloadsToMessages,
@@ -178,7 +179,7 @@ describe("msteams messenger", () => {
178
179
  });
179
180
 
180
181
  it("preserves parsed mentions when appending OneDrive fallback file links", async () => {
181
- const tmpDir = await mkdtemp(path.join(os.tmpdir(), "msteams-mention-"));
182
+ const tmpDir = await mkdtemp(path.join(resolvePreferredOpenClawTmpDir(), "msteams-mention-"));
182
183
  const localFile = path.join(tmpDir, "note.txt");
183
184
  await writeFile(localFile, "hello");
184
185
 
package/src/messenger.ts CHANGED
@@ -295,7 +295,7 @@ async function buildActivity(
295
295
  // Teams only accepts base64 data URLs for images
296
296
  const conversationType = conversationRef.conversation?.conversationType?.toLowerCase();
297
297
  const isPersonal = conversationType === "personal";
298
- const isImage = contentType?.startsWith("image/") ?? false;
298
+ const isImage = media.kind === "image";
299
299
 
300
300
  if (
301
301
  requiresFileConsent({
@@ -347,7 +347,7 @@ async function buildActivity(
347
347
  return activity;
348
348
  }
349
349
 
350
- if (!isPersonal && !isImage && tokenProvider) {
350
+ if (!isPersonal && media.kind !== "image" && tokenProvider) {
351
351
  // Fallback: no SharePoint site configured, try OneDrive upload
352
352
  const uploaded = await uploadAndShareOneDrive({
353
353
  buffer: media.buffer,
@@ -1,7 +1,6 @@
1
1
  const TTL_MS = 24 * 60 * 60 * 1000; // 24 hours
2
2
 
3
3
  type CacheEntry = {
4
- messageIds: Set<string>;
5
4
  timestamps: Map<string, number>;
6
5
  };
7
6
 
@@ -11,7 +10,6 @@ function cleanupExpired(entry: CacheEntry): void {
11
10
  const now = Date.now();
12
11
  for (const [msgId, timestamp] of entry.timestamps) {
13
12
  if (now - timestamp > TTL_MS) {
14
- entry.messageIds.delete(msgId);
15
13
  entry.timestamps.delete(msgId);
16
14
  }
17
15
  }
@@ -23,12 +21,11 @@ export function recordMSTeamsSentMessage(conversationId: string, messageId: stri
23
21
  }
24
22
  let entry = sentMessages.get(conversationId);
25
23
  if (!entry) {
26
- entry = { messageIds: new Set(), timestamps: new Map() };
24
+ entry = { timestamps: new Map() };
27
25
  sentMessages.set(conversationId, entry);
28
26
  }
29
- entry.messageIds.add(messageId);
30
27
  entry.timestamps.set(messageId, Date.now());
31
- if (entry.messageIds.size > 200) {
28
+ if (entry.timestamps.size > 200) {
32
29
  cleanupExpired(entry);
33
30
  }
34
31
  }
@@ -39,7 +36,7 @@ export function wasMSTeamsMessageSent(conversationId: string, messageId: string)
39
36
  return false;
40
37
  }
41
38
  cleanupExpired(entry);
42
- return entry.messageIds.has(messageId);
39
+ return entry.timestamps.has(messageId);
43
40
  }
44
41
 
45
42
  export function clearMSTeamsSentMessageCache(): void {