@xmoxmo/bncr 0.4.0 → 0.4.2
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/index.js +619 -455
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/src/bootstrap/runtime-discovery.ts +4 -0
- package/src/bootstrap/runtime-loader.ts +23 -2
- package/src/messaging/outbound/build-send-action.ts +21 -5
- package/src/messaging/outbound/send-params.ts +23 -5
- package/src/plugin/channel-plugin-surface-group.ts +33 -31
package/openclaw.plugin.json
CHANGED
package/package.json
CHANGED
|
@@ -153,6 +153,10 @@ function ensurePluginNodeModulesLink(pluginDir: string, targetRoot: string) {
|
|
|
153
153
|
}
|
|
154
154
|
|
|
155
155
|
export function resolveBncrRuntimeSourceDir(pluginDir: string) {
|
|
156
|
+
const pluginRoot = resolveBncrPluginRoot(pluginDir);
|
|
157
|
+
const rootSource = path.join(pluginRoot, 'src');
|
|
158
|
+
if (fs.existsSync(path.join(rootSource, 'channel.ts'))) return rootSource;
|
|
159
|
+
|
|
156
160
|
const direct = path.join(pluginDir, 'src');
|
|
157
161
|
if (fs.existsSync(path.join(direct, 'channel.ts'))) return direct;
|
|
158
162
|
|
|
@@ -15,9 +15,30 @@ export type LoadedRuntime = {
|
|
|
15
15
|
createBncrChannelPlugin: ChannelModule['createBncrChannelPlugin'];
|
|
16
16
|
};
|
|
17
17
|
|
|
18
|
-
export
|
|
18
|
+
export function resolvePluginEntryFileFromModule(moduleUrl: string) {
|
|
19
|
+
const currentFile = fileURLToPath(moduleUrl);
|
|
20
|
+
const pluginRoot = resolveBncrPluginRoot(currentFile);
|
|
21
|
+
const currentDir = path.dirname(currentFile);
|
|
22
|
+
const distEntry = path.join(pluginRoot, 'dist', 'index.js');
|
|
23
|
+
if (currentFile === distEntry && fs.existsSync(distEntry)) return distEntry;
|
|
24
|
+
|
|
25
|
+
const sourceEntry = path.join(pluginRoot, 'index.ts');
|
|
26
|
+
if (fs.existsSync(sourceEntry)) return sourceEntry;
|
|
27
|
+
|
|
28
|
+
if (fs.existsSync(distEntry)) return distEntry;
|
|
29
|
+
|
|
30
|
+
if (path.basename(currentDir) === 'dist') return distEntry;
|
|
31
|
+
|
|
32
|
+
return sourceEntry;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function resolvePluginEntryFile() {
|
|
36
|
+
return resolvePluginEntryFileFromModule(import.meta.url);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export const pluginFile = resolvePluginEntryFile();
|
|
19
40
|
export const pluginDir = path.dirname(pluginFile);
|
|
20
|
-
export const pluginRequire = createRequire(
|
|
41
|
+
export const pluginRequire = createRequire(pluginFile);
|
|
21
42
|
export const pluginRoot = resolveBncrPluginRoot(pluginFile);
|
|
22
43
|
|
|
23
44
|
const runtimeSourceDir = resolveBncrRuntimeSourceDir(pluginDir);
|
|
@@ -12,6 +12,7 @@ type MinimalBncrSendInput = {
|
|
|
12
12
|
media?: string;
|
|
13
13
|
filePath?: string;
|
|
14
14
|
mediaUrl?: string;
|
|
15
|
+
mediaUrls?: string[];
|
|
15
16
|
asVoice?: boolean;
|
|
16
17
|
audioAsVoice?: boolean;
|
|
17
18
|
params?: Record<string, unknown>;
|
|
@@ -73,13 +74,19 @@ export function buildBncrMessageAction(input: MinimalBncrSendInput): BuiltBncrMe
|
|
|
73
74
|
input.filePath,
|
|
74
75
|
input.mediaUrl,
|
|
75
76
|
);
|
|
77
|
+
const rawMediaUrls = Array.isArray(paramsObj.mediaUrls)
|
|
78
|
+
? paramsObj.mediaUrls
|
|
79
|
+
: Array.isArray(input.mediaUrls)
|
|
80
|
+
? input.mediaUrls
|
|
81
|
+
: undefined;
|
|
82
|
+
const mediaUrls = rawMediaUrls?.map((value) => asString(value || '').trim()).filter(Boolean);
|
|
76
83
|
|
|
77
84
|
const message = pickFirstString(paramsObj.message, input.message) ?? '';
|
|
78
85
|
const explicitCaption = pickFirstString(paramsObj.caption, input.caption) ?? '';
|
|
79
86
|
const asVoice = pickFirstBoolean(paramsObj.asVoice, input.asVoice);
|
|
80
87
|
const audioAsVoice = pickFirstBoolean(paramsObj.audioAsVoice, input.audioAsVoice);
|
|
81
88
|
|
|
82
|
-
if ((asVoice === true || audioAsVoice === true) && !mediaPath) {
|
|
89
|
+
if ((asVoice === true || audioAsVoice === true) && !mediaPath && !mediaUrls?.length) {
|
|
83
90
|
throw new Error('bncr voice send requires media path');
|
|
84
91
|
}
|
|
85
92
|
|
|
@@ -93,11 +100,20 @@ export function buildBncrMessageAction(input: MinimalBncrSendInput): BuiltBncrMe
|
|
|
93
100
|
const finalCaption = explicitCaption || message;
|
|
94
101
|
if (finalCaption) normalizedParams.caption = finalCaption;
|
|
95
102
|
delete normalizedParams.message;
|
|
103
|
+
if (mediaUrls?.length) normalizedParams.mediaUrls = mediaUrls;
|
|
96
104
|
} else {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
105
|
+
if (mediaUrls?.length) {
|
|
106
|
+
normalizedParams.mediaUrls = mediaUrls;
|
|
107
|
+
const finalCaption = explicitCaption || message;
|
|
108
|
+
if (finalCaption) normalizedParams.caption = finalCaption;
|
|
109
|
+
delete normalizedParams.message;
|
|
110
|
+
delete normalizedParams.path;
|
|
111
|
+
} else {
|
|
112
|
+
const finalMessage = message || explicitCaption;
|
|
113
|
+
if (!finalMessage.trim()) throw new Error('bncr send requires message or media');
|
|
114
|
+
normalizedParams.message = finalMessage;
|
|
115
|
+
delete normalizedParams.caption;
|
|
116
|
+
}
|
|
101
117
|
}
|
|
102
118
|
|
|
103
119
|
if (asVoice === true) normalizedParams.asVoice = true;
|
|
@@ -7,6 +7,7 @@ export type NormalizedBncrSendParams = {
|
|
|
7
7
|
message: string;
|
|
8
8
|
caption: string;
|
|
9
9
|
mediaUrl?: string;
|
|
10
|
+
mediaUrls?: string[];
|
|
10
11
|
asVoice: boolean;
|
|
11
12
|
audioAsVoice: boolean;
|
|
12
13
|
type?: string;
|
|
@@ -33,16 +34,32 @@ export function normalizeBncrSendParams(input: {
|
|
|
33
34
|
readOpenClawStringParam(paramsObj, 'path', { trim: false }) ??
|
|
34
35
|
readOpenClawStringParam(paramsObj, 'filePath', { trim: false }) ??
|
|
35
36
|
readOpenClawStringParam(paramsObj, 'mediaUrl', { trim: false });
|
|
37
|
+
const rawMediaUrls = paramsObj.mediaUrls;
|
|
38
|
+
const mediaUrls = Array.isArray(rawMediaUrls)
|
|
39
|
+
? Array.from(
|
|
40
|
+
new Set(rawMediaUrls.map((v) => (typeof v === 'string' ? v.trim() : '')).filter(Boolean)),
|
|
41
|
+
)
|
|
42
|
+
: undefined;
|
|
43
|
+
// 如果 mediaUrl 已经在 mediaUrls 中,去重避免重复发送
|
|
44
|
+
const dedupedMediaUrls = mediaUrls?.length
|
|
45
|
+
? mediaUrl && mediaUrls.includes(mediaUrl)
|
|
46
|
+
? mediaUrls
|
|
47
|
+
: mediaUrl
|
|
48
|
+
? [mediaUrl, ...mediaUrls]
|
|
49
|
+
: mediaUrls
|
|
50
|
+
: undefined;
|
|
36
51
|
const asVoice = readOpenClawBooleanParam(paramsObj, 'asVoice') ?? false;
|
|
37
52
|
const audioAsVoice = readOpenClawBooleanParam(paramsObj, 'audioAsVoice') ?? false;
|
|
38
53
|
const type = readOpenClawStringParam(paramsObj, 'type') || undefined;
|
|
39
54
|
|
|
40
|
-
|
|
55
|
+
const hasMedia = Boolean(mediaUrl || dedupedMediaUrls?.length);
|
|
41
56
|
|
|
42
|
-
|
|
43
|
-
const normalizedCaption = mediaUrl ? caption || message || '' : '';
|
|
57
|
+
if (asVoice && !hasMedia) throw new Error('send voice requires media path');
|
|
44
58
|
|
|
45
|
-
|
|
59
|
+
const normalizedMessage = hasMedia ? '' : message || caption || '';
|
|
60
|
+
const normalizedCaption = hasMedia ? caption || message || '' : '';
|
|
61
|
+
|
|
62
|
+
if (!normalizedMessage.trim() && !normalizedCaption.trim() && !hasMedia) {
|
|
46
63
|
throw new Error('send requires message or media');
|
|
47
64
|
}
|
|
48
65
|
|
|
@@ -51,7 +68,8 @@ export function normalizeBncrSendParams(input: {
|
|
|
51
68
|
accountId: resolvedAccountId,
|
|
52
69
|
message: normalizedMessage,
|
|
53
70
|
caption: normalizedCaption,
|
|
54
|
-
mediaUrl: mediaUrl || undefined,
|
|
71
|
+
mediaUrl: dedupedMediaUrls?.length ? undefined : mediaUrl || undefined,
|
|
72
|
+
mediaUrls: dedupedMediaUrls,
|
|
55
73
|
asVoice,
|
|
56
74
|
audioAsVoice,
|
|
57
75
|
...(type ? { type } : {}),
|
|
@@ -140,37 +140,39 @@ export function createBncrChannelPluginSurfaceGroup(runtime: {
|
|
|
140
140
|
const normalized = normalizeBncrSendParams({ params, accountId: accountId || '' });
|
|
141
141
|
|
|
142
142
|
const toolActionBridge = runtime.getToolActionBridge();
|
|
143
|
-
const result =
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
143
|
+
const result =
|
|
144
|
+
normalized.mediaUrl || normalized.mediaUrls?.length
|
|
145
|
+
? await sendBncrMedia({
|
|
146
|
+
channelId: runtime.channelId,
|
|
147
|
+
accountId: normalized.accountId,
|
|
148
|
+
to: normalized.to,
|
|
149
|
+
text: normalized.caption,
|
|
150
|
+
mediaUrl: normalized.mediaUrl,
|
|
151
|
+
mediaUrls: normalized.mediaUrls,
|
|
152
|
+
asVoice: normalized.asVoice,
|
|
153
|
+
audioAsVoice: normalized.audioAsVoice,
|
|
154
|
+
type: normalized.type,
|
|
155
|
+
mediaLocalRoots,
|
|
156
|
+
resolveVerifiedTarget: (to, accountId) =>
|
|
157
|
+
toolActionBridge.resolveVerifiedTarget(to, accountId),
|
|
158
|
+
rememberSessionRoute: (sessionKey, accountId, route) =>
|
|
159
|
+
toolActionBridge.rememberSessionRoute(sessionKey, accountId, route),
|
|
160
|
+
enqueueFromReply: (args) => toolActionBridge.enqueueFromReply(args),
|
|
161
|
+
createMessageId: () => randomUUID(),
|
|
162
|
+
})
|
|
163
|
+
: await sendBncrText({
|
|
164
|
+
channelId: runtime.channelId,
|
|
165
|
+
accountId: normalized.accountId,
|
|
166
|
+
to: normalized.to,
|
|
167
|
+
text: normalized.message,
|
|
168
|
+
mediaLocalRoots,
|
|
169
|
+
resolveVerifiedTarget: (to, accountId) =>
|
|
170
|
+
toolActionBridge.resolveVerifiedTarget(to, accountId),
|
|
171
|
+
rememberSessionRoute: (sessionKey, accountId, route) =>
|
|
172
|
+
toolActionBridge.rememberSessionRoute(sessionKey, accountId, route),
|
|
173
|
+
enqueueFromReply: (args) => toolActionBridge.enqueueFromReply(args),
|
|
174
|
+
createMessageId: () => randomUUID(),
|
|
175
|
+
});
|
|
174
176
|
|
|
175
177
|
return runtime.openClawJsonResult({ ok: true, ...result });
|
|
176
178
|
},
|