@openclaw/msteams 2026.9.6 → 2026.9.8
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/assets/icon.png +0 -0
- package/dist/.setup/{adapter.runtime-CQWZeqB5.cjs → adapter.runtime-BiWeMKXE.cjs} +21 -29
- package/dist/.setup/{approval-card-CPNH_q3P.cjs → approval-card-DWPDItvq.cjs} +6 -3
- package/dist/.setup/{approval-handler.runtime-CUnanUdR.cjs → approval-handler.runtime-D1s7UR3U.cjs} +4 -4
- package/dist/.setup/bot-framework-service-url-BUhTe8F3.cjs +55 -0
- package/dist/.setup/{channel-BDp16XRR.cjs → channel-ByzS7QJ0.cjs} +286 -180
- package/dist/.setup/{channel.runtime-Cv5F8JCa.cjs → channel.runtime-Baz8XDFs.cjs} +43 -142
- package/dist/.setup/{channel.setup-BVDfgdCc.cjs → channel.setup-DL8lcWT_.cjs} +6 -6
- package/dist/.setup/{config-schema-D22Lr1Qk.cjs → config-schema-0KoBzb0t.cjs} +24 -38
- package/dist/.setup/{messenger-8RA1FUJa.cjs → conversation-store-state-B7JuyZTm.cjs} +693 -287
- package/dist/.setup/{src-BfOCwlHp.cjs → monitor-BJ7IyH4y.cjs} +422 -592
- package/dist/.setup/{oauth-C6m7dvHj.cjs → oauth-DQjOnJ4l.cjs} +1 -1
- package/dist/.setup/{reaction-types-C7RA7Wxt.cjs → reaction-types-CQ4oSUe7.cjs} +2 -6
- package/dist/.setup/{resolve-allowlist-CHzaaWiC.cjs → resolve-allowlist-Pl_NQFYH.cjs} +55 -312
- package/dist/.setup/{rolldown-runtime-VH7oDXx4.cjs → rolldown-runtime-BloeesfJ.cjs} +22 -0
- package/dist/.setup/{send-CYN_N7O1.cjs → send-VUM7Sryb.cjs} +43 -96
- package/dist/.setup/{setup-plugin-api-DpiaA8z1.cjs → setup-plugin-api-Dyf8kF-l.cjs} +1 -1
- package/dist/.setup/{thread-session-CXgHK-yi.cjs → thread-session--rw3BTal.cjs} +2 -5
- package/dist/api.cjs +2 -2
- package/dist/channel-config-api.cjs +1 -1
- package/dist/channel-plugin-api.cjs +1 -1
- package/dist/configured-state.cjs +0 -1
- package/dist/directory-contract-api.cjs +1 -1
- package/dist/doctor-contract-api.cjs +201 -371
- package/dist/qa-runner-api.cjs +1 -1
- package/dist/runtime-api.cjs +0 -6
- package/dist/setup-entry.cjs +1 -1
- package/dist/setup-plugin-api.cjs +1 -1
- package/openclaw.plugin.json +46 -5
- package/package.json +9 -9
- package/dist/.setup/polls-BJ4-4uZm.cjs +0 -668
- package/dist/.setup/secret-input-C65t6kjM.cjs +0 -1
- package/dist/.setup/sso-token-store-YYLHXgFH.cjs +0 -111
|
@@ -1,66 +1,192 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_rolldown_runtime = require("./.setup/rolldown-runtime-
|
|
2
|
+
const require_rolldown_runtime = require("./.setup/rolldown-runtime-BloeesfJ.cjs");
|
|
3
3
|
const require_delegated_state = require("./.setup/delegated-state-u-ywZyZT.cjs");
|
|
4
|
-
const require_polls = require("./.setup/polls-BJ4-4uZm.cjs");
|
|
5
|
-
const require_sso_token_store = require("./.setup/sso-token-store-YYLHXgFH.cjs");
|
|
6
4
|
let openclaw_plugin_sdk_string_coerce_runtime = require("openclaw/plugin-sdk/string-coerce-runtime");
|
|
7
|
-
let
|
|
8
|
-
node_crypto = require_rolldown_runtime.__toESM(node_crypto, 1);
|
|
5
|
+
let openclaw_plugin_sdk_error_runtime = require("openclaw/plugin-sdk/error-runtime");
|
|
9
6
|
let node_fs_promises = require("node:fs/promises");
|
|
10
7
|
node_fs_promises = require_rolldown_runtime.__toESM(node_fs_promises, 1);
|
|
11
8
|
let node_path = require("node:path");
|
|
12
9
|
node_path = require_rolldown_runtime.__toESM(node_path, 1);
|
|
13
|
-
let openclaw_plugin_sdk_runtime_doctor_migrations = require("openclaw/plugin-sdk/runtime-doctor-migrations");
|
|
14
10
|
let openclaw_plugin_sdk_session_store_paths = require("openclaw/plugin-sdk/session-store-paths");
|
|
11
|
+
//#region packages/normalization-core/src/record-coerce.ts
|
|
12
|
+
/** Type guard for non-array object records at browser-safe boundaries. */
|
|
13
|
+
function isRecord$1(value) {
|
|
14
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
15
|
+
}
|
|
16
|
+
/** Returns a non-array record or null. */
|
|
17
|
+
function asNullableRecord(value) {
|
|
18
|
+
return isRecord$1(value) ? value : null;
|
|
19
|
+
}
|
|
20
|
+
//#endregion
|
|
21
|
+
//#region src/config/channel-config-normalization.ts
|
|
22
|
+
/** Applies one channel-specific doctor migration to every object-shaped account. */
|
|
23
|
+
function normalizeChannelAccounts(params) {
|
|
24
|
+
const rawAccounts = asNullableRecord(params.entry.accounts);
|
|
25
|
+
if (!rawAccounts) return {
|
|
26
|
+
entry: params.entry,
|
|
27
|
+
changed: false
|
|
28
|
+
};
|
|
29
|
+
let changed = false;
|
|
30
|
+
const accounts = { ...rawAccounts };
|
|
31
|
+
for (const [accountId, value] of Object.entries(rawAccounts)) {
|
|
32
|
+
const account = asNullableRecord(value);
|
|
33
|
+
if (!account) continue;
|
|
34
|
+
const normalized = params.normalizeAccount({
|
|
35
|
+
account,
|
|
36
|
+
accountId,
|
|
37
|
+
pathPrefix: `${params.pathPrefix}.accounts.${accountId}`,
|
|
38
|
+
changes: params.changes
|
|
39
|
+
});
|
|
40
|
+
if (normalized.changed) {
|
|
41
|
+
accounts[accountId] = normalized.entry;
|
|
42
|
+
changed = true;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return changed ? {
|
|
46
|
+
entry: {
|
|
47
|
+
...params.entry,
|
|
48
|
+
accounts
|
|
49
|
+
},
|
|
50
|
+
changed: true
|
|
51
|
+
} : {
|
|
52
|
+
entry: params.entry,
|
|
53
|
+
changed: false
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
/** Applies the same channel-specific doctor migration at root and account scope. */
|
|
57
|
+
function normalizeChannelConfigEntries(params) {
|
|
58
|
+
const changes = params.changes ?? [];
|
|
59
|
+
const channels = params.cfg.channels;
|
|
60
|
+
const entry = asNullableRecord(channels?.[params.channelId]);
|
|
61
|
+
if (!entry) return {
|
|
62
|
+
config: params.cfg,
|
|
63
|
+
changes
|
|
64
|
+
};
|
|
65
|
+
const channelPath = `channels.${params.channelId}`;
|
|
66
|
+
const root = params.normalizeEntry({
|
|
67
|
+
entry,
|
|
68
|
+
pathPrefix: channelPath,
|
|
69
|
+
changes
|
|
70
|
+
});
|
|
71
|
+
const accounts = normalizeChannelAccounts({
|
|
72
|
+
entry: root.entry,
|
|
73
|
+
pathPrefix: channelPath,
|
|
74
|
+
changes,
|
|
75
|
+
normalizeAccount: (accountParams) => params.normalizeEntry({
|
|
76
|
+
entry: accountParams.account,
|
|
77
|
+
accountId: accountParams.accountId,
|
|
78
|
+
pathPrefix: accountParams.pathPrefix,
|
|
79
|
+
changes: accountParams.changes
|
|
80
|
+
})
|
|
81
|
+
});
|
|
82
|
+
if (!root.changed && !accounts.changed) return {
|
|
83
|
+
config: params.cfg,
|
|
84
|
+
changes
|
|
85
|
+
};
|
|
86
|
+
return {
|
|
87
|
+
config: {
|
|
88
|
+
...params.cfg,
|
|
89
|
+
channels: {
|
|
90
|
+
...channels,
|
|
91
|
+
[params.channelId]: accounts.entry
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
changes
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
//#endregion
|
|
98
|
+
//#region src/plugin-sdk/legacy-webhook-listener-migration.ts
|
|
99
|
+
/** Preserve explicitly configured webhook listeners while moving ingress onto Gateway routes. */
|
|
100
|
+
function createLegacyWebhookListenerDoctorContract(params) {
|
|
101
|
+
const portKey = params.portKey ?? "webhookPort";
|
|
102
|
+
const hostKey = params.hostKey === void 0 ? "webhookHost" : params.hostKey;
|
|
103
|
+
const source = (entry) => params.webhookKey ? asNullableRecord(entry[params.webhookKey]) : entry;
|
|
104
|
+
const hasLegacy = (value) => {
|
|
105
|
+
const entry = asNullableRecord(value);
|
|
106
|
+
const listener = entry && source(entry);
|
|
107
|
+
return Boolean(listener && (Object.hasOwn(listener, portKey) || hostKey && Object.hasOwn(listener, hostKey)));
|
|
108
|
+
};
|
|
109
|
+
const prefix = `channels.${params.channelKey}`;
|
|
110
|
+
return {
|
|
111
|
+
legacyConfigRules: [{
|
|
112
|
+
path: ["channels", params.channelKey],
|
|
113
|
+
message: `${prefix} webhook listeners moved to Gateway routes. Run "openclaw doctor --fix" to preserve explicitly configured listener settings as legacyWebhook.`,
|
|
114
|
+
match: (value) => {
|
|
115
|
+
const accounts = asNullableRecord(asNullableRecord(value)?.accounts);
|
|
116
|
+
return hasLegacy(value) || Object.values(accounts ?? {}).some(hasLegacy);
|
|
117
|
+
}
|
|
118
|
+
}],
|
|
119
|
+
normalizeCompatibilityConfig: ({ cfg }) => {
|
|
120
|
+
const root = asNullableRecord(asNullableRecord(cfg.channels)?.[params.channelKey]);
|
|
121
|
+
const inherited = root && source(root);
|
|
122
|
+
const canonicalRoot = asNullableRecord(root?.legacyWebhook);
|
|
123
|
+
return normalizeChannelConfigEntries({
|
|
124
|
+
cfg,
|
|
125
|
+
channelId: params.channelKey,
|
|
126
|
+
normalizeEntry: ({ entry, accountId, pathPrefix, changes }) => {
|
|
127
|
+
const listener = source(entry);
|
|
128
|
+
if (!listener || !hasLegacy(entry)) return {
|
|
129
|
+
entry,
|
|
130
|
+
changed: false
|
|
131
|
+
};
|
|
132
|
+
const next = { ...entry };
|
|
133
|
+
const port = Object.hasOwn(listener, portKey) ? listener[portKey] : (accountId ? canonicalRoot?.port ?? inherited?.[portKey] : void 0) ?? params.defaultPort;
|
|
134
|
+
const inheritedHost = accountId ? canonicalRoot ? canonicalRoot.host : (hostKey ? inherited?.[hostKey] : void 0) ?? params.defaultHost : params.defaultHost;
|
|
135
|
+
const host = hostKey ? listener[hostKey] ?? inheritedHost : inheritedHost;
|
|
136
|
+
const legacyPath = [pathPrefix, params.webhookKey].filter(Boolean).join(".");
|
|
137
|
+
if (Object.hasOwn(entry, "legacyWebhook")) changes.push(`Removed ${legacyPath} legacy listener keys; ${pathPrefix}.legacyWebhook is already configured.`);
|
|
138
|
+
else if (accountId && root?.legacyWebhook === false) changes.push(`Removed ${legacyPath} legacy listener keys; ${prefix}.legacyWebhook: false keeps this account's inherited listener disabled.`);
|
|
139
|
+
else {
|
|
140
|
+
next.legacyWebhook = {
|
|
141
|
+
port,
|
|
142
|
+
...host !== void 0 ? { host } : {}
|
|
143
|
+
};
|
|
144
|
+
changes.push(`Moved ${legacyPath} listener settings to ${pathPrefix}.legacyWebhook. Point the external callback or reverse proxy at the Gateway port and webhook path, verify delivery, then set legacyWebhook: false to disable legacy forwarding.`);
|
|
145
|
+
}
|
|
146
|
+
const updated = params.webhookKey ? { ...listener } : next;
|
|
147
|
+
delete updated[portKey];
|
|
148
|
+
if (hostKey) delete updated[hostKey];
|
|
149
|
+
if (params.webhookKey) {
|
|
150
|
+
if (Object.keys(updated).length) next[params.webhookKey] = updated;
|
|
151
|
+
else delete next[params.webhookKey];
|
|
152
|
+
}
|
|
153
|
+
return {
|
|
154
|
+
entry: next,
|
|
155
|
+
changed: true
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
//#endregion
|
|
163
|
+
//#region \0openclaw:bundled-sdk:openclaw/plugin-sdk/runtime-doctor-migrations
|
|
164
|
+
var runtime_doctor_migrations_exports = /* @__PURE__ */ require_rolldown_runtime.__exportAll({ createLegacyWebhookListenerDoctorContract: () => createLegacyWebhookListenerDoctorContract });
|
|
165
|
+
require_rolldown_runtime.__reExport(runtime_doctor_migrations_exports, require("openclaw/plugin-sdk/runtime-doctor-migrations"));
|
|
166
|
+
//#endregion
|
|
15
167
|
//#region extensions/msteams/config-doctor-api.ts
|
|
16
|
-
const
|
|
168
|
+
const webhookMigration = createLegacyWebhookListenerDoctorContract({
|
|
169
|
+
channelKey: "msteams",
|
|
170
|
+
defaultPort: 3978,
|
|
171
|
+
webhookKey: "webhook",
|
|
172
|
+
portKey: "port",
|
|
173
|
+
hostKey: null
|
|
174
|
+
});
|
|
175
|
+
const streamingAliasMigration = (0, runtime_doctor_migrations_exports.defineChannelAliasMigration)({
|
|
17
176
|
channelId: "msteams",
|
|
18
177
|
streaming: { defaultMode: "partial" }
|
|
19
178
|
});
|
|
20
|
-
const legacyConfigRules = streamingAliasMigration.legacyConfigRules;
|
|
179
|
+
const legacyConfigRules = [...webhookMigration.legacyConfigRules, ...streamingAliasMigration.legacyConfigRules];
|
|
21
180
|
function normalizeCompatibilityConfig({ cfg }) {
|
|
22
|
-
|
|
181
|
+
const webhook = webhookMigration.normalizeCompatibilityConfig({ cfg });
|
|
182
|
+
return streamingAliasMigration.normalizeChannelConfig({
|
|
183
|
+
cfg: webhook.config,
|
|
184
|
+
changes: webhook.changes
|
|
185
|
+
});
|
|
23
186
|
}
|
|
24
187
|
//#endregion
|
|
25
188
|
//#region extensions/msteams/doctor-contract-api.ts
|
|
26
|
-
const LEARNINGS_NAMESPACE = "feedback-learnings";
|
|
27
|
-
const MAX_LEARNING_ENTRIES = 1e4;
|
|
28
189
|
const MSTEAMS_PLUGIN_ID = "Microsoft Teams";
|
|
29
|
-
function encodeSessionKey(sessionKey) {
|
|
30
|
-
return Buffer.from(sessionKey, "utf8").toString("base64url");
|
|
31
|
-
}
|
|
32
|
-
function learningStoreKey(storePath, sessionKey) {
|
|
33
|
-
return node_crypto.default.createHash("sha256").update(`${storePath}\0${sessionKey}`, "utf8").digest("hex");
|
|
34
|
-
}
|
|
35
|
-
function decodeSessionKey(fileStem) {
|
|
36
|
-
try {
|
|
37
|
-
const decoded = Buffer.from(fileStem, "base64url").toString("utf8");
|
|
38
|
-
return encodeSessionKey(decoded) === fileStem && decoded.trim() ? decoded : null;
|
|
39
|
-
} catch {
|
|
40
|
-
return null;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
function resolveLearningSessionKey(fileStem) {
|
|
44
|
-
return decodeSessionKey(fileStem);
|
|
45
|
-
}
|
|
46
|
-
function legacySanitizeSessionKey(sessionKey) {
|
|
47
|
-
return sessionKey.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
48
|
-
}
|
|
49
|
-
async function listKnownSessionKeys(storePath) {
|
|
50
|
-
const candidates = [storePath, node_path.default.join(storePath, "sessions.json")];
|
|
51
|
-
for (const candidate of candidates) try {
|
|
52
|
-
const parsed = JSON.parse(await node_fs_promises.default.readFile(candidate, "utf8"));
|
|
53
|
-
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) continue;
|
|
54
|
-
const sessions = parsed.sessions && typeof parsed.sessions === "object" && !Array.isArray(parsed.sessions) ? parsed.sessions : parsed;
|
|
55
|
-
return Object.keys(sessions).filter((key) => key.trim());
|
|
56
|
-
} catch {}
|
|
57
|
-
return [];
|
|
58
|
-
}
|
|
59
|
-
function resolveLegacySanitizedSessionKey(fileStem, knownSessionKeys) {
|
|
60
|
-
const matches = knownSessionKeys.filter((sessionKey) => legacySanitizeSessionKey(sessionKey) === fileStem);
|
|
61
|
-
const [match] = matches;
|
|
62
|
-
return matches.length === 1 && match ? match : null;
|
|
63
|
-
}
|
|
64
190
|
function listAgentIds(config) {
|
|
65
191
|
const ids = /* @__PURE__ */ new Set(["main"]);
|
|
66
192
|
if ((0, openclaw_plugin_sdk_string_coerce_runtime.isRecord)(config.agents?.entries)) {
|
|
@@ -77,290 +203,48 @@ function listCandidateStorePaths(params) {
|
|
|
77
203
|
}));
|
|
78
204
|
return [...paths];
|
|
79
205
|
}
|
|
80
|
-
function
|
|
81
|
-
return node_path.default.join(stateDir, filename);
|
|
82
|
-
}
|
|
83
|
-
async function readLegacyJsonFile(filePath, parse) {
|
|
84
|
-
try {
|
|
85
|
-
return parse(JSON.parse(await node_fs_promises.default.readFile(filePath, "utf8")));
|
|
86
|
-
} catch {
|
|
87
|
-
return null;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
function isStringArray(value) {
|
|
91
|
-
return Array.isArray(value) && value.every((entry) => typeof entry === "string");
|
|
92
|
-
}
|
|
93
|
-
function parseLegacyConversationStore(value) {
|
|
94
|
-
if (!(0, openclaw_plugin_sdk_string_coerce_runtime.isRecord)(value) || value.version !== 1 || !(0, openclaw_plugin_sdk_string_coerce_runtime.isRecord)(value.conversations)) return null;
|
|
95
|
-
return require_polls.normalizeMSTeamsLegacyConversationStore({
|
|
96
|
-
version: 1,
|
|
97
|
-
conversations: value.conversations
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
|
-
function parseLegacyPoll(value) {
|
|
101
|
-
if (!(0, openclaw_plugin_sdk_string_coerce_runtime.isRecord)(value)) return null;
|
|
102
|
-
const votes = (0, openclaw_plugin_sdk_string_coerce_runtime.isRecord)(value.votes) ? value.votes : null;
|
|
103
|
-
if (typeof value.id !== "string" || !value.id || typeof value.question !== "string" || !value.question || !isStringArray(value.options) || typeof value.maxSelections !== "number" || !Number.isFinite(value.maxSelections) || typeof value.createdAt !== "string" || !votes) return null;
|
|
104
|
-
const normalizedVotes = {};
|
|
105
|
-
for (const [voterId, selections] of Object.entries(votes)) if (typeof voterId === "string" && isStringArray(selections)) normalizedVotes[voterId] = selections;
|
|
106
|
-
return {
|
|
107
|
-
id: value.id,
|
|
108
|
-
question: value.question,
|
|
109
|
-
options: value.options,
|
|
110
|
-
maxSelections: value.maxSelections,
|
|
111
|
-
createdAt: value.createdAt,
|
|
112
|
-
...typeof value.updatedAt === "string" ? { updatedAt: value.updatedAt } : {},
|
|
113
|
-
...typeof value.conversationId === "string" ? { conversationId: value.conversationId } : {},
|
|
114
|
-
...typeof value.messageId === "string" ? { messageId: value.messageId } : {},
|
|
115
|
-
votes: normalizedVotes
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
function parseLegacyPollStore(value) {
|
|
119
|
-
if (!(0, openclaw_plugin_sdk_string_coerce_runtime.isRecord)(value) || value.version !== 1 || !(0, openclaw_plugin_sdk_string_coerce_runtime.isRecord)(value.polls)) return null;
|
|
120
|
-
const polls = {};
|
|
121
|
-
for (const [pollId, poll] of Object.entries(value.polls)) {
|
|
122
|
-
const parsed = parseLegacyPoll(poll);
|
|
123
|
-
if (parsed) polls[pollId] = parsed;
|
|
124
|
-
}
|
|
125
|
-
return {
|
|
126
|
-
version: 1,
|
|
127
|
-
polls
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
async function listLegacyLearningFiles(storePath) {
|
|
131
|
-
let entries;
|
|
206
|
+
async function hasRetiredSource(filePath) {
|
|
132
207
|
try {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
const knownSessionKeys = await listKnownSessionKeys(storePath);
|
|
139
|
-
const files = [];
|
|
140
|
-
for (const entry of entries) {
|
|
141
|
-
if (!entry.isFile() || !entry.name.endsWith(suffix)) continue;
|
|
142
|
-
const fileStem = entry.name.slice(0, -15);
|
|
143
|
-
const sessionKey = resolveLearningSessionKey(fileStem) ?? resolveLegacySanitizedSessionKey(fileStem, knownSessionKeys);
|
|
144
|
-
const filePath = node_path.default.join(storePath, entry.name);
|
|
145
|
-
try {
|
|
146
|
-
const parsed = JSON.parse(await node_fs_promises.default.readFile(filePath, "utf8"));
|
|
147
|
-
if (Array.isArray(parsed)) {
|
|
148
|
-
const learnings = parsed.filter((item) => typeof item === "string");
|
|
149
|
-
if (learnings.length > 0) files.push({
|
|
150
|
-
storePath,
|
|
151
|
-
sessionKey,
|
|
152
|
-
filePath,
|
|
153
|
-
learnings: learnings.slice(-10)
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
|
-
} catch {}
|
|
208
|
+
await node_fs_promises.default.lstat(filePath);
|
|
209
|
+
return true;
|
|
210
|
+
} catch (error) {
|
|
211
|
+
if ((0, openclaw_plugin_sdk_error_runtime.extractErrorCode)(error) === "ENOENT") return false;
|
|
212
|
+
throw error;
|
|
157
213
|
}
|
|
158
|
-
return files;
|
|
159
214
|
}
|
|
160
|
-
function
|
|
161
|
-
const
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
if (
|
|
165
|
-
seen.add(learning);
|
|
166
|
-
merged.push(learning);
|
|
215
|
+
async function hasRetiredLearnings(params) {
|
|
216
|
+
for (const storePath of listCandidateStorePaths(params)) try {
|
|
217
|
+
if ((await node_fs_promises.default.stat(storePath)).isDirectory() && (await node_fs_promises.default.readdir(storePath)).some((name) => name.endsWith(".learnings.json"))) return true;
|
|
218
|
+
} catch (error) {
|
|
219
|
+
if ((0, openclaw_plugin_sdk_error_runtime.extractErrorCode)(error) !== "ENOENT") throw error;
|
|
167
220
|
}
|
|
168
|
-
return
|
|
221
|
+
return false;
|
|
169
222
|
}
|
|
170
|
-
|
|
171
|
-
const {
|
|
172
|
-
const changes = [];
|
|
173
|
-
let missing = 0;
|
|
174
|
-
for (const { store, requiredKeys } of params.stores) {
|
|
175
|
-
const retainedKeys = new Set((await store.entries()).map((entry) => entry.key));
|
|
176
|
-
missing += [...requiredKeys].filter((key) => !retainedKeys.has(key)).length;
|
|
177
|
-
}
|
|
178
|
-
if (missing > 0) {
|
|
179
|
-
warnings.push(`Incomplete ${label} migration: plugin state failed to retain every required entry (${missing} missing); left legacy source in place`);
|
|
180
|
-
return {
|
|
181
|
-
changes,
|
|
182
|
-
warnings
|
|
183
|
-
};
|
|
184
|
-
}
|
|
185
|
-
changes.push(`Migrated ${imported} ${label} ${imported === 1 ? "entry" : "entries"} -> plugin state`);
|
|
186
|
-
await (0, openclaw_plugin_sdk_runtime_doctor_migrations.archiveLegacyStateSource)({
|
|
187
|
-
filePath,
|
|
188
|
-
label: params.archiveLabel ?? label,
|
|
189
|
-
changes,
|
|
190
|
-
warnings
|
|
191
|
-
});
|
|
223
|
+
function retiredJsonMigration(name, label, hasSource) {
|
|
224
|
+
const guidance = `Microsoft Teams ${label} JSON state predates June 2026. Install OpenClaw 2026.9.5, run "openclaw doctor --fix", then upgrade to latest. The legacy source was left untouched.`;
|
|
192
225
|
return {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
};
|
|
196
|
-
}
|
|
197
|
-
const stateMigrations = [
|
|
198
|
-
{
|
|
199
|
-
id: "msteams-conversations-json-to-plugin-state",
|
|
200
|
-
label: "Microsoft Teams conversations",
|
|
201
|
-
async detectLegacyState(params) {
|
|
202
|
-
const state = await readLegacyJsonFile(resolveStateFilePath(params.stateDir, require_polls.MSTEAMS_CONVERSATIONS_LEGACY_FILENAME), parseLegacyConversationStore);
|
|
203
|
-
if (!state || Object.keys(state.conversations).length === 0) return null;
|
|
204
|
-
return { preview: [`- ${MSTEAMS_PLUGIN_ID} conversations: ${Object.keys(state.conversations).length} entries -> plugin state (${require_polls.MSTEAMS_CONVERSATIONS_NAMESPACE})`] };
|
|
205
|
-
},
|
|
206
|
-
async migrateLegacyState(params) {
|
|
207
|
-
const filePath = resolveStateFilePath(params.stateDir, require_polls.MSTEAMS_CONVERSATIONS_LEGACY_FILENAME);
|
|
208
|
-
const state = await readLegacyJsonFile(filePath, parseLegacyConversationStore);
|
|
209
|
-
if (!state) return {
|
|
210
|
-
changes: [],
|
|
211
|
-
warnings: []
|
|
212
|
-
};
|
|
213
|
-
const store = params.context.openPluginStateKeyedStore({
|
|
214
|
-
namespace: require_polls.MSTEAMS_CONVERSATIONS_NAMESPACE,
|
|
215
|
-
maxEntries: require_polls.MSTEAMS_SQLITE_MAX_CONVERSATION_ROWS
|
|
216
|
-
});
|
|
217
|
-
const requiredKeys = new Set((await store.entries()).map((entry) => entry.key));
|
|
218
|
-
let imported = 0;
|
|
219
|
-
for (const [rawConversationId, reference] of require_polls.selectRetainedMSTeamsConversations(state.conversations)) {
|
|
220
|
-
const conversationId = require_polls.normalizeStoredConversationId(rawConversationId);
|
|
221
|
-
if (!conversationId) continue;
|
|
222
|
-
const key = require_polls.buildMSTeamsConversationStateKey(conversationId);
|
|
223
|
-
requiredKeys.add(key);
|
|
224
|
-
const storedReference = require_polls.prepareMSTeamsConversationReferenceForStorage(conversationId, reference);
|
|
225
|
-
if (await store.registerIfAbsent(key, storedReference)) imported++;
|
|
226
|
-
}
|
|
227
|
-
return completeLegacyKeyedImport({
|
|
228
|
-
filePath,
|
|
229
|
-
label: `${MSTEAMS_PLUGIN_ID} conversation`,
|
|
230
|
-
imported,
|
|
231
|
-
warnings: [],
|
|
232
|
-
stores: [{
|
|
233
|
-
store,
|
|
234
|
-
requiredKeys
|
|
235
|
-
}]
|
|
236
|
-
});
|
|
237
|
-
}
|
|
238
|
-
},
|
|
239
|
-
{
|
|
240
|
-
id: "msteams-polls-json-to-plugin-state",
|
|
241
|
-
label: "Microsoft Teams polls",
|
|
242
|
-
async detectLegacyState(params) {
|
|
243
|
-
const state = await readLegacyJsonFile(resolveStateFilePath(params.stateDir, require_polls.MSTEAMS_POLLS_LEGACY_FILENAME), parseLegacyPollStore);
|
|
244
|
-
if (!state || Object.keys(state.polls).length === 0) return null;
|
|
245
|
-
return { preview: [`- ${MSTEAMS_PLUGIN_ID} polls: ${Object.keys(state.polls).length} entries -> plugin state (${require_polls.MSTEAMS_POLLS_NAMESPACE})`] };
|
|
246
|
-
},
|
|
247
|
-
async migrateLegacyState(params) {
|
|
248
|
-
return await require_polls.withMSTeamsSqliteMutationLock({ stateDir: params.stateDir }, require_polls.MSTEAMS_POLLS_NAMESPACE, async () => {
|
|
249
|
-
const filePath = resolveStateFilePath(params.stateDir, require_polls.MSTEAMS_POLLS_LEGACY_FILENAME);
|
|
250
|
-
const state = await readLegacyJsonFile(filePath, parseLegacyPollStore);
|
|
251
|
-
if (!state) return {
|
|
252
|
-
changes: [],
|
|
253
|
-
warnings: []
|
|
254
|
-
};
|
|
255
|
-
const pollStore = params.context.openPluginStateKeyedStore({
|
|
256
|
-
namespace: require_polls.MSTEAMS_POLLS_NAMESPACE,
|
|
257
|
-
maxEntries: require_polls.MSTEAMS_SQLITE_MAX_POLL_ROWS
|
|
258
|
-
});
|
|
259
|
-
const voteBucketStore = params.context.openPluginStateKeyedStore({
|
|
260
|
-
namespace: require_polls.MSTEAMS_POLL_VOTE_BUCKETS_NAMESPACE,
|
|
261
|
-
maxEntries: require_polls.MSTEAMS_MAX_POLL_VOTE_BUCKET_ROWS
|
|
262
|
-
});
|
|
263
|
-
const requiredPollKeys = new Set((await pollStore.entries()).map((entry) => entry.key));
|
|
264
|
-
const requiredVoteKeys = new Set((await voteBucketStore.entries()).map((entry) => entry.key));
|
|
265
|
-
let imported = 0;
|
|
266
|
-
for (const [pollId, poll] of require_polls.selectRetainedMSTeamsPolls(state.polls)) {
|
|
267
|
-
const { metadata, votes } = require_polls.splitMSTeamsPoll(poll);
|
|
268
|
-
const pollKey = require_polls.buildMSTeamsPollStateKey(pollId);
|
|
269
|
-
requiredPollKeys.add(pollKey);
|
|
270
|
-
const didImportPoll = await pollStore.registerIfAbsent(pollKey, metadata);
|
|
271
|
-
const buckets = /* @__PURE__ */ new Map();
|
|
272
|
-
for (const [voterId, selections] of Object.entries(votes)) {
|
|
273
|
-
const bucket = require_polls.selectMSTeamsPollVoteBucket(pollId, voterId);
|
|
274
|
-
const bucketVotes = buckets.get(bucket) ?? {};
|
|
275
|
-
bucketVotes[voterId] = selections;
|
|
276
|
-
buckets.set(bucket, bucketVotes);
|
|
277
|
-
}
|
|
278
|
-
let importedVoteBucket = false;
|
|
279
|
-
for (const [bucket, bucketVotes] of buckets) {
|
|
280
|
-
const key = require_polls.buildMSTeamsPollVoteBucketKey(pollId, bucket);
|
|
281
|
-
requiredVoteKeys.add(key);
|
|
282
|
-
const existing = await voteBucketStore.lookup(key);
|
|
283
|
-
await voteBucketStore.register(key, {
|
|
284
|
-
pollId,
|
|
285
|
-
bucket,
|
|
286
|
-
votes: {
|
|
287
|
-
...bucketVotes,
|
|
288
|
-
...existing?.votes
|
|
289
|
-
},
|
|
290
|
-
updatedAt: poll.updatedAt ?? poll.createdAt
|
|
291
|
-
});
|
|
292
|
-
importedVoteBucket = true;
|
|
293
|
-
}
|
|
294
|
-
if (didImportPoll || importedVoteBucket) imported++;
|
|
295
|
-
}
|
|
296
|
-
return completeLegacyKeyedImport({
|
|
297
|
-
filePath,
|
|
298
|
-
label: `${MSTEAMS_PLUGIN_ID} poll`,
|
|
299
|
-
imported,
|
|
300
|
-
warnings: [],
|
|
301
|
-
stores: [{
|
|
302
|
-
store: pollStore,
|
|
303
|
-
requiredKeys: requiredPollKeys
|
|
304
|
-
}, {
|
|
305
|
-
store: voteBucketStore,
|
|
306
|
-
requiredKeys: requiredVoteKeys
|
|
307
|
-
}]
|
|
308
|
-
});
|
|
309
|
-
});
|
|
310
|
-
}
|
|
311
|
-
},
|
|
312
|
-
{
|
|
313
|
-
id: "msteams-sso-tokens-json-to-plugin-state",
|
|
314
|
-
label: "Microsoft Teams SSO tokens",
|
|
226
|
+
id: `msteams-${name}-json-to-plugin-state`,
|
|
227
|
+
label: `Microsoft Teams ${label}`,
|
|
315
228
|
async detectLegacyState(params) {
|
|
316
|
-
|
|
317
|
-
if (!state || Object.keys(state.tokens).length === 0) return null;
|
|
318
|
-
return { preview: [`- ${MSTEAMS_PLUGIN_ID} SSO tokens: ${Object.keys(state.tokens).length} entries -> plugin state (${require_sso_token_store.MSTEAMS_SSO_TOKENS_NAMESPACE})`] };
|
|
229
|
+
return await hasSource(params) ? { preview: [guidance] } : null;
|
|
319
230
|
},
|
|
320
231
|
async migrateLegacyState(params) {
|
|
321
|
-
|
|
322
|
-
const filePath = resolveStateFilePath(params.stateDir, require_sso_token_store.MSTEAMS_SSO_TOKENS_LEGACY_FILENAME);
|
|
323
|
-
const state = await readLegacyJsonFile(filePath, (value) => require_sso_token_store.isMSTeamsSsoStoreData(value) ? value : null);
|
|
324
|
-
if (!state) return {
|
|
232
|
+
return {
|
|
325
233
|
changes: [],
|
|
326
|
-
warnings
|
|
234
|
+
warnings: await hasSource(params) ? [guidance] : []
|
|
327
235
|
};
|
|
328
|
-
const store = params.context.openPluginStateKeyedStore({
|
|
329
|
-
namespace: require_sso_token_store.MSTEAMS_SSO_TOKENS_NAMESPACE,
|
|
330
|
-
maxEntries: require_sso_token_store.MSTEAMS_MAX_SSO_TOKENS
|
|
331
|
-
});
|
|
332
|
-
const requiredKeys = new Set((await store.entries()).map((entry) => entry.key));
|
|
333
|
-
let imported = 0;
|
|
334
|
-
let skipped = 0;
|
|
335
|
-
for (const token of Object.values(state.tokens)) {
|
|
336
|
-
const normalized = require_sso_token_store.normalizeMSTeamsSsoStoredToken(token);
|
|
337
|
-
if (!normalized) {
|
|
338
|
-
skipped++;
|
|
339
|
-
continue;
|
|
340
|
-
}
|
|
341
|
-
const key = require_sso_token_store.makeMSTeamsSsoTokenStoreKey(normalized.connectionName, normalized.userId);
|
|
342
|
-
requiredKeys.add(key);
|
|
343
|
-
if (await store.registerIfAbsent(key, normalized)) imported++;
|
|
344
|
-
}
|
|
345
|
-
if (skipped > 0) warnings.push(`Skipped ${skipped} malformed ${MSTEAMS_PLUGIN_ID} SSO token ${skipped === 1 ? "entry" : "entries"} during migration`);
|
|
346
|
-
return completeLegacyKeyedImport({
|
|
347
|
-
filePath,
|
|
348
|
-
label: `${MSTEAMS_PLUGIN_ID} SSO token`,
|
|
349
|
-
archiveLabel: `${MSTEAMS_PLUGIN_ID} SSO-token`,
|
|
350
|
-
imported,
|
|
351
|
-
warnings,
|
|
352
|
-
stores: [{
|
|
353
|
-
store,
|
|
354
|
-
requiredKeys
|
|
355
|
-
}]
|
|
356
|
-
});
|
|
357
236
|
}
|
|
358
|
-
}
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
const stateMigrations = [
|
|
240
|
+
retiredJsonMigration("conversations", "conversations", (params) => hasRetiredSource(node_path.default.join(params.stateDir, "msteams-conversations.json"))),
|
|
241
|
+
retiredJsonMigration("polls", "polls", (params) => hasRetiredSource(node_path.default.join(params.stateDir, "msteams-polls.json"))),
|
|
242
|
+
retiredJsonMigration("sso-tokens", "SSO tokens", (params) => hasRetiredSource(node_path.default.join(params.stateDir, "msteams-sso-tokens.json"))),
|
|
359
243
|
{
|
|
360
244
|
id: "msteams-delegated-token-json-to-plugin-state",
|
|
361
245
|
label: "Microsoft Teams delegated OAuth token",
|
|
362
246
|
async detectLegacyState(params) {
|
|
363
|
-
const filePath =
|
|
247
|
+
const filePath = node_path.default.join(params.stateDir, require_delegated_state.MSTEAMS_DELEGATED_TOKEN_LEGACY_FILENAME);
|
|
364
248
|
try {
|
|
365
249
|
return (await node_fs_promises.default.stat(filePath)).isFile() ? { preview: [`- ${MSTEAMS_PLUGIN_ID} delegated OAuth token -> plugin state (${require_delegated_state.MSTEAMS_DELEGATED_TOKEN_NAMESPACE})`] } : null;
|
|
366
250
|
} catch {
|
|
@@ -370,7 +254,7 @@ const stateMigrations = [
|
|
|
370
254
|
async migrateLegacyState(params) {
|
|
371
255
|
const changes = [];
|
|
372
256
|
const warnings = [];
|
|
373
|
-
const filePath =
|
|
257
|
+
const filePath = node_path.default.join(params.stateDir, require_delegated_state.MSTEAMS_DELEGATED_TOKEN_LEGACY_FILENAME);
|
|
374
258
|
let token;
|
|
375
259
|
try {
|
|
376
260
|
token = require_delegated_state.normalizeMSTeamsDelegatedTokens(JSON.parse(await node_fs_promises.default.readFile(filePath, "utf8")));
|
|
@@ -423,7 +307,7 @@ const stateMigrations = [
|
|
|
423
307
|
};
|
|
424
308
|
}
|
|
425
309
|
changes.push(`Migrated ${MSTEAMS_PLUGIN_ID} delegated OAuth token -> plugin state`);
|
|
426
|
-
await (0,
|
|
310
|
+
await (0, runtime_doctor_migrations_exports.archiveLegacyStateSource)({
|
|
427
311
|
filePath,
|
|
428
312
|
label: `${MSTEAMS_PLUGIN_ID} delegated OAuth token`,
|
|
429
313
|
changes,
|
|
@@ -435,61 +319,7 @@ const stateMigrations = [
|
|
|
435
319
|
};
|
|
436
320
|
}
|
|
437
321
|
},
|
|
438
|
-
|
|
439
|
-
id: "msteams-feedback-learnings-json-to-plugin-state",
|
|
440
|
-
label: "Microsoft Teams feedback learnings",
|
|
441
|
-
async detectLegacyState(params) {
|
|
442
|
-
const files = (await Promise.all(listCandidateStorePaths(params).map((storePath) => listLegacyLearningFiles(storePath)))).flat();
|
|
443
|
-
if (files.length === 0) return null;
|
|
444
|
-
return { preview: [`- Microsoft Teams feedback learnings: ${files.length} ${files.length === 1 ? "file" : "files"} -> plugin state (${LEARNINGS_NAMESPACE})`] };
|
|
445
|
-
},
|
|
446
|
-
async migrateLegacyState(params) {
|
|
447
|
-
const changes = [];
|
|
448
|
-
const warnings = [];
|
|
449
|
-
const files = (await Promise.all(listCandidateStorePaths(params).map((storePath) => listLegacyLearningFiles(storePath)))).flat();
|
|
450
|
-
const store = params.context.openPluginStateKeyedStore({
|
|
451
|
-
namespace: LEARNINGS_NAMESPACE,
|
|
452
|
-
maxEntries: MAX_LEARNING_ENTRIES
|
|
453
|
-
});
|
|
454
|
-
const existingEntries = await store.entries();
|
|
455
|
-
const existingKeys = new Set(existingEntries.map((entry) => entry.key));
|
|
456
|
-
const importableFiles = files.filter((file) => file.sessionKey);
|
|
457
|
-
const missingKeys = new Set(importableFiles.map((file) => learningStoreKey(file.storePath, file.sessionKey ?? "")).filter((key) => !existingKeys.has(key)));
|
|
458
|
-
if (missingKeys.size > MAX_LEARNING_ENTRIES - existingKeys.size) {
|
|
459
|
-
warnings.push(`Skipped Microsoft Teams feedback-learning migration because plugin state has room for ${MAX_LEARNING_ENTRIES - existingKeys.size} of ${missingKeys.size} missing entries; left legacy sources in place`);
|
|
460
|
-
return {
|
|
461
|
-
changes,
|
|
462
|
-
warnings
|
|
463
|
-
};
|
|
464
|
-
}
|
|
465
|
-
let imported = 0;
|
|
466
|
-
for (const file of files) {
|
|
467
|
-
if (!file.sessionKey) {
|
|
468
|
-
warnings.push(`Left Microsoft Teams feedback-learning source in place because its legacy filename cannot be mapped to a session key: ${file.filePath}`);
|
|
469
|
-
continue;
|
|
470
|
-
}
|
|
471
|
-
const key = learningStoreKey(file.storePath, file.sessionKey);
|
|
472
|
-
const existing = await store.lookup(key);
|
|
473
|
-
await store.register(key, {
|
|
474
|
-
sessionKey: existing?.sessionKey ?? file.sessionKey,
|
|
475
|
-
learnings: mergeLearnings(file.learnings, existing),
|
|
476
|
-
updatedAt: Date.now()
|
|
477
|
-
});
|
|
478
|
-
imported++;
|
|
479
|
-
await (0, openclaw_plugin_sdk_runtime_doctor_migrations.archiveLegacyStateSource)({
|
|
480
|
-
filePath: file.filePath,
|
|
481
|
-
label: "Microsoft Teams feedback-learning",
|
|
482
|
-
changes,
|
|
483
|
-
warnings
|
|
484
|
-
});
|
|
485
|
-
}
|
|
486
|
-
if (imported > 0) changes.unshift(`Migrated ${imported} Microsoft Teams feedback-learning ${imported === 1 ? "entry" : "entries"} -> plugin state`);
|
|
487
|
-
return {
|
|
488
|
-
changes,
|
|
489
|
-
warnings
|
|
490
|
-
};
|
|
491
|
-
}
|
|
492
|
-
}
|
|
322
|
+
retiredJsonMigration("feedback-learnings", "feedback learnings", hasRetiredLearnings)
|
|
493
323
|
];
|
|
494
324
|
//#endregion
|
|
495
325
|
exports.legacyConfigRules = legacyConfigRules;
|
package/dist/qa-runner-api.cjs
CHANGED
|
@@ -2,7 +2,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
|
2
2
|
let openclaw_plugin_sdk_qa_runner_runtime = require("openclaw/plugin-sdk/qa-runner-runtime");
|
|
3
3
|
//#region extensions/msteams/src/qa/cli.ts
|
|
4
4
|
const DEFAULT_MSTEAMS_QA_SCENARIOS = ["channel-canary"];
|
|
5
|
-
const loadMSTeamsQaAdapterRuntime = (0, openclaw_plugin_sdk_qa_runner_runtime.createLazyCliRuntimeLoader)(() => Promise.resolve().then(() => require("./.setup/adapter.runtime-
|
|
5
|
+
const loadMSTeamsQaAdapterRuntime = (0, openclaw_plugin_sdk_qa_runner_runtime.createLazyCliRuntimeLoader)(() => Promise.resolve().then(() => require("./.setup/adapter.runtime-BiWeMKXE.cjs")));
|
|
6
6
|
async function runQaMSTeams(options) {
|
|
7
7
|
await (0, openclaw_plugin_sdk_qa_runner_runtime.runLiveTransportQaSuiteCommand)({
|
|
8
8
|
channelId: "msteams",
|
package/dist/runtime-api.cjs
CHANGED
|
@@ -114,12 +114,6 @@ Object.defineProperty(exports, "isDangerousNameMatchingEnabled", {
|
|
|
114
114
|
return openclaw_plugin_sdk_dangerous_name_runtime.isDangerousNameMatchingEnabled;
|
|
115
115
|
}
|
|
116
116
|
});
|
|
117
|
-
Object.defineProperty(exports, "keepHttpServerTaskAlive", {
|
|
118
|
-
enumerable: true,
|
|
119
|
-
get: function() {
|
|
120
|
-
return openclaw_plugin_sdk_channel_outbound.keepHttpServerTaskAlive;
|
|
121
|
-
}
|
|
122
|
-
});
|
|
123
117
|
Object.defineProperty(exports, "loadOutboundMediaFromUrl", {
|
|
124
118
|
enumerable: true,
|
|
125
119
|
get: function() {
|
package/dist/setup-entry.cjs
CHANGED
|
@@ -4,7 +4,7 @@ let node_url = require("node:url");
|
|
|
4
4
|
var setup_entry_default = (0, openclaw_plugin_sdk_channel_entry_contract.defineBundledChannelSetupEntry)({
|
|
5
5
|
importMetaUrl: require("url").pathToFileURL(__filename).href,
|
|
6
6
|
plugin: {
|
|
7
|
-
specifier: (0, node_url.fileURLToPath)(new URL(".setup/setup-plugin-api-
|
|
7
|
+
specifier: (0, node_url.fileURLToPath)(new URL(".setup/setup-plugin-api-Dyf8kF-l.cjs", require("url").pathToFileURL(__filename).href).href),
|
|
8
8
|
exportName: "msteamsSetupPlugin"
|
|
9
9
|
},
|
|
10
10
|
secrets: {
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_channel_setup = require("./.setup/channel.setup-
|
|
2
|
+
const require_channel_setup = require("./.setup/channel.setup-DL8lcWT_.cjs");
|
|
3
3
|
exports.msteamsSetupPlugin = require_channel_setup.msteamsSetupPlugin;
|