@meet-im/meet 1.1.2 → 2.0.0

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/README.md CHANGED
@@ -1 +1 @@
1
- # @meet-im/meet-channel
1
+ # @meet-im/meet
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meet-im/meet",
3
- "version": "1.1.2",
3
+ "version": "2.0.0",
4
4
  "type": "module",
5
5
  "description": "OpenClaw Meet channel plugin",
6
6
  "scripts": {
@@ -61,13 +61,13 @@
61
61
  "devDependencies": {
62
62
  "@types/node": "^22.0.0",
63
63
  "@vitest/coverage-v8": "^2.1.8",
64
- "openclaw": "2026.3.8",
64
+ "openclaw": "2026.3.23",
65
65
  "tsx": "^4.21.0",
66
66
  "typescript": "^5.7.0",
67
67
  "vitest": "^2.1.8"
68
68
  },
69
69
  "peerDependencies": {
70
- "openclaw": ">=2026.3.8"
70
+ "openclaw": ">=2026.3.23"
71
71
  },
72
72
  "publishConfig": {
73
73
  "access": "public"
package/src/accounts.ts CHANGED
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  DEFAULT_ACCOUNT_ID,
3
3
  normalizeAccountId,
4
- createAccountListHelpers,
5
- type ClawdbotConfig,
6
- } from "openclaw/plugin-sdk"
4
+ } from "openclaw/plugin-sdk/account-id"
5
+ import { createAccountListHelpers } from "openclaw/plugin-sdk/account-helpers"
6
+ import type { ClawdbotConfig } from "openclaw/plugin-sdk"
7
7
  import type { MeetConfig, MeetAccountConfig, ResolvedMeetAccount } from "./types.js"
8
8
 
9
9
  const { listAccountIds: listNestedAccountIds, resolveDefaultAccountId: resolveNestedDefaultAccountId } = createAccountListHelpers("meet")
@@ -105,7 +105,7 @@ function mergeMeetAccountConfig(
105
105
  const { accounts: _ignored, ...base } = meetCfg ?? {}
106
106
  const account = resolveAccountConfig(cfg, accountId) ?? {}
107
107
 
108
- const baseGroups = base.groups ?? {}
108
+ const baseGroups = (base as MeetConfig).groups ?? {}
109
109
  const accountGroups = (account as MeetConfig).groups ?? {}
110
110
  const mergedGroups = { ...baseGroups, ...accountGroups }
111
111
 
package/src/bot.ts CHANGED
@@ -1,10 +1,11 @@
1
- import type { ClawdbotConfig, RuntimeEnv, ReplyPayload, HistoryEntry } from "openclaw/plugin-sdk"
1
+ import type { ClawdbotConfig, RuntimeEnv } from "openclaw/plugin-sdk"
2
+ import type { HistoryEntry } from "openclaw/plugin-sdk/reply-history"
2
3
  import {
3
4
  buildPendingHistoryContextFromMap,
4
5
  clearHistoryEntriesIfEnabled,
5
6
  recordPendingHistoryEntryIfEnabled,
6
- DEFAULT_ACCOUNT_ID,
7
- } from "openclaw/plugin-sdk"
7
+ } from "openclaw/plugin-sdk/reply-history"
8
+ import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/account-id"
8
9
  import type { MeetBot, MsgContent } from "@meet-im/meet-bot-jssdk"
9
10
  import type { ResolvedMeetAccount, MeetMessageContext } from "./types.js"
10
11
  import { msgContentToContext, extractQuoteMessageMedia } from "./sdk-bridge.js"
package/src/channel.ts CHANGED
@@ -1,13 +1,13 @@
1
1
  import type {
2
2
  ChannelPlugin,
3
3
  ClawdbotConfig,
4
- GroupToolPolicyConfig,
5
4
  } from "openclaw/plugin-sdk";
5
+ import type { GroupToolPolicyConfig } from "openclaw/plugin-sdk/channel-policy";
6
6
  import {
7
7
  DEFAULT_ACCOUNT_ID,
8
8
  normalizeAccountId,
9
- PAIRING_APPROVED_MESSAGE,
10
- } from "openclaw/plugin-sdk";
9
+ } from "openclaw/plugin-sdk/account-id";
10
+ import { PAIRING_APPROVED_MESSAGE } from "openclaw/plugin-sdk/channel-status";
11
11
  import type { ResolvedMeetAccount, MeetConfig } from "./types.js";
12
12
  import {
13
13
  resolveMeetAccount,
@@ -69,9 +69,9 @@ export const meetPlugin: ChannelPlugin<ResolvedMeetAccount> = {
69
69
  },
70
70
  groups: {
71
71
  resolveToolPolicy: ({
72
- cfg,
73
- accountId,
74
- groupId,
72
+ cfg: _cfg,
73
+ accountId: _accountId,
74
+ groupId: _groupId,
75
75
  }): GroupToolPolicyConfig | undefined => {
76
76
  // 群组访问控制在 bot.ts 中处理,这里只返回工具策略配置
77
77
  // 不使用 { deny: ["*"] } 拒绝所有工具,否则会导致 tools: []
@@ -378,7 +378,7 @@ export const meetPlugin: ChannelPlugin<ResolvedMeetAccount> = {
378
378
  gateway: {
379
379
  startAccount: async (ctx) => {
380
380
  const { monitorMeetProvider } = await import("./monitor.js");
381
- const account = resolveMeetAccount({
381
+ resolveMeetAccount({
382
382
  cfg: ctx.cfg,
383
383
  accountId: ctx.accountId,
384
384
  });
package/src/monitor.ts CHANGED
@@ -1,5 +1,6 @@
1
- import type { ClawdbotConfig, RuntimeEnv, HistoryEntry } from "openclaw/plugin-sdk"
2
- import { KeyedAsyncQueue } from "openclaw/plugin-sdk"
1
+ import type { ClawdbotConfig, RuntimeEnv } from "openclaw/plugin-sdk"
2
+ import type { HistoryEntry } from "openclaw/plugin-sdk/reply-history"
3
+ import { KeyedAsyncQueue } from "openclaw/plugin-sdk/keyed-async-queue"
3
4
  import type { ResolvedMeetAccount } from "./types.js"
4
5
  import type { MsgContent } from "@meet-im/meet-bot-jssdk"
5
6
  import type { QuoteMsgMap } from "./sdk-bridge.js"
@@ -22,7 +23,6 @@ export async function monitorMeetProvider(opts: MonitorMeetOpts = {}): Promise<v
22
23
  }
23
24
 
24
25
  const log = opts.runtime?.log ?? console.log
25
- const error = opts.runtime?.error ?? console.error
26
26
 
27
27
  if (opts.accountId) {
28
28
  const account = resolveMeetAccount({ cfg, accountId: opts.accountId })
@@ -99,9 +99,7 @@ async function monitorSingleAccount(params: {
99
99
 
100
100
  abortSignal?.addEventListener("abort", handleAbort, { once: true })
101
101
 
102
- // TODO: SDK 更新后移除类型断言
103
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
104
- bot.on("message", ((data: { message: MsgContent; quoteMsgMap: QuoteMsgMap }) => {
102
+ bot.on("message", (data: { message: MsgContent; quoteMsgMap: QuoteMsgMap }) => {
105
103
  const { message: msg, quoteMsgMap } = data
106
104
  let queueKey: string
107
105
  try {
@@ -149,7 +147,7 @@ async function monitorSingleAccount(params: {
149
147
  },
150
148
  },
151
149
  )
152
- }) as any)
150
+ })
153
151
 
154
152
  bot.on("error", (err) => {
155
153
  error(`[${accountId}]: polling error: ${String(err)}`)
package/src/outbound.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { ChannelOutboundAdapter } from "openclaw/plugin-sdk";
1
+ import type { ChannelOutboundAdapter } from "openclaw/plugin-sdk/channel-send-result";
2
2
  import { getMeetRuntime } from "./runtime.js";
3
3
  import { sendMessageMeet, sendMediaMeet } from "./send.js";
4
4
 
@@ -11,8 +11,13 @@ export const meetOutbound: ChannelOutboundAdapter = {
11
11
  chunkerMode: "text",
12
12
  textChunkLimit: 4000,
13
13
  sendText: async ({ cfg, to, text, accountId }) => {
14
- const result = await sendMessageMeet({ cfg, to, text, accountId });
15
- return { channel: "meet", ...result };
14
+ const result = await sendMessageMeet({
15
+ cfg,
16
+ to,
17
+ text: text ?? "",
18
+ accountId: accountId ?? undefined,
19
+ });
20
+ return { channel: "meet", messageId: result.messageId, chatId: result.chatId };
16
21
  },
17
22
  sendMedia: async ({
18
23
  cfg,
@@ -22,14 +27,17 @@ export const meetOutbound: ChannelOutboundAdapter = {
22
27
  mediaLocalRoots,
23
28
  accountId,
24
29
  }) => {
30
+ if (!mediaUrl) {
31
+ throw new Error("mediaUrl is required for sendMedia");
32
+ }
25
33
  const result = await sendMediaMeet({
26
34
  cfg,
27
35
  to,
28
- text: text || undefined,
36
+ text: text ?? undefined,
29
37
  mediaUrl,
30
- mediaLocalRoots,
31
- accountId,
38
+ mediaLocalRoots: mediaLocalRoots ?? undefined,
39
+ accountId: accountId ?? undefined,
32
40
  });
33
- return { channel: "meet", ...result };
41
+ return { channel: "meet", messageId: result.messageId, chatId: result.chatId };
34
42
  },
35
43
  };
@@ -1,14 +1,9 @@
1
1
  import type { MeetBot } from "@meet-im/meet-bot-jssdk"
2
2
  import type { ClawdbotConfig, RuntimeEnv, ReplyPayload } from "openclaw/plugin-sdk"
3
- import { createReplyPrefixContext } from "openclaw/plugin-sdk"
3
+ import { createReplyPrefixContext } from "openclaw/plugin-sdk/channel-runtime"
4
4
  import { getMeetRuntime } from "./runtime.js"
5
5
  import { sendMessageMeet } from "./send.js"
6
6
 
7
- /**
8
- * 匹配完整的 mention 格式: <@userId>
9
- */
10
- const COMPLETE_MENTION_REGEX = /<@(-?\d+)>/g
11
-
12
7
  /**
13
8
  * 匹配末尾不完整的 mention 开始: <@ 或 <@xxx (没有闭合的 >)
14
9
  */
@@ -100,7 +95,7 @@ export async function createMeetReplyDispatcher(
100
95
  humanDelay: core.channel.reply.resolveHumanDelayConfig(cfg, agentId),
101
96
  onReplyStart: async () => {
102
97
  },
103
- deliver: async (payload: ReplyPayload, info) => {
98
+ deliver: async (payload: ReplyPayload, _info) => {
104
99
  const text = payload.text ?? ""
105
100
  if (!text.trim()) {
106
101
  return
package/src/sdk-bridge.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { MsgContent, SessionInfo, SessionType, AttachmentInfo } from "@meet-im/meet-bot-jssdk"
1
+ import type { MsgContent, SessionInfo, SessionType } from "@meet-im/meet-bot-jssdk"
2
2
  import type { MeetMessageContext, MeetReplyContext, MeetMediaAttachment } from "./types.js"
3
3
 
4
4
  // TODO: 从 SDK 导入,等待 SDK 发布
package/src/send.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { ClawdbotConfig, RuntimeEnv } from "openclaw/plugin-sdk";
2
- import type { ResolvedMeetAccount, MeetMediaInfo } from "./types.js";
2
+ import type { MeetMediaInfo } from "./types.js";
3
3
  import type { UploadProgress as SdkUploadProgress } from "@meet-im/meet-bot-jssdk";
4
4
  import { resolveMeetAccount } from "./accounts.js";
5
5
  import { getMeetClient } from "./client.js";
@@ -52,6 +52,57 @@ export function inferContentTypeFromFileName(fileName: string): string | undefin
52
52
  return mimeMap[ext];
53
53
  }
54
54
 
55
+ /**
56
+ * 根据 MIME 类型获取文件扩展名
57
+ */
58
+ function getExtensionFromContentType(contentType: string): string | undefined {
59
+ const mimeToExt: Record<string, string> = {
60
+ "image/jpeg": ".jpg",
61
+ "image/png": ".png",
62
+ "image/gif": ".gif",
63
+ "image/webp": ".webp",
64
+ "image/avif": ".avif",
65
+ "image/heic": ".heic",
66
+ "image/heif": ".heif",
67
+ "image/bmp": ".bmp",
68
+ "image/x-icon": ".ico",
69
+ "image/svg+xml": ".svg",
70
+ "image/tiff": ".tiff",
71
+ "video/mp4": ".mp4",
72
+ "video/webm": ".webm",
73
+ "video/quicktime": ".mov",
74
+ "video/x-msvideo": ".avi",
75
+ "video/x-matroska": ".mkv",
76
+ "audio/mpeg": ".mp3",
77
+ "audio/wav": ".wav",
78
+ "audio/ogg": ".ogg",
79
+ "audio/flac": ".flac",
80
+ "audio/mp4": ".m4a",
81
+ "application/pdf": ".pdf",
82
+ "application/json": ".json",
83
+ "application/xml": ".xml",
84
+ };
85
+ return mimeToExt[contentType];
86
+ }
87
+
88
+ /**
89
+ * 确保文件名有正确的扩展名
90
+ * 如果文件名没有扩展名,根据 contentType 添加
91
+ */
92
+ function ensureFileNameExtension(fileName: string, contentType: string): string {
93
+ // 检查是否已有扩展名
94
+ const hasExtension = /\.[a-zA-Z0-9]+$/.test(fileName);
95
+ if (hasExtension) {
96
+ return fileName;
97
+ }
98
+ // 根据 contentType 添加扩展名
99
+ const ext = getExtensionFromContentType(contentType);
100
+ if (ext) {
101
+ return fileName + ext;
102
+ }
103
+ return fileName;
104
+ }
105
+
55
106
  /**
56
107
  * 获取最终的 contentType
57
108
  * 如果原始 contentType 缺失或为通用二进制流,则根据文件名推断
@@ -207,8 +258,10 @@ export async function sendMediaMeet(
207
258
  }
208
259
 
209
260
  const sessionInfo = parseTargetToSessionInfo(to, Number(botUserId));
210
- const fileName = media.fileName || "file";
211
- const contentType = resolveContentType(fileName, media.contentType);
261
+ const rawFileName = media.fileName || "file";
262
+ const contentType = resolveContentType(rawFileName, media.contentType);
263
+ // 确保文件名有正确的扩展名
264
+ const fileName = ensureFileNameExtension(rawFileName, contentType);
212
265
 
213
266
  log(
214
267
  `sending media to=${to} fileName=${fileName} size=${media.buffer.length} contentType=${contentType}`,
@@ -279,7 +332,7 @@ export async function getMessageMeet(opts: {
279
332
  messageId: string;
280
333
  accountId?: string;
281
334
  }): Promise<{ content: string } | null> {
282
- const { cfg, messageId, accountId } = opts;
335
+ const { cfg, accountId } = opts;
283
336
  const account = resolveMeetAccount({ cfg, accountId });
284
337
  if (!account.configured) {
285
338
  return null;