@meet-im/meet 3.4.5 → 3.5.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/dist/src/approval-native.d.ts +30 -0
- package/dist/src/approval-native.js +235 -0
- package/dist/src/channel.js +2 -0
- package/dist/src/config-schema.d.ts +44 -0
- package/dist/src/config-schema.js +9 -0
- package/dist/src/exec-approvals.d.ts +26 -0
- package/dist/src/exec-approvals.js +71 -0
- package/dist/src/generated/plugin-build-meta.d.ts +1 -1
- package/dist/src/generated/plugin-build-meta.js +1 -1
- package/dist/src/outbound.js +9 -0
- package/dist/src/send.d.ts +1 -0
- package/dist/src/send.js +8 -2
- package/dist/src/types.d.ts +2 -1
- package/openclaw.plugin.json +32 -0
- package/package.json +1 -1
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type ChannelApprovalNativeRuntimeAdapter } from "openclaw/plugin-sdk/approval-handler-runtime";
|
|
2
|
+
import type { ChannelApprovalCapability } from "openclaw/plugin-sdk/channel-contract";
|
|
3
|
+
import type { MeetExecApprovalConfig } from "./types.js";
|
|
4
|
+
type MeetPendingPayload = {
|
|
5
|
+
text: string;
|
|
6
|
+
};
|
|
7
|
+
type MeetPreparedTarget = {
|
|
8
|
+
to: string;
|
|
9
|
+
threadId?: string;
|
|
10
|
+
};
|
|
11
|
+
type MeetPendingEntry = {
|
|
12
|
+
chatId: string;
|
|
13
|
+
messageId: string;
|
|
14
|
+
};
|
|
15
|
+
export declare const meetApprovalNativeRuntime: ChannelApprovalNativeRuntimeAdapter<MeetPendingPayload, MeetPreparedTarget, MeetPendingEntry, never, unknown>;
|
|
16
|
+
export declare function createMeetNativeApprovalAdapter(configOverride?: MeetExecApprovalConfig | null): {
|
|
17
|
+
auth: {
|
|
18
|
+
authorizeActorAction?: ChannelApprovalCapability["authorizeActorAction"];
|
|
19
|
+
getActionAvailabilityState?: ChannelApprovalCapability["getActionAvailabilityState"];
|
|
20
|
+
getExecInitiatingSurfaceState?: ChannelApprovalCapability["getExecInitiatingSurfaceState"];
|
|
21
|
+
resolveApproveCommandBehavior?: ChannelApprovalCapability["resolveApproveCommandBehavior"];
|
|
22
|
+
};
|
|
23
|
+
delivery: ChannelApprovalCapability["delivery"];
|
|
24
|
+
nativeRuntime: ChannelApprovalCapability["nativeRuntime"];
|
|
25
|
+
render: ChannelApprovalCapability["render"];
|
|
26
|
+
native: ChannelApprovalCapability["native"];
|
|
27
|
+
describeExecApprovalSetup: ChannelApprovalCapability["describeExecApprovalSetup"];
|
|
28
|
+
};
|
|
29
|
+
export declare function getMeetApprovalCapability(): ChannelApprovalCapability;
|
|
30
|
+
export {};
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import { createChannelApprovalNativeRuntimeAdapter, } from "openclaw/plugin-sdk/approval-handler-runtime";
|
|
2
|
+
import { buildChannelApprovalNativeTargetKey, resolveApprovalRequestSessionConversation, } from "openclaw/plugin-sdk/approval-native-runtime";
|
|
3
|
+
import { buildExecApprovalPendingReplyPayload, } from "openclaw/plugin-sdk/approval-runtime";
|
|
4
|
+
import { normalizeLowercaseStringOrEmpty, normalizeOptionalString, } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
5
|
+
import { listMeetAccountIds, resolveMeetAccount } from "./accounts.js";
|
|
6
|
+
import { createChannelApproverDmTargetResolver, createChannelNativeOriginTargetResolver, createApproverRestrictedNativeApprovalCapability, splitChannelApprovalCapability, } from "openclaw/plugin-sdk/approval-runtime";
|
|
7
|
+
import { getMeetExecApprovalApprovers, isMeetExecApprovalApprover, isMeetExecApprovalClientEnabled, } from "./exec-approvals.js";
|
|
8
|
+
import { sendMessageMeet } from "./send.js";
|
|
9
|
+
function shouldHandleMeetApprovalRequest(_params) {
|
|
10
|
+
return true;
|
|
11
|
+
}
|
|
12
|
+
function extractMeetSessionKind(sessionKey) {
|
|
13
|
+
if (!sessionKey) {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
const match = sessionKey.match(/meet:(channel|group|dm):/);
|
|
17
|
+
if (!match) {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
return match[1];
|
|
21
|
+
}
|
|
22
|
+
function normalizeMeetOriginChannelId(value) {
|
|
23
|
+
if (!value) {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
const trimmed = value.trim();
|
|
27
|
+
if (!trimmed) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
const prefixed = trimmed.match(/^(?:channel):(-?\d+)$/i);
|
|
31
|
+
if (prefixed) {
|
|
32
|
+
return prefixed[1];
|
|
33
|
+
}
|
|
34
|
+
return /^-?\d+$/.test(trimmed) ? trimmed : null;
|
|
35
|
+
}
|
|
36
|
+
function normalizeMeetThreadId(value) {
|
|
37
|
+
if (typeof value === "number") {
|
|
38
|
+
return Number.isFinite(value) ? String(value) : undefined;
|
|
39
|
+
}
|
|
40
|
+
if (typeof value !== "string") {
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
const normalized = value.trim();
|
|
44
|
+
return /^-?\d+$/.test(normalized) ? normalized : undefined;
|
|
45
|
+
}
|
|
46
|
+
function createMeetOriginTargetResolver(_configOverride) {
|
|
47
|
+
return createChannelNativeOriginTargetResolver({
|
|
48
|
+
channel: "meet",
|
|
49
|
+
shouldHandleRequest: ({ cfg, accountId, request }) => shouldHandleMeetApprovalRequest({
|
|
50
|
+
cfg,
|
|
51
|
+
accountId,
|
|
52
|
+
request,
|
|
53
|
+
}),
|
|
54
|
+
resolveTurnSourceTarget: (request) => {
|
|
55
|
+
const sessionConversation = resolveApprovalRequestSessionConversation({
|
|
56
|
+
request,
|
|
57
|
+
channel: "meet",
|
|
58
|
+
bundledFallback: false,
|
|
59
|
+
});
|
|
60
|
+
const sessionKind = extractMeetSessionKind(normalizeOptionalString(request.request.sessionKey) ?? null);
|
|
61
|
+
const turnSourceChannel = normalizeLowercaseStringOrEmpty(request.request.turnSourceChannel);
|
|
62
|
+
const rawTurnSourceTo = normalizeOptionalString(request.request.turnSourceTo) ?? "";
|
|
63
|
+
const turnSourceTo = normalizeMeetOriginChannelId(rawTurnSourceTo);
|
|
64
|
+
const threadId = normalizeMeetThreadId(request.request.turnSourceThreadId) ??
|
|
65
|
+
normalizeMeetThreadId(sessionConversation?.threadId) ??
|
|
66
|
+
undefined;
|
|
67
|
+
const hasExplicitOriginTarget = /^(?:channel):/i.test(rawTurnSourceTo);
|
|
68
|
+
if (turnSourceChannel !== "meet" || !turnSourceTo || sessionKind === "dm") {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
return hasExplicitOriginTarget || sessionKind === "channel" || sessionKind === "group"
|
|
72
|
+
? { to: turnSourceTo, threadId }
|
|
73
|
+
: null;
|
|
74
|
+
},
|
|
75
|
+
resolveSessionTarget: (sessionTarget, request) => {
|
|
76
|
+
const sessionConversation = resolveApprovalRequestSessionConversation({
|
|
77
|
+
request,
|
|
78
|
+
channel: "meet",
|
|
79
|
+
bundledFallback: false,
|
|
80
|
+
});
|
|
81
|
+
const sessionKind = extractMeetSessionKind(request.request.sessionKey?.trim() || null);
|
|
82
|
+
if (sessionKind === "dm") {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
const targetTo = normalizeMeetOriginChannelId(sessionTarget.to);
|
|
86
|
+
return targetTo
|
|
87
|
+
? {
|
|
88
|
+
to: targetTo,
|
|
89
|
+
threadId: normalizeMeetThreadId(sessionTarget.threadId) ??
|
|
90
|
+
normalizeMeetThreadId(sessionConversation?.threadId) ??
|
|
91
|
+
undefined,
|
|
92
|
+
}
|
|
93
|
+
: null;
|
|
94
|
+
},
|
|
95
|
+
resolveFallbackTarget: (request) => {
|
|
96
|
+
const sessionConversation = resolveApprovalRequestSessionConversation({
|
|
97
|
+
request,
|
|
98
|
+
channel: "meet",
|
|
99
|
+
bundledFallback: false,
|
|
100
|
+
});
|
|
101
|
+
const sessionKind = extractMeetSessionKind(request.request.sessionKey?.trim() || null);
|
|
102
|
+
if (sessionKind === "dm") {
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
const fallbackChannelId = normalizeMeetOriginChannelId(sessionConversation?.id);
|
|
106
|
+
return fallbackChannelId
|
|
107
|
+
? {
|
|
108
|
+
to: fallbackChannelId,
|
|
109
|
+
threadId: normalizeMeetThreadId(sessionConversation?.threadId) ?? undefined,
|
|
110
|
+
}
|
|
111
|
+
: null;
|
|
112
|
+
},
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
function createMeetApproverDmTargetResolver(configOverride) {
|
|
116
|
+
return createChannelApproverDmTargetResolver({
|
|
117
|
+
shouldHandleRequest: ({ cfg, accountId, request }) => shouldHandleMeetApprovalRequest({
|
|
118
|
+
cfg,
|
|
119
|
+
accountId,
|
|
120
|
+
request,
|
|
121
|
+
}),
|
|
122
|
+
resolveApprovers: ({ cfg, accountId }) => getMeetExecApprovalApprovers({ cfg, accountId, configOverride }),
|
|
123
|
+
mapApprover: (approver) => ({ to: `user:${approver}` }),
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
function buildMeetPendingPayload(params) {
|
|
127
|
+
if (params.view.approvalKind !== "exec") {
|
|
128
|
+
return {
|
|
129
|
+
text: params.view.title,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
const payload = buildExecApprovalPendingReplyPayload({
|
|
133
|
+
approvalId: params.request.id,
|
|
134
|
+
approvalSlug: params.request.id.slice(0, 8),
|
|
135
|
+
approvalCommandId: params.request.id,
|
|
136
|
+
warningText: params.view.warningText ?? normalizeOptionalString(params.request.request.warningText) ?? undefined,
|
|
137
|
+
ask: params.view.ask ?? normalizeOptionalString(params.request.request.ask) ?? undefined,
|
|
138
|
+
agentId: params.view.agentId ?? normalizeOptionalString(params.request.request.agentId) ?? undefined,
|
|
139
|
+
allowedDecisions: params.view.actions.map((action) => action.decision),
|
|
140
|
+
command: params.view.commandText,
|
|
141
|
+
cwd: params.view.cwd ?? normalizeOptionalString(params.request.request.cwd) ?? undefined,
|
|
142
|
+
host: params.view.host === "node" ? "node" : "gateway",
|
|
143
|
+
nodeId: params.view.nodeId ?? normalizeOptionalString(params.request.request.nodeId) ?? undefined,
|
|
144
|
+
sessionKey: params.view.sessionKey ?? normalizeOptionalString(params.request.request.sessionKey) ?? undefined,
|
|
145
|
+
expiresAtMs: params.request.expiresAtMs,
|
|
146
|
+
nowMs: params.nowMs,
|
|
147
|
+
});
|
|
148
|
+
const reason = params.view.ask?.trim();
|
|
149
|
+
const text = reason ? `${reason}\n\n${payload.text ?? ""}` : (payload.text ?? "");
|
|
150
|
+
return {
|
|
151
|
+
text,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
export const meetApprovalNativeRuntime = createChannelApprovalNativeRuntimeAdapter({
|
|
155
|
+
eventKinds: ["exec", "plugin"],
|
|
156
|
+
availability: {
|
|
157
|
+
isConfigured: ({ cfg, accountId }) => isMeetExecApprovalClientEnabled({ cfg, accountId }),
|
|
158
|
+
shouldHandle: ({ cfg, accountId, request }) => shouldHandleMeetApprovalRequest({
|
|
159
|
+
cfg,
|
|
160
|
+
accountId,
|
|
161
|
+
request,
|
|
162
|
+
}),
|
|
163
|
+
},
|
|
164
|
+
presentation: {
|
|
165
|
+
buildPendingPayload: ({ request, nowMs, view }) => buildMeetPendingPayload({
|
|
166
|
+
request: request,
|
|
167
|
+
nowMs,
|
|
168
|
+
view,
|
|
169
|
+
}),
|
|
170
|
+
buildResolvedResult: () => ({ kind: "leave" }),
|
|
171
|
+
buildExpiredResult: () => ({ kind: "leave" }),
|
|
172
|
+
},
|
|
173
|
+
transport: {
|
|
174
|
+
prepareTarget: ({ plannedTarget }) => ({
|
|
175
|
+
dedupeKey: buildChannelApprovalNativeTargetKey(plannedTarget.target),
|
|
176
|
+
target: {
|
|
177
|
+
to: plannedTarget.surface === "approver-dm" && !/^user:/i.test(plannedTarget.target.to)
|
|
178
|
+
? `user:${plannedTarget.target.to}`
|
|
179
|
+
: plannedTarget.target.to,
|
|
180
|
+
...(plannedTarget.target.threadId != null
|
|
181
|
+
? { threadId: String(plannedTarget.target.threadId) }
|
|
182
|
+
: {}),
|
|
183
|
+
},
|
|
184
|
+
}),
|
|
185
|
+
deliverPending: async ({ cfg, accountId, preparedTarget, pendingPayload }) => {
|
|
186
|
+
try {
|
|
187
|
+
const result = await sendMessageMeet({
|
|
188
|
+
cfg: cfg,
|
|
189
|
+
to: preparedTarget.to,
|
|
190
|
+
text: pendingPayload.text,
|
|
191
|
+
accountId: accountId ?? undefined,
|
|
192
|
+
threadId: preparedTarget.threadId,
|
|
193
|
+
});
|
|
194
|
+
return {
|
|
195
|
+
chatId: result.chatId,
|
|
196
|
+
messageId: result.messageId,
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
catch {
|
|
200
|
+
return null;
|
|
201
|
+
}
|
|
202
|
+
},
|
|
203
|
+
},
|
|
204
|
+
});
|
|
205
|
+
function createMeetApprovalCapability(configOverride) {
|
|
206
|
+
return createApproverRestrictedNativeApprovalCapability({
|
|
207
|
+
channel: "meet",
|
|
208
|
+
channelLabel: "Meet",
|
|
209
|
+
describeExecApprovalSetup: ({ accountId, }) => {
|
|
210
|
+
const prefix = accountId && accountId !== "default"
|
|
211
|
+
? `channels.meet.accounts.${accountId}`
|
|
212
|
+
: "channels.meet";
|
|
213
|
+
return `Approve it from the Web UI or terminal UI for now. Meet supports native exec approvals for this account. Configure \`${prefix}.execApprovals.approvers\` or \`commands.ownerAllowFrom\`; set \`${prefix}.execApprovals.enabled\` to \`auto\` or \`true\`.`;
|
|
214
|
+
},
|
|
215
|
+
listAccountIds: listMeetAccountIds,
|
|
216
|
+
hasApprovers: ({ cfg, accountId }) => getMeetExecApprovalApprovers({ cfg, accountId, configOverride }).length > 0,
|
|
217
|
+
isExecAuthorizedSender: ({ cfg, accountId, senderId }) => isMeetExecApprovalApprover({ cfg, accountId, senderId, configOverride }),
|
|
218
|
+
isNativeDeliveryEnabled: ({ cfg, accountId }) => isMeetExecApprovalClientEnabled({ cfg, accountId, configOverride }),
|
|
219
|
+
resolveNativeDeliveryMode: ({ cfg, accountId }) => configOverride?.target ??
|
|
220
|
+
resolveMeetAccount({ cfg, accountId }).config.execApprovals?.target ??
|
|
221
|
+
"dm",
|
|
222
|
+
resolveOriginTarget: createMeetOriginTargetResolver(configOverride),
|
|
223
|
+
resolveApproverDmTargets: createMeetApproverDmTargetResolver(configOverride),
|
|
224
|
+
notifyOriginWhenDmOnly: true,
|
|
225
|
+
nativeRuntime: meetApprovalNativeRuntime,
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
export function createMeetNativeApprovalAdapter(configOverride) {
|
|
229
|
+
return splitChannelApprovalCapability(createMeetApprovalCapability(configOverride));
|
|
230
|
+
}
|
|
231
|
+
let cachedMeetApprovalCapability;
|
|
232
|
+
export function getMeetApprovalCapability() {
|
|
233
|
+
cachedMeetApprovalCapability ??= createMeetApprovalCapability();
|
|
234
|
+
return cachedMeetApprovalCapability;
|
|
235
|
+
}
|
package/dist/src/channel.js
CHANGED
|
@@ -7,6 +7,7 @@ import { sendMessageMeet } from "./send.js";
|
|
|
7
7
|
import { getMeetClient } from "./client.js";
|
|
8
8
|
import { getAllCachedUsers, rememberMeetUser } from "./directory-cache.js";
|
|
9
9
|
import { MeetPluginConfigSchema } from "./config-schema.js";
|
|
10
|
+
import { getMeetApprovalCapability } from "./approval-native.js";
|
|
10
11
|
const meta = {
|
|
11
12
|
id: "meet",
|
|
12
13
|
label: "Meet",
|
|
@@ -298,6 +299,7 @@ export const meetPlugin = {
|
|
|
298
299
|
listGroupsLive: async () => [],
|
|
299
300
|
},
|
|
300
301
|
outbound: meetOutbound,
|
|
302
|
+
approvalCapability: getMeetApprovalCapability(),
|
|
301
303
|
status: {
|
|
302
304
|
defaultRuntime: {
|
|
303
305
|
accountId: DEFAULT_ACCOUNT_ID,
|
|
@@ -16,6 +16,17 @@ export declare const MeetGroupConfigSchema: z.ZodObject<{
|
|
|
16
16
|
disabled: "disabled";
|
|
17
17
|
}>>;
|
|
18
18
|
}, z.core.$strip>;
|
|
19
|
+
export declare const MeetExecApprovalConfigSchema: z.ZodObject<{
|
|
20
|
+
enabled: z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodLiteral<"auto">]>>;
|
|
21
|
+
approvers: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>>;
|
|
22
|
+
target: z.ZodOptional<z.ZodEnum<{
|
|
23
|
+
dm: "dm";
|
|
24
|
+
channel: "channel";
|
|
25
|
+
both: "both";
|
|
26
|
+
}>>;
|
|
27
|
+
agentFilter: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
28
|
+
sessionFilter: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
29
|
+
}, z.core.$strip>;
|
|
19
30
|
export declare const MeetAccountConfigSchema: z.ZodObject<{
|
|
20
31
|
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
21
32
|
name: z.ZodOptional<z.ZodString>;
|
|
@@ -63,6 +74,17 @@ export declare const MeetAccountConfigSchema: z.ZodObject<{
|
|
|
63
74
|
disabled: "disabled";
|
|
64
75
|
}>>;
|
|
65
76
|
}, z.core.$strip>>>;
|
|
77
|
+
execApprovals: z.ZodOptional<z.ZodObject<{
|
|
78
|
+
enabled: z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodLiteral<"auto">]>>;
|
|
79
|
+
approvers: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>>;
|
|
80
|
+
target: z.ZodOptional<z.ZodEnum<{
|
|
81
|
+
dm: "dm";
|
|
82
|
+
channel: "channel";
|
|
83
|
+
both: "both";
|
|
84
|
+
}>>;
|
|
85
|
+
agentFilter: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
86
|
+
sessionFilter: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
87
|
+
}, z.core.$strip>>;
|
|
66
88
|
}, z.core.$strip>;
|
|
67
89
|
export declare const MeetConfigSchema: z.ZodObject<{
|
|
68
90
|
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -163,6 +185,28 @@ export declare const MeetConfigSchema: z.ZodObject<{
|
|
|
163
185
|
disabled: "disabled";
|
|
164
186
|
}>>;
|
|
165
187
|
}, z.core.$strip>>>;
|
|
188
|
+
execApprovals: z.ZodOptional<z.ZodObject<{
|
|
189
|
+
enabled: z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodLiteral<"auto">]>>;
|
|
190
|
+
approvers: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>>;
|
|
191
|
+
target: z.ZodOptional<z.ZodEnum<{
|
|
192
|
+
dm: "dm";
|
|
193
|
+
channel: "channel";
|
|
194
|
+
both: "both";
|
|
195
|
+
}>>;
|
|
196
|
+
agentFilter: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
197
|
+
sessionFilter: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
198
|
+
}, z.core.$strip>>;
|
|
166
199
|
}, z.core.$strip>>>;
|
|
200
|
+
execApprovals: z.ZodOptional<z.ZodObject<{
|
|
201
|
+
enabled: z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodLiteral<"auto">]>>;
|
|
202
|
+
approvers: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>>;
|
|
203
|
+
target: z.ZodOptional<z.ZodEnum<{
|
|
204
|
+
dm: "dm";
|
|
205
|
+
channel: "channel";
|
|
206
|
+
both: "both";
|
|
207
|
+
}>>;
|
|
208
|
+
agentFilter: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
209
|
+
sessionFilter: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
210
|
+
}, z.core.$strip>>;
|
|
167
211
|
}, z.core.$strip>;
|
|
168
212
|
export declare const MeetPluginConfigSchema: import("openclaw/plugin-sdk").ChannelConfigSchema;
|
|
@@ -13,6 +13,13 @@ export const MeetGroupConfigSchema = z.object({
|
|
|
13
13
|
users: z.array(z.union([z.string(), z.number()])).optional(),
|
|
14
14
|
groupPolicy: z.enum(["open", "allowlist", "disabled"]).optional(),
|
|
15
15
|
});
|
|
16
|
+
export const MeetExecApprovalConfigSchema = z.object({
|
|
17
|
+
enabled: z.union([z.boolean(), z.literal("auto")]).optional(),
|
|
18
|
+
approvers: z.array(z.union([z.string(), z.number()])).optional(),
|
|
19
|
+
target: z.enum(["dm", "channel", "both"]).optional(),
|
|
20
|
+
agentFilter: z.array(z.string()).optional(),
|
|
21
|
+
sessionFilter: z.array(z.string()).optional(),
|
|
22
|
+
});
|
|
16
23
|
export const MeetAccountConfigSchema = z.object({
|
|
17
24
|
enabled: z.boolean().optional(),
|
|
18
25
|
name: z.string().optional(),
|
|
@@ -34,6 +41,7 @@ export const MeetAccountConfigSchema = z.object({
|
|
|
34
41
|
mediaMaxMb: z.number().min(0).optional(),
|
|
35
42
|
typingMode: z.enum(["none", "instant", "message"]).optional(),
|
|
36
43
|
groups: z.record(z.string(), MeetGroupConfigSchema).optional(),
|
|
44
|
+
execApprovals: MeetExecApprovalConfigSchema.optional(),
|
|
37
45
|
});
|
|
38
46
|
export const MeetConfigSchema = z.object({
|
|
39
47
|
enabled: z.boolean().optional(),
|
|
@@ -58,5 +66,6 @@ export const MeetConfigSchema = z.object({
|
|
|
58
66
|
mediaMaxMb: z.number().min(0).optional(),
|
|
59
67
|
typingMode: z.enum(["none", "instant", "message"]).optional(),
|
|
60
68
|
accounts: z.record(z.string(), MeetAccountConfigSchema).optional(),
|
|
69
|
+
execApprovals: MeetExecApprovalConfigSchema.optional(),
|
|
61
70
|
});
|
|
62
71
|
export const MeetPluginConfigSchema = buildChannelConfigSchema(MeetConfigSchema);
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { ChannelOutboundPayloadHint } from "openclaw/plugin-sdk/channel-contract";
|
|
2
|
+
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-contracts";
|
|
3
|
+
import type { ReplyPayload } from "openclaw/plugin-sdk/reply-dispatch-runtime";
|
|
4
|
+
import type { MeetExecApprovalConfig } from "./types.js";
|
|
5
|
+
export declare function getMeetExecApprovalApprovers(params: {
|
|
6
|
+
cfg: OpenClawConfig;
|
|
7
|
+
accountId?: string | null;
|
|
8
|
+
configOverride?: MeetExecApprovalConfig | null;
|
|
9
|
+
}): string[];
|
|
10
|
+
export declare function isMeetExecApprovalClientEnabled(params: {
|
|
11
|
+
cfg: OpenClawConfig;
|
|
12
|
+
accountId?: string | null;
|
|
13
|
+
configOverride?: MeetExecApprovalConfig | null;
|
|
14
|
+
}): boolean;
|
|
15
|
+
export declare function isMeetExecApprovalApprover(params: {
|
|
16
|
+
cfg: OpenClawConfig;
|
|
17
|
+
accountId?: string | null;
|
|
18
|
+
senderId?: string | null;
|
|
19
|
+
configOverride?: MeetExecApprovalConfig | null;
|
|
20
|
+
}): boolean;
|
|
21
|
+
export declare function shouldSuppressLocalMeetExecApprovalPrompt(params: {
|
|
22
|
+
cfg: OpenClawConfig;
|
|
23
|
+
accountId?: string | null;
|
|
24
|
+
payload: ReplyPayload;
|
|
25
|
+
hint?: ChannelOutboundPayloadHint;
|
|
26
|
+
}): boolean;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { resolveMeetAccount } from "./accounts.js";
|
|
2
|
+
import { getExecApprovalReplyMetadata, isChannelExecApprovalClientEnabledFromConfig, matchesApprovalRequestFilters, resolveApprovalApprovers, } from "openclaw/plugin-sdk/approval-runtime";
|
|
3
|
+
function normalizeMeetApproverId(value) {
|
|
4
|
+
const trimmed = value.trim();
|
|
5
|
+
if (!trimmed) {
|
|
6
|
+
return undefined;
|
|
7
|
+
}
|
|
8
|
+
// Meet 用户ID是数字
|
|
9
|
+
if (/^-?\d+$/.test(trimmed)) {
|
|
10
|
+
return trimmed;
|
|
11
|
+
}
|
|
12
|
+
// 支持 user:ID 格式
|
|
13
|
+
const match = trimmed.match(/^user:(-?\d+)$/i);
|
|
14
|
+
return match ? match[1] : undefined;
|
|
15
|
+
}
|
|
16
|
+
function resolveMeetOwnerApprovers(cfg) {
|
|
17
|
+
const ownerAllowFrom = cfg.commands?.ownerAllowFrom;
|
|
18
|
+
if (!Array.isArray(ownerAllowFrom) || ownerAllowFrom.length === 0) {
|
|
19
|
+
return [];
|
|
20
|
+
}
|
|
21
|
+
return resolveApprovalApprovers({
|
|
22
|
+
explicit: ownerAllowFrom,
|
|
23
|
+
normalizeApprover: (value) => normalizeMeetApproverId(String(value)),
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
export function getMeetExecApprovalApprovers(params) {
|
|
27
|
+
return resolveApprovalApprovers({
|
|
28
|
+
explicit: params.configOverride?.approvers ??
|
|
29
|
+
resolveMeetAccount(params).config.execApprovals?.approvers ??
|
|
30
|
+
resolveMeetOwnerApprovers(params.cfg),
|
|
31
|
+
normalizeApprover: (value) => normalizeMeetApproverId(String(value)),
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
export function isMeetExecApprovalClientEnabled(params) {
|
|
35
|
+
const config = params.configOverride ?? resolveMeetAccount(params).config.execApprovals;
|
|
36
|
+
return isChannelExecApprovalClientEnabledFromConfig({
|
|
37
|
+
enabled: config?.enabled,
|
|
38
|
+
approverCount: getMeetExecApprovalApprovers({
|
|
39
|
+
cfg: params.cfg,
|
|
40
|
+
accountId: params.accountId,
|
|
41
|
+
configOverride: params.configOverride,
|
|
42
|
+
}).length,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
export function isMeetExecApprovalApprover(params) {
|
|
46
|
+
const senderId = params.senderId?.trim();
|
|
47
|
+
if (!senderId) {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
return getMeetExecApprovalApprovers({
|
|
51
|
+
cfg: params.cfg,
|
|
52
|
+
accountId: params.accountId,
|
|
53
|
+
configOverride: params.configOverride,
|
|
54
|
+
}).includes(senderId);
|
|
55
|
+
}
|
|
56
|
+
export function shouldSuppressLocalMeetExecApprovalPrompt(params) {
|
|
57
|
+
const metadata = getExecApprovalReplyMetadata(params.payload);
|
|
58
|
+
const config = resolveMeetAccount(params).config.execApprovals;
|
|
59
|
+
return (params.hint?.kind === "approval-pending" &&
|
|
60
|
+
params.hint.nativeRouteActive === true &&
|
|
61
|
+
isMeetExecApprovalClientEnabled(params) &&
|
|
62
|
+
metadata !== null &&
|
|
63
|
+
matchesApprovalRequestFilters({
|
|
64
|
+
request: {
|
|
65
|
+
agentId: metadata.agentId,
|
|
66
|
+
sessionKey: metadata.sessionKey,
|
|
67
|
+
},
|
|
68
|
+
agentFilter: config?.agentFilter,
|
|
69
|
+
sessionFilter: config?.sessionFilter,
|
|
70
|
+
}));
|
|
71
|
+
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const MEET_PLUGIN_VERSION = "3.
|
|
1
|
+
export declare const MEET_PLUGIN_VERSION = "3.5.0";
|
|
2
2
|
export declare const MEET_OPENCLAW_VERSION = "2026.5.18";
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const MEET_PLUGIN_VERSION = "3.
|
|
1
|
+
export const MEET_PLUGIN_VERSION = "3.5.0";
|
|
2
2
|
export const MEET_OPENCLAW_VERSION = "2026.5.18";
|
package/dist/src/outbound.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { getMeetRuntime } from "./runtime.js";
|
|
2
2
|
import { sendMessageMeet, sendMediaMeet } from "./send.js";
|
|
3
|
+
import { shouldSuppressLocalMeetExecApprovalPrompt } from "./exec-approvals.js";
|
|
3
4
|
export const meetOutbound = {
|
|
4
5
|
deliveryMode: "direct",
|
|
5
6
|
chunker: (text, limit) => {
|
|
@@ -31,4 +32,12 @@ export const meetOutbound = {
|
|
|
31
32
|
});
|
|
32
33
|
return { channel: "meet", messageId: result.messageId, chatId: result.chatId };
|
|
33
34
|
},
|
|
35
|
+
shouldSuppressLocalPayloadPrompt: (params) => {
|
|
36
|
+
return shouldSuppressLocalMeetExecApprovalPrompt({
|
|
37
|
+
cfg: params.cfg,
|
|
38
|
+
accountId: params.accountId,
|
|
39
|
+
payload: params.payload,
|
|
40
|
+
hint: params.hint,
|
|
41
|
+
});
|
|
42
|
+
},
|
|
34
43
|
};
|
package/dist/src/send.d.ts
CHANGED
package/dist/src/send.js
CHANGED
|
@@ -123,7 +123,7 @@ export function mergeAtIds(explicitAtIds, extractedAtIds) {
|
|
|
123
123
|
return [...new Set([...(explicitAtIds ?? []), ...(extractedAtIds ?? [])])];
|
|
124
124
|
}
|
|
125
125
|
export async function sendMessageMeet(opts) {
|
|
126
|
-
const { cfg, to, text, accountId, atIds: explicitAtIds, runtime } = opts;
|
|
126
|
+
const { cfg, to, text, accountId, threadId, atIds: explicitAtIds, runtime } = opts;
|
|
127
127
|
const log = runtime?.log ?? console.log;
|
|
128
128
|
const logError = runtime?.error ?? console.error;
|
|
129
129
|
const account = resolveMeetAccount({ cfg, accountId });
|
|
@@ -170,8 +170,14 @@ export async function sendMessageMeet(opts) {
|
|
|
170
170
|
const finalAtIds = mergeAtIds(explicitAtIds, extractedAtIds);
|
|
171
171
|
log(`send message to=${to} atIds=${finalAtIds.join(",") || "none"}`);
|
|
172
172
|
const sessionInfo = parseTargetToSessionInfo(to, Number(botUserId));
|
|
173
|
+
const finalSessionInfo = threadId && sessionInfo.sessionType === 3
|
|
174
|
+
? {
|
|
175
|
+
...sessionInfo,
|
|
176
|
+
threadId: Number(threadId),
|
|
177
|
+
}
|
|
178
|
+
: sessionInfo;
|
|
173
179
|
try {
|
|
174
|
-
const result = await bot.sendMessage(
|
|
180
|
+
const result = await bot.sendMessage(finalSessionInfo, {
|
|
175
181
|
content: cleanText,
|
|
176
182
|
atIds: finalAtIds,
|
|
177
183
|
});
|
package/dist/src/types.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import type { SessionInfo, AttachmentInfo, UploadProgress } from "@meet-im/meet-bot-jssdk";
|
|
2
2
|
import type { z } from "zod";
|
|
3
|
-
import { MeetConfigSchema, MeetAccountConfigSchema, MeetChannelConfigSchema, MeetGroupConfigSchema } from "./config-schema.js";
|
|
3
|
+
import { MeetConfigSchema, MeetAccountConfigSchema, MeetChannelConfigSchema, MeetGroupConfigSchema, MeetExecApprovalConfigSchema } from "./config-schema.js";
|
|
4
4
|
export type MeetConfig = z.infer<typeof MeetConfigSchema>;
|
|
5
5
|
export type MeetAccountConfig = z.infer<typeof MeetAccountConfigSchema>;
|
|
6
6
|
export type MeetChannelConfig = z.infer<typeof MeetChannelConfigSchema>;
|
|
7
7
|
export type MeetGroupConfig = z.infer<typeof MeetGroupConfigSchema>;
|
|
8
|
+
export type MeetExecApprovalConfig = z.infer<typeof MeetExecApprovalConfigSchema>;
|
|
8
9
|
export type { AttachmentInfo, UploadProgress };
|
|
9
10
|
export type ResolvedMeetAccount = {
|
|
10
11
|
accountId: string;
|
package/openclaw.plugin.json
CHANGED
|
@@ -28,6 +28,22 @@
|
|
|
28
28
|
"type": "array",
|
|
29
29
|
"items": { "anyOf": [{ "type": "string" }, { "type": "number" }] }
|
|
30
30
|
},
|
|
31
|
+
"execApprovals": {
|
|
32
|
+
"type": "object",
|
|
33
|
+
"additionalProperties": false,
|
|
34
|
+
"properties": {
|
|
35
|
+
"enabled": {
|
|
36
|
+
"anyOf": [{ "type": "boolean" }, { "type": "string", "const": "auto" }]
|
|
37
|
+
},
|
|
38
|
+
"approvers": {
|
|
39
|
+
"type": "array",
|
|
40
|
+
"items": { "anyOf": [{ "type": "string" }, { "type": "number" }] }
|
|
41
|
+
},
|
|
42
|
+
"target": { "type": "string", "enum": ["dm", "channel", "both"] },
|
|
43
|
+
"agentFilter": { "type": "array", "items": { "type": "string" } },
|
|
44
|
+
"sessionFilter": { "type": "array", "items": { "type": "string" } }
|
|
45
|
+
}
|
|
46
|
+
},
|
|
31
47
|
"requireMention": { "type": "boolean" },
|
|
32
48
|
"systemPrompt": { "type": "string" },
|
|
33
49
|
"channels": {
|
|
@@ -88,6 +104,22 @@
|
|
|
88
104
|
"type": "array",
|
|
89
105
|
"items": { "anyOf": [{ "type": "string" }, { "type": "number" }] }
|
|
90
106
|
},
|
|
107
|
+
"execApprovals": {
|
|
108
|
+
"type": "object",
|
|
109
|
+
"additionalProperties": false,
|
|
110
|
+
"properties": {
|
|
111
|
+
"enabled": {
|
|
112
|
+
"anyOf": [{ "type": "boolean" }, { "type": "string", "const": "auto" }]
|
|
113
|
+
},
|
|
114
|
+
"approvers": {
|
|
115
|
+
"type": "array",
|
|
116
|
+
"items": { "anyOf": [{ "type": "string" }, { "type": "number" }] }
|
|
117
|
+
},
|
|
118
|
+
"target": { "type": "string", "enum": ["dm", "channel", "both"] },
|
|
119
|
+
"agentFilter": { "type": "array", "items": { "type": "string" } },
|
|
120
|
+
"sessionFilter": { "type": "array", "items": { "type": "string" } }
|
|
121
|
+
}
|
|
122
|
+
},
|
|
91
123
|
"requireMention": { "type": "boolean" },
|
|
92
124
|
"systemPrompt": { "type": "string" },
|
|
93
125
|
"historyLimit": { "type": "number", "minimum": 0 },
|