@nextclaw/openclaw-compat 0.1.1 → 0.1.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.d.ts +118 -1
- package/dist/index.js +271 -15
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -59,10 +59,58 @@ type OpenClawProviderPlugin = {
|
|
|
59
59
|
models?: Record<string, unknown>;
|
|
60
60
|
auth?: Array<Record<string, unknown>>;
|
|
61
61
|
};
|
|
62
|
+
type OpenClawChannelConfigSchema = {
|
|
63
|
+
schema: Record<string, unknown>;
|
|
64
|
+
uiHints?: Record<string, PluginConfigUiHint>;
|
|
65
|
+
};
|
|
66
|
+
type OpenClawChannelSetup = {
|
|
67
|
+
validateInput?: (params: {
|
|
68
|
+
cfg: Record<string, unknown>;
|
|
69
|
+
input: unknown;
|
|
70
|
+
accountId?: string | null;
|
|
71
|
+
}) => string | null;
|
|
72
|
+
applyAccountConfig?: (params: {
|
|
73
|
+
cfg: Record<string, unknown>;
|
|
74
|
+
input: unknown;
|
|
75
|
+
accountId?: string | null;
|
|
76
|
+
}) => Record<string, unknown>;
|
|
77
|
+
};
|
|
78
|
+
type OpenClawChannelGatewayStartContext = {
|
|
79
|
+
accountId?: string | null;
|
|
80
|
+
log?: {
|
|
81
|
+
debug?: (message: string) => void;
|
|
82
|
+
info?: (message: string) => void;
|
|
83
|
+
warn?: (message: string) => void;
|
|
84
|
+
error?: (message: string) => void;
|
|
85
|
+
};
|
|
86
|
+
};
|
|
87
|
+
type OpenClawChannelGateway = {
|
|
88
|
+
startAccount?: (ctx: OpenClawChannelGatewayStartContext) => Promise<void | {
|
|
89
|
+
stop?: () => void | Promise<void>;
|
|
90
|
+
}> | void | {
|
|
91
|
+
stop?: () => void | Promise<void>;
|
|
92
|
+
};
|
|
93
|
+
};
|
|
94
|
+
type OpenClawChannelConfigAdapter = {
|
|
95
|
+
listAccountIds?: (cfg?: Record<string, unknown>) => string[];
|
|
96
|
+
defaultAccountId?: (cfg?: Record<string, unknown>) => string;
|
|
97
|
+
};
|
|
98
|
+
type OpenClawChannelAgentPrompt = {
|
|
99
|
+
messageToolHints?: (params: {
|
|
100
|
+
cfg: Config;
|
|
101
|
+
accountId?: string | null;
|
|
102
|
+
}) => string[];
|
|
103
|
+
};
|
|
62
104
|
type OpenClawChannelPlugin = {
|
|
63
105
|
id: string;
|
|
64
106
|
meta?: Record<string, unknown>;
|
|
65
107
|
capabilities?: Record<string, unknown>;
|
|
108
|
+
configSchema?: OpenClawChannelConfigSchema;
|
|
109
|
+
config?: OpenClawChannelConfigAdapter;
|
|
110
|
+
setup?: OpenClawChannelSetup;
|
|
111
|
+
gateway?: OpenClawChannelGateway;
|
|
112
|
+
agentTools?: OpenClawPluginTool[] | (() => OpenClawPluginTool | OpenClawPluginTool[] | null | undefined);
|
|
113
|
+
agentPrompt?: OpenClawChannelAgentPrompt;
|
|
66
114
|
outbound?: {
|
|
67
115
|
sendText?: (ctx: {
|
|
68
116
|
cfg: Config;
|
|
@@ -141,8 +189,38 @@ type PluginProviderRegistration = {
|
|
|
141
189
|
provider: OpenClawProviderPlugin;
|
|
142
190
|
source: string;
|
|
143
191
|
};
|
|
192
|
+
type PluginReplyDispatchParams = {
|
|
193
|
+
ctx: {
|
|
194
|
+
Body?: string;
|
|
195
|
+
BodyForAgent?: string;
|
|
196
|
+
BodyForCommands?: string;
|
|
197
|
+
ChatType?: string;
|
|
198
|
+
SenderId?: string;
|
|
199
|
+
SenderName?: string;
|
|
200
|
+
SessionKey?: string;
|
|
201
|
+
AccountId?: string;
|
|
202
|
+
OriginatingChannel?: string;
|
|
203
|
+
OriginatingTo?: string;
|
|
204
|
+
Provider?: string;
|
|
205
|
+
Surface?: string;
|
|
206
|
+
[key: string]: unknown;
|
|
207
|
+
};
|
|
208
|
+
cfg?: unknown;
|
|
209
|
+
dispatcherOptions: {
|
|
210
|
+
deliver: (replyPayload: {
|
|
211
|
+
text?: string;
|
|
212
|
+
}, info: {
|
|
213
|
+
kind: string;
|
|
214
|
+
}) => Promise<void> | void;
|
|
215
|
+
onError?: (error: unknown) => void;
|
|
216
|
+
};
|
|
217
|
+
};
|
|
144
218
|
type PluginRuntime = {
|
|
145
219
|
version: string;
|
|
220
|
+
config: {
|
|
221
|
+
loadConfig: () => Record<string, unknown>;
|
|
222
|
+
writeConfigFile: (next: Record<string, unknown>) => Promise<void>;
|
|
223
|
+
};
|
|
146
224
|
tools: {
|
|
147
225
|
createMemorySearchTool: (params: {
|
|
148
226
|
config?: Config;
|
|
@@ -153,6 +231,11 @@ type PluginRuntime = {
|
|
|
153
231
|
agentSessionKey?: string;
|
|
154
232
|
}) => OpenClawPluginTool | null;
|
|
155
233
|
};
|
|
234
|
+
channel: {
|
|
235
|
+
reply: {
|
|
236
|
+
dispatchReplyWithBufferedBlockDispatcher: (params: PluginReplyDispatchParams) => Promise<void>;
|
|
237
|
+
};
|
|
238
|
+
};
|
|
156
239
|
};
|
|
157
240
|
type OpenClawPluginApi = {
|
|
158
241
|
id: string;
|
|
@@ -254,6 +337,34 @@ declare function enablePluginInConfig(config: Config, pluginId: string): Config;
|
|
|
254
337
|
declare function disablePluginInConfig(config: Config, pluginId: string): Config;
|
|
255
338
|
declare function addPluginLoadPath(config: Config, loadPath: string): Config;
|
|
256
339
|
|
|
340
|
+
type PluginChannelBinding = {
|
|
341
|
+
pluginId: string;
|
|
342
|
+
channelId: string;
|
|
343
|
+
channel: OpenClawChannelPlugin;
|
|
344
|
+
};
|
|
345
|
+
type PluginChannelGatewayHandle = {
|
|
346
|
+
pluginId: string;
|
|
347
|
+
channelId: string;
|
|
348
|
+
accountId: string;
|
|
349
|
+
stop?: () => void | Promise<void>;
|
|
350
|
+
};
|
|
351
|
+
declare function getPluginChannelBindings(registry: PluginRegistry): PluginChannelBinding[];
|
|
352
|
+
declare function resolvePluginChannelMessageToolHints(params: {
|
|
353
|
+
registry: PluginRegistry;
|
|
354
|
+
channel?: string | null;
|
|
355
|
+
cfg?: Config;
|
|
356
|
+
accountId?: string | null;
|
|
357
|
+
}): string[];
|
|
358
|
+
declare function getPluginUiMetadataFromRegistry(registry: PluginRegistry): PluginUiMetadata[];
|
|
359
|
+
declare function startPluginChannelGateways(params: {
|
|
360
|
+
registry: PluginRegistry;
|
|
361
|
+
logger?: PluginLogger;
|
|
362
|
+
}): Promise<{
|
|
363
|
+
handles: PluginChannelGatewayHandle[];
|
|
364
|
+
diagnostics: PluginDiagnostic[];
|
|
365
|
+
}>;
|
|
366
|
+
declare function stopPluginChannelGateways(handles: PluginChannelGatewayHandle[]): Promise<void>;
|
|
367
|
+
|
|
257
368
|
type PluginCandidate = {
|
|
258
369
|
idHint: string;
|
|
259
370
|
source: string;
|
|
@@ -396,6 +507,12 @@ type PackageManifest = {
|
|
|
396
507
|
};
|
|
397
508
|
declare function getPackageManifestMetadata(manifest: PackageManifest | undefined): OpenClawPackageManifest | undefined;
|
|
398
509
|
|
|
510
|
+
type PluginRuntimeBridge = {
|
|
511
|
+
loadConfig?: () => Record<string, unknown>;
|
|
512
|
+
writeConfigFile?: (next: Record<string, unknown>) => Promise<void>;
|
|
513
|
+
dispatchReplyWithBufferedBlockDispatcher?: (params: PluginReplyDispatchParams) => Promise<void>;
|
|
514
|
+
};
|
|
515
|
+
declare function setPluginRuntimeBridge(next: PluginRuntimeBridge | null): void;
|
|
399
516
|
declare function createPluginRuntime(params: {
|
|
400
517
|
workspace: string;
|
|
401
518
|
config?: Config;
|
|
@@ -459,4 +576,4 @@ declare function uninstallPlugin(params: {
|
|
|
459
576
|
extensionsDir?: string;
|
|
460
577
|
}): Promise<UninstallPluginResult>;
|
|
461
578
|
|
|
462
|
-
export { DEFAULT_ACCOUNT_ID, type InstallPluginResult, type NormalizedPluginsConfig, type OpenClawChannelPlugin, type OpenClawPluginApi, type OpenClawPluginChannelRegistration, type OpenClawPluginConfigSchema, type OpenClawPluginDefinition, type OpenClawPluginModule, type OpenClawPluginTool, type OpenClawPluginToolContext, type OpenClawPluginToolFactory, type OpenClawPluginToolOptions, type OpenClawProviderPlugin, PLUGIN_MANIFEST_FILENAME, PLUGIN_MANIFEST_FILENAMES, type PackageManifest, type PluginCandidate, type PluginChannelRegistration, type PluginConfigUiHint, type PluginDiagnostic, type PluginDiscoveryResult, type PluginInstallLogger, type PluginInstallSource, type PluginInstallUpdate, type PluginKind, type PluginLoadOptions, type PluginLogger, type PluginManifest, type PluginManifestLoadResult, type PluginManifestRecord, type PluginManifestRegistry, type PluginOrigin, type PluginProviderRegistration, type PluginRecord, type PluginRegistry, type PluginRuntime, type PluginStatusReport, type PluginToolRegistration, type PluginUiMetadata, type UninstallActions, type UninstallPluginResult, type _CompatOnly, __nextclawPluginSdkCompat, addPluginLoadPath, buildChannelConfigSchema, buildOauthProviderAuthResult, buildPluginStatusReport, createPluginRuntime, disablePluginInConfig, discoverOpenClawPlugins, emptyPluginConfigSchema, enablePluginInConfig, getPackageManifestMetadata, installPluginFromArchive, installPluginFromDir, installPluginFromFile, installPluginFromNpmSpec, installPluginFromPath, loadOpenClawPlugins, loadPluginManifest, loadPluginManifestRegistry, loadPluginUiMetadata, normalizeAccountId, normalizePluginHttpPath, normalizePluginsConfig, recordPluginInstall, removePluginFromConfig, resolveEnableState, resolvePluginInstallDir, resolvePluginManifestPath, resolveUninstallDirectoryTarget, sleep, toPluginUiMetadata, uninstallPlugin, validateJsonSchemaValue };
|
|
579
|
+
export { DEFAULT_ACCOUNT_ID, type InstallPluginResult, type NormalizedPluginsConfig, type OpenClawChannelAgentPrompt, type OpenClawChannelConfigAdapter, type OpenClawChannelConfigSchema, type OpenClawChannelGateway, type OpenClawChannelGatewayStartContext, type OpenClawChannelPlugin, type OpenClawChannelSetup, type OpenClawPluginApi, type OpenClawPluginChannelRegistration, type OpenClawPluginConfigSchema, type OpenClawPluginDefinition, type OpenClawPluginModule, type OpenClawPluginTool, type OpenClawPluginToolContext, type OpenClawPluginToolFactory, type OpenClawPluginToolOptions, type OpenClawProviderPlugin, PLUGIN_MANIFEST_FILENAME, PLUGIN_MANIFEST_FILENAMES, type PackageManifest, type PluginCandidate, type PluginChannelBinding, type PluginChannelGatewayHandle, type PluginChannelRegistration, type PluginConfigUiHint, type PluginDiagnostic, type PluginDiscoveryResult, type PluginInstallLogger, type PluginInstallSource, type PluginInstallUpdate, type PluginKind, type PluginLoadOptions, type PluginLogger, type PluginManifest, type PluginManifestLoadResult, type PluginManifestRecord, type PluginManifestRegistry, type PluginOrigin, type PluginProviderRegistration, type PluginRecord, type PluginRegistry, type PluginReplyDispatchParams, type PluginRuntime, type PluginRuntimeBridge, type PluginStatusReport, type PluginToolRegistration, type PluginUiMetadata, type UninstallActions, type UninstallPluginResult, type _CompatOnly, __nextclawPluginSdkCompat, addPluginLoadPath, buildChannelConfigSchema, buildOauthProviderAuthResult, buildPluginStatusReport, createPluginRuntime, disablePluginInConfig, discoverOpenClawPlugins, emptyPluginConfigSchema, enablePluginInConfig, getPackageManifestMetadata, getPluginChannelBindings, getPluginUiMetadataFromRegistry, installPluginFromArchive, installPluginFromDir, installPluginFromFile, installPluginFromNpmSpec, installPluginFromPath, loadOpenClawPlugins, loadPluginManifest, loadPluginManifestRegistry, loadPluginUiMetadata, normalizeAccountId, normalizePluginHttpPath, normalizePluginsConfig, recordPluginInstall, removePluginFromConfig, resolveEnableState, resolvePluginChannelMessageToolHints, resolvePluginInstallDir, resolvePluginManifestPath, resolveUninstallDirectoryTarget, setPluginRuntimeBridge, sleep, startPluginChannelGateways, stopPluginChannelGateways, toPluginUiMetadata, uninstallPlugin, validateJsonSchemaValue };
|
package/dist/index.js
CHANGED
|
@@ -169,6 +169,125 @@ function addPluginLoadPath(config, loadPath) {
|
|
|
169
169
|
};
|
|
170
170
|
}
|
|
171
171
|
|
|
172
|
+
// src/plugins/channel-runtime.ts
|
|
173
|
+
function normalizeChannelId(channel) {
|
|
174
|
+
return (channel ?? "").trim().toLowerCase();
|
|
175
|
+
}
|
|
176
|
+
function toBinding(registration) {
|
|
177
|
+
const channelId = registration.channel.id?.trim();
|
|
178
|
+
if (!channelId) {
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
return {
|
|
182
|
+
pluginId: registration.pluginId,
|
|
183
|
+
channelId,
|
|
184
|
+
channel: registration.channel
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
function getPluginChannelBindings(registry) {
|
|
188
|
+
const bindings = [];
|
|
189
|
+
for (const entry of registry.channels) {
|
|
190
|
+
const binding = toBinding(entry);
|
|
191
|
+
if (!binding) {
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
bindings.push(binding);
|
|
195
|
+
}
|
|
196
|
+
return bindings;
|
|
197
|
+
}
|
|
198
|
+
function resolvePluginChannelMessageToolHints(params) {
|
|
199
|
+
const channelId = normalizeChannelId(params.channel);
|
|
200
|
+
if (!channelId) {
|
|
201
|
+
return [];
|
|
202
|
+
}
|
|
203
|
+
const binding = getPluginChannelBindings(params.registry).find(
|
|
204
|
+
(entry) => normalizeChannelId(entry.channelId) === channelId
|
|
205
|
+
);
|
|
206
|
+
if (!binding) {
|
|
207
|
+
return [];
|
|
208
|
+
}
|
|
209
|
+
const resolveHints = binding.channel.agentPrompt?.messageToolHints;
|
|
210
|
+
if (typeof resolveHints !== "function") {
|
|
211
|
+
return [];
|
|
212
|
+
}
|
|
213
|
+
try {
|
|
214
|
+
const hinted = resolveHints({
|
|
215
|
+
cfg: params.cfg ?? {},
|
|
216
|
+
accountId: params.accountId
|
|
217
|
+
});
|
|
218
|
+
if (!Array.isArray(hinted)) {
|
|
219
|
+
return [];
|
|
220
|
+
}
|
|
221
|
+
return hinted.map((entry) => typeof entry === "string" ? entry.trim() : "").filter(Boolean);
|
|
222
|
+
} catch {
|
|
223
|
+
return [];
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
function getPluginUiMetadataFromRegistry(registry) {
|
|
227
|
+
return registry.plugins.map((plugin) => ({
|
|
228
|
+
id: plugin.id,
|
|
229
|
+
configSchema: plugin.configJsonSchema,
|
|
230
|
+
configUiHints: plugin.configUiHints
|
|
231
|
+
}));
|
|
232
|
+
}
|
|
233
|
+
async function startPluginChannelGateways(params) {
|
|
234
|
+
const logger = params.logger;
|
|
235
|
+
const diagnostics = [];
|
|
236
|
+
const handles = [];
|
|
237
|
+
for (const binding of getPluginChannelBindings(params.registry)) {
|
|
238
|
+
const gateway = binding.channel.gateway;
|
|
239
|
+
if (!gateway?.startAccount) {
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
242
|
+
const accountIdsRaw = binding.channel.config?.listAccountIds?.() ?? [binding.channel.config?.defaultAccountId?.() ?? "default"];
|
|
243
|
+
const accountIds = Array.from(
|
|
244
|
+
new Set(accountIdsRaw.map((id) => typeof id === "string" ? id.trim() : "").filter(Boolean))
|
|
245
|
+
);
|
|
246
|
+
const finalAccountIds = accountIds.length > 0 ? accountIds : ["default"];
|
|
247
|
+
for (const accountId of finalAccountIds) {
|
|
248
|
+
try {
|
|
249
|
+
const started = await gateway.startAccount({
|
|
250
|
+
accountId,
|
|
251
|
+
log: logger
|
|
252
|
+
});
|
|
253
|
+
handles.push({
|
|
254
|
+
pluginId: binding.pluginId,
|
|
255
|
+
channelId: binding.channelId,
|
|
256
|
+
accountId,
|
|
257
|
+
stop: started && typeof started === "object" && "stop" in started && typeof started.stop === "function" ? started.stop : void 0
|
|
258
|
+
});
|
|
259
|
+
} catch (error) {
|
|
260
|
+
const raw = String(error);
|
|
261
|
+
const lower = raw.toLowerCase();
|
|
262
|
+
const level = lower.includes("required") || lower.includes("not configured") || lower.includes("missing") ? "warn" : "error";
|
|
263
|
+
const message = `failed to start channel gateway for ${binding.channelId}/${accountId}: ${raw}`;
|
|
264
|
+
diagnostics.push({
|
|
265
|
+
level,
|
|
266
|
+
pluginId: binding.pluginId,
|
|
267
|
+
message
|
|
268
|
+
});
|
|
269
|
+
if (level === "error") {
|
|
270
|
+
logger?.error(message);
|
|
271
|
+
} else {
|
|
272
|
+
logger?.warn(message);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
return { handles, diagnostics };
|
|
278
|
+
}
|
|
279
|
+
async function stopPluginChannelGateways(handles) {
|
|
280
|
+
for (const handle of handles) {
|
|
281
|
+
if (!handle.stop) {
|
|
282
|
+
continue;
|
|
283
|
+
}
|
|
284
|
+
try {
|
|
285
|
+
await handle.stop();
|
|
286
|
+
} catch {
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
172
291
|
// src/plugins/discovery.ts
|
|
173
292
|
import fs2 from "fs";
|
|
174
293
|
import path2 from "path";
|
|
@@ -736,19 +855,23 @@ async function installPluginFromPackageDir(params) {
|
|
|
736
855
|
}
|
|
737
856
|
logger.info?.(`Installing to ${targetDir}...`);
|
|
738
857
|
await fs3.cp(packageDir, targetDir, { recursive: true, force: true });
|
|
739
|
-
for (const extensionPath of extensions) {
|
|
740
|
-
const resolved = path3.resolve(targetDir, extensionPath);
|
|
741
|
-
if (!resolved.startsWith(path3.resolve(targetDir) + path3.sep) && resolved !== path3.resolve(targetDir)) {
|
|
742
|
-
return { ok: false, error: `extension entry escapes plugin directory: ${extensionPath}` };
|
|
743
|
-
}
|
|
744
|
-
if (!await exists(resolved)) {
|
|
745
|
-
logger.warn?.(`extension entry not found: ${extensionPath}`);
|
|
746
|
-
}
|
|
747
|
-
}
|
|
748
858
|
try {
|
|
859
|
+
for (const extensionPath of extensions) {
|
|
860
|
+
const resolved = path3.resolve(targetDir, extensionPath);
|
|
861
|
+
if (!resolved.startsWith(path3.resolve(targetDir) + path3.sep) && resolved !== path3.resolve(targetDir)) {
|
|
862
|
+
throw new Error(`extension entry escapes plugin directory: ${extensionPath}`);
|
|
863
|
+
}
|
|
864
|
+
if (!await exists(resolved)) {
|
|
865
|
+
throw new Error(`extension entry not found after install: ${extensionPath}`);
|
|
866
|
+
}
|
|
867
|
+
}
|
|
749
868
|
await installDependenciesIfNeeded(targetDir, packageManifest, logger);
|
|
750
869
|
} catch (err) {
|
|
751
|
-
|
|
870
|
+
await fs3.rm(targetDir, { recursive: true, force: true }).catch(() => void 0);
|
|
871
|
+
return {
|
|
872
|
+
ok: false,
|
|
873
|
+
error: err instanceof Error ? err.message : `failed to install dependencies: ${String(err)}`
|
|
874
|
+
};
|
|
752
875
|
}
|
|
753
876
|
return {
|
|
754
877
|
ok: true,
|
|
@@ -785,7 +908,7 @@ async function installPluginFromArchive(params) {
|
|
|
785
908
|
} catch (err) {
|
|
786
909
|
return { ok: false, error: String(err) };
|
|
787
910
|
}
|
|
788
|
-
return installPluginFromPackageDir({
|
|
911
|
+
return await installPluginFromPackageDir({
|
|
789
912
|
packageDir,
|
|
790
913
|
extensionsDir: params.extensionsDir,
|
|
791
914
|
logger,
|
|
@@ -892,7 +1015,7 @@ async function installPluginFromNpmSpec(params) {
|
|
|
892
1015
|
return { ok: false, error: "npm pack produced no archive" };
|
|
893
1016
|
}
|
|
894
1017
|
const archivePath = path3.join(tempDir, archiveName);
|
|
895
|
-
return installPluginFromArchive({
|
|
1018
|
+
return await installPluginFromArchive({
|
|
896
1019
|
archivePath,
|
|
897
1020
|
extensionsDir: params.extensionsDir,
|
|
898
1021
|
logger,
|
|
@@ -1096,6 +1219,10 @@ function loadPluginUiMetadata(params) {
|
|
|
1096
1219
|
// src/plugins/runtime.ts
|
|
1097
1220
|
import { getPackageVersion } from "@nextclaw/core";
|
|
1098
1221
|
import { MemoryGetTool, MemorySearchTool } from "@nextclaw/core";
|
|
1222
|
+
var bridge = {};
|
|
1223
|
+
function setPluginRuntimeBridge(next) {
|
|
1224
|
+
bridge = next ?? {};
|
|
1225
|
+
}
|
|
1099
1226
|
function toPluginTool(tool) {
|
|
1100
1227
|
return {
|
|
1101
1228
|
name: tool.name,
|
|
@@ -1104,12 +1231,39 @@ function toPluginTool(tool) {
|
|
|
1104
1231
|
execute: (params) => tool.execute(params)
|
|
1105
1232
|
};
|
|
1106
1233
|
}
|
|
1234
|
+
function loadConfigWithFallback(config) {
|
|
1235
|
+
if (bridge.loadConfig) {
|
|
1236
|
+
return bridge.loadConfig();
|
|
1237
|
+
}
|
|
1238
|
+
return config ?? {};
|
|
1239
|
+
}
|
|
1240
|
+
async function writeConfigWithFallback(next) {
|
|
1241
|
+
if (!bridge.writeConfigFile) {
|
|
1242
|
+
throw new Error("plugin runtime config.writeConfigFile is unavailable outside gateway runtime");
|
|
1243
|
+
}
|
|
1244
|
+
await bridge.writeConfigFile(next);
|
|
1245
|
+
}
|
|
1246
|
+
async function dispatchReplyWithFallback(params) {
|
|
1247
|
+
if (!bridge.dispatchReplyWithBufferedBlockDispatcher) {
|
|
1248
|
+
throw new Error("plugin runtime channel.reply dispatcher is unavailable outside gateway runtime");
|
|
1249
|
+
}
|
|
1250
|
+
await bridge.dispatchReplyWithBufferedBlockDispatcher(params);
|
|
1251
|
+
}
|
|
1107
1252
|
function createPluginRuntime(params) {
|
|
1108
1253
|
return {
|
|
1109
1254
|
version: getPackageVersion(),
|
|
1255
|
+
config: {
|
|
1256
|
+
loadConfig: () => loadConfigWithFallback(params.config),
|
|
1257
|
+
writeConfigFile: async (next) => writeConfigWithFallback(next)
|
|
1258
|
+
},
|
|
1110
1259
|
tools: {
|
|
1111
1260
|
createMemorySearchTool: () => toPluginTool(new MemorySearchTool(params.workspace)),
|
|
1112
1261
|
createMemoryGetTool: () => toPluginTool(new MemoryGetTool(params.workspace))
|
|
1262
|
+
},
|
|
1263
|
+
channel: {
|
|
1264
|
+
reply: {
|
|
1265
|
+
dispatchReplyWithBufferedBlockDispatcher: async (dispatchParams) => dispatchReplyWithFallback(dispatchParams)
|
|
1266
|
+
}
|
|
1113
1267
|
}
|
|
1114
1268
|
};
|
|
1115
1269
|
}
|
|
@@ -1272,8 +1426,21 @@ function ensureUniqueNames(params) {
|
|
|
1272
1426
|
}
|
|
1273
1427
|
return accepted;
|
|
1274
1428
|
}
|
|
1429
|
+
function isPlaceholderConfigSchema(schema) {
|
|
1430
|
+
if (!schema || typeof schema !== "object") {
|
|
1431
|
+
return false;
|
|
1432
|
+
}
|
|
1433
|
+
const type = schema.type;
|
|
1434
|
+
const isObjectType = type === "object" || Array.isArray(type) && type.includes("object");
|
|
1435
|
+
if (!isObjectType) {
|
|
1436
|
+
return false;
|
|
1437
|
+
}
|
|
1438
|
+
const properties = schema.properties;
|
|
1439
|
+
const noProperties = !properties || typeof properties === "object" && !Array.isArray(properties) && Object.keys(properties).length === 0;
|
|
1440
|
+
return noProperties && schema.additionalProperties === false;
|
|
1441
|
+
}
|
|
1275
1442
|
function validatePluginConfig(params) {
|
|
1276
|
-
if (!params.schema) {
|
|
1443
|
+
if (!params.schema || isPlaceholderConfigSchema(params.schema)) {
|
|
1277
1444
|
return { ok: true, value: params.value };
|
|
1278
1445
|
}
|
|
1279
1446
|
const cacheKey = params.cacheKey ?? JSON.stringify(params.schema);
|
|
@@ -1567,12 +1734,95 @@ function loadOpenClawPlugins(options) {
|
|
|
1567
1734
|
if (accepted.length === 0) {
|
|
1568
1735
|
return;
|
|
1569
1736
|
}
|
|
1737
|
+
const channelPlugin = normalizedChannel;
|
|
1570
1738
|
registry.channels.push({
|
|
1571
1739
|
pluginId,
|
|
1572
|
-
channel:
|
|
1740
|
+
channel: channelPlugin,
|
|
1573
1741
|
source: candidate.source
|
|
1574
1742
|
});
|
|
1575
|
-
|
|
1743
|
+
const channelId = accepted[0];
|
|
1744
|
+
record.channelIds.push(channelId);
|
|
1745
|
+
const configSchema = channelPlugin.configSchema;
|
|
1746
|
+
if (configSchema && typeof configSchema === "object") {
|
|
1747
|
+
const schema = configSchema.schema;
|
|
1748
|
+
if (schema && typeof schema === "object" && !Array.isArray(schema)) {
|
|
1749
|
+
record.configJsonSchema = schema;
|
|
1750
|
+
record.configSchema = true;
|
|
1751
|
+
}
|
|
1752
|
+
const uiHints = configSchema.uiHints;
|
|
1753
|
+
if (uiHints && typeof uiHints === "object" && !Array.isArray(uiHints)) {
|
|
1754
|
+
record.configUiHints = {
|
|
1755
|
+
...record.configUiHints ?? {},
|
|
1756
|
+
...uiHints
|
|
1757
|
+
};
|
|
1758
|
+
}
|
|
1759
|
+
}
|
|
1760
|
+
const pushChannelTools = (value, optional, sourceLabel, resolveValue) => {
|
|
1761
|
+
const previewTools = normalizeToolList(value);
|
|
1762
|
+
if (previewTools.length === 0) {
|
|
1763
|
+
return;
|
|
1764
|
+
}
|
|
1765
|
+
const declaredNames = previewTools.map((tool) => tool.name);
|
|
1766
|
+
const acceptedNames = ensureUniqueNames({
|
|
1767
|
+
names: declaredNames,
|
|
1768
|
+
pluginId,
|
|
1769
|
+
diagnostics: registry.diagnostics,
|
|
1770
|
+
source: candidate.source,
|
|
1771
|
+
owners: toolNameOwners,
|
|
1772
|
+
reserved: reservedToolNames,
|
|
1773
|
+
kind: "tool"
|
|
1774
|
+
});
|
|
1775
|
+
if (acceptedNames.length === 0) {
|
|
1776
|
+
return;
|
|
1777
|
+
}
|
|
1778
|
+
const factory = (ctx) => {
|
|
1779
|
+
const tools = normalizeToolList(resolveValue(ctx));
|
|
1780
|
+
if (tools.length === 0) {
|
|
1781
|
+
return [];
|
|
1782
|
+
}
|
|
1783
|
+
const byName = new Map(tools.map((tool) => [tool.name, tool]));
|
|
1784
|
+
return acceptedNames.map((name) => byName.get(name)).filter(Boolean);
|
|
1785
|
+
};
|
|
1786
|
+
registry.tools.push({
|
|
1787
|
+
pluginId,
|
|
1788
|
+
factory,
|
|
1789
|
+
names: acceptedNames,
|
|
1790
|
+
optional,
|
|
1791
|
+
source: candidate.source
|
|
1792
|
+
});
|
|
1793
|
+
record.toolNames.push(...acceptedNames);
|
|
1794
|
+
const previewByName = new Map(previewTools.map((tool) => [tool.name, tool]));
|
|
1795
|
+
for (const name of acceptedNames) {
|
|
1796
|
+
const resolvedTool = previewByName.get(name);
|
|
1797
|
+
if (!resolvedTool || resolvedToolNames.has(resolvedTool.name)) {
|
|
1798
|
+
continue;
|
|
1799
|
+
}
|
|
1800
|
+
resolvedToolNames.add(resolvedTool.name);
|
|
1801
|
+
registry.resolvedTools.push(resolvedTool);
|
|
1802
|
+
}
|
|
1803
|
+
registry.diagnostics.push({
|
|
1804
|
+
level: "warn",
|
|
1805
|
+
pluginId,
|
|
1806
|
+
source: candidate.source,
|
|
1807
|
+
message: `${sourceLabel} registered channel-owned tools: ${acceptedNames.join(", ")}`
|
|
1808
|
+
});
|
|
1809
|
+
};
|
|
1810
|
+
const agentTools = channelPlugin.agentTools;
|
|
1811
|
+
if (typeof agentTools === "function") {
|
|
1812
|
+
pushChannelTools(
|
|
1813
|
+
normalizeToolList(agentTools()),
|
|
1814
|
+
false,
|
|
1815
|
+
`channel "${channelId}"`,
|
|
1816
|
+
() => agentTools()
|
|
1817
|
+
);
|
|
1818
|
+
} else if (agentTools) {
|
|
1819
|
+
pushChannelTools(
|
|
1820
|
+
normalizeToolList(agentTools),
|
|
1821
|
+
false,
|
|
1822
|
+
`channel "${channelId}"`,
|
|
1823
|
+
() => agentTools
|
|
1824
|
+
);
|
|
1825
|
+
}
|
|
1576
1826
|
},
|
|
1577
1827
|
registerProvider: (provider) => {
|
|
1578
1828
|
const accepted = ensureUniqueNames({
|
|
@@ -1810,6 +2060,8 @@ export {
|
|
|
1810
2060
|
emptyPluginConfigSchema,
|
|
1811
2061
|
enablePluginInConfig,
|
|
1812
2062
|
getPackageManifestMetadata,
|
|
2063
|
+
getPluginChannelBindings,
|
|
2064
|
+
getPluginUiMetadataFromRegistry,
|
|
1813
2065
|
installPluginFromArchive,
|
|
1814
2066
|
installPluginFromDir,
|
|
1815
2067
|
installPluginFromFile,
|
|
@@ -1825,10 +2077,14 @@ export {
|
|
|
1825
2077
|
recordPluginInstall,
|
|
1826
2078
|
removePluginFromConfig,
|
|
1827
2079
|
resolveEnableState,
|
|
2080
|
+
resolvePluginChannelMessageToolHints,
|
|
1828
2081
|
resolvePluginInstallDir,
|
|
1829
2082
|
resolvePluginManifestPath,
|
|
1830
2083
|
resolveUninstallDirectoryTarget,
|
|
2084
|
+
setPluginRuntimeBridge,
|
|
1831
2085
|
sleep,
|
|
2086
|
+
startPluginChannelGateways,
|
|
2087
|
+
stopPluginChannelGateways,
|
|
1832
2088
|
toPluginUiMetadata,
|
|
1833
2089
|
uninstallPlugin,
|
|
1834
2090
|
validateJsonSchemaValue
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nextclaw/openclaw-compat",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "OpenClaw plugin compatibility layer for NextClaw.",
|
|
6
6
|
"type": "module",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"jiti": "^1.21.7",
|
|
19
19
|
"jszip": "^3.10.1",
|
|
20
20
|
"tar": "^7.4.3",
|
|
21
|
-
"@nextclaw/core": "^0.4.
|
|
21
|
+
"@nextclaw/core": "^0.4.9"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
24
|
"@types/node": "^20.17.6",
|