@cored-im/openclaw-plugin 0.1.7 → 0.1.11
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 +1 -5
- package/README.zh.md +1 -5
- package/dist/index.cjs +124 -143
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -9
- package/dist/index.d.ts +11 -9
- package/dist/index.js +124 -143
- package/dist/index.js.map +1 -1
- package/dist/setup-entry.cjs +114 -117
- package/dist/setup-entry.cjs.map +1 -1
- package/dist/setup-entry.d.cts +4 -9
- package/dist/setup-entry.d.ts +4 -9
- package/dist/setup-entry.js +114 -117
- package/dist/setup-entry.js.map +1 -1
- package/dist/types-BEkT8vuK.d.cts +11 -0
- package/dist/types-BEkT8vuK.d.ts +11 -0
- package/openclaw.plugin.json +6 -53
- package/package.json +3 -2
- package/src/channel.ts +129 -134
- package/src/config.test.ts +4 -10
- package/src/config.ts +1 -11
- package/src/index.ts +15 -21
- package/src/messaging/inbound.test.ts +12 -160
- package/src/messaging/inbound.ts +12 -41
- package/src/setup-entry.ts +2 -2
- package/src/types.ts +3 -16
- package/src/typings/openclaw-plugin-sdk.d.ts +0 -162
package/dist/index.js
CHANGED
|
@@ -10,9 +10,7 @@ import {
|
|
|
10
10
|
// src/config.ts
|
|
11
11
|
var DEFAULTS = {
|
|
12
12
|
enableEncryption: true,
|
|
13
|
-
requestTimeout: 3e4
|
|
14
|
-
requireMention: true,
|
|
15
|
-
inboundWhitelist: []
|
|
13
|
+
requestTimeout: 3e4
|
|
16
14
|
};
|
|
17
15
|
var ENV_PREFIX = "CORED_";
|
|
18
16
|
function getChannelConfig(cfg) {
|
|
@@ -31,10 +29,6 @@ function readEnvConfig() {
|
|
|
31
29
|
result.enableEncryption = env[`${ENV_PREFIX}ENABLE_ENCRYPTION`] !== "false";
|
|
32
30
|
if (env[`${ENV_PREFIX}REQUEST_TIMEOUT`])
|
|
33
31
|
result.requestTimeout = Number(env[`${ENV_PREFIX}REQUEST_TIMEOUT`]);
|
|
34
|
-
if (env[`${ENV_PREFIX}REQUIRE_MENTION`] !== void 0)
|
|
35
|
-
result.requireMention = env[`${ENV_PREFIX}REQUIRE_MENTION`] !== "false";
|
|
36
|
-
if (env[`${ENV_PREFIX}BOT_USER_ID`])
|
|
37
|
-
result.botUserId = env[`${ENV_PREFIX}BOT_USER_ID`];
|
|
38
32
|
return result;
|
|
39
33
|
}
|
|
40
34
|
function listAccountIds(cfg) {
|
|
@@ -55,15 +49,12 @@ function resolveAccountConfig(cfg, accountId) {
|
|
|
55
49
|
const raw = ch?.accounts?.[id] ?? ch;
|
|
56
50
|
return {
|
|
57
51
|
accountId: id,
|
|
58
|
-
enabled: raw?.enabled ?? true,
|
|
59
52
|
appId: raw?.appId ?? envConfig.appId ?? "",
|
|
60
53
|
appSecret: raw?.appSecret ?? envConfig.appSecret ?? "",
|
|
61
54
|
backendUrl: raw?.backendUrl ?? envConfig.backendUrl ?? "",
|
|
55
|
+
enabled: raw?.enabled ?? true,
|
|
62
56
|
enableEncryption: raw?.enableEncryption ?? envConfig.enableEncryption ?? DEFAULTS.enableEncryption,
|
|
63
|
-
requestTimeout: raw?.requestTimeout ?? envConfig.requestTimeout ?? DEFAULTS.requestTimeout
|
|
64
|
-
requireMention: raw?.requireMention ?? envConfig.requireMention ?? DEFAULTS.requireMention,
|
|
65
|
-
botUserId: raw?.botUserId ?? envConfig.botUserId,
|
|
66
|
-
inboundWhitelist: raw?.inboundWhitelist ?? [...DEFAULTS.inboundWhitelist]
|
|
57
|
+
requestTimeout: raw?.requestTimeout ?? envConfig.requestTimeout ?? DEFAULTS.requestTimeout
|
|
67
58
|
};
|
|
68
59
|
}
|
|
69
60
|
function validateAccountConfig(config) {
|
|
@@ -315,171 +306,177 @@ function parseTarget(to) {
|
|
|
315
306
|
}
|
|
316
307
|
|
|
317
308
|
// src/channel.ts
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
const accounts = section?.accounts;
|
|
321
|
-
const defaultAccount = section?.defaultAccount;
|
|
322
|
-
if (accounts && Object.keys(accounts).length > 0) {
|
|
323
|
-
const targetId = accountId ?? defaultAccount ?? Object.keys(accounts)[0];
|
|
324
|
-
const account = accounts[targetId];
|
|
325
|
-
if (!account) {
|
|
326
|
-
throw new Error(`cored: account "${targetId}" not found`);
|
|
327
|
-
}
|
|
328
|
-
return {
|
|
329
|
-
accountId: targetId,
|
|
330
|
-
appId: account.appId,
|
|
331
|
-
appSecret: account.appSecret,
|
|
332
|
-
backendUrl: account.backendUrl,
|
|
333
|
-
enableEncryption: account.enableEncryption ?? section.enableEncryption ?? true,
|
|
334
|
-
requestTimeout: account.requestTimeout ?? section.requestTimeout ?? 3e4,
|
|
335
|
-
requireMention: account.requireMention ?? section.requireMention ?? true
|
|
336
|
-
};
|
|
337
|
-
}
|
|
338
|
-
const appId = section?.appId;
|
|
339
|
-
const appSecret = section?.appSecret;
|
|
340
|
-
const backendUrl = section?.backendUrl;
|
|
341
|
-
if (!appId || !appSecret || !backendUrl) {
|
|
342
|
-
throw new Error("cored: appId, appSecret, and backendUrl are required");
|
|
343
|
-
}
|
|
344
|
-
return {
|
|
345
|
-
accountId: null,
|
|
346
|
-
appId,
|
|
347
|
-
appSecret,
|
|
348
|
-
backendUrl,
|
|
349
|
-
enableEncryption: section?.enableEncryption ?? true,
|
|
350
|
-
requestTimeout: section?.requestTimeout ?? 3e4,
|
|
351
|
-
requireMention: section?.requireMention ?? true
|
|
352
|
-
};
|
|
353
|
-
}
|
|
354
|
-
var coredPlugin = createChatChannelPlugin({
|
|
355
|
-
base: createChannelPluginBase({
|
|
356
|
-
id: "cored",
|
|
357
|
-
setup: {
|
|
358
|
-
resolveAccount,
|
|
359
|
-
inspectAccount(cfg, accountId) {
|
|
360
|
-
const section = cfg.channels?.["cored"];
|
|
361
|
-
const hasConfig = Boolean(
|
|
362
|
-
section?.appId && section?.appSecret && section?.backendUrl
|
|
363
|
-
);
|
|
364
|
-
return {
|
|
365
|
-
enabled: Boolean(section?.enabled !== false),
|
|
366
|
-
configured: hasConfig,
|
|
367
|
-
tokenStatus: hasConfig ? "available" : "missing"
|
|
368
|
-
};
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
}),
|
|
372
|
-
// Plugin metadata
|
|
309
|
+
var base = createChannelPluginBase({
|
|
310
|
+
id: "cored",
|
|
373
311
|
meta: {
|
|
374
312
|
id: "cored",
|
|
375
313
|
label: "Cored",
|
|
376
314
|
selectionLabel: "Cored",
|
|
377
315
|
docsPath: "/channels/cored",
|
|
378
316
|
blurb: "Connect OpenClaw to Cored",
|
|
379
|
-
aliases: ["
|
|
317
|
+
aliases: ["co"]
|
|
380
318
|
},
|
|
381
|
-
// Capabilities
|
|
382
319
|
capabilities: {
|
|
383
320
|
chatTypes: ["direct", "group"]
|
|
384
321
|
},
|
|
385
|
-
// Config
|
|
386
322
|
config: {
|
|
387
323
|
listAccountIds: (cfg) => listAccountIds(cfg),
|
|
388
|
-
resolveAccount: (cfg, accountId) => resolveAccountConfig(cfg, accountId)
|
|
324
|
+
resolveAccount: (cfg, accountId) => resolveAccountConfig(cfg, accountId ?? void 0),
|
|
325
|
+
inspectAccount(cfg, accountId) {
|
|
326
|
+
const resolved = resolveAccountConfig(cfg, accountId ?? void 0);
|
|
327
|
+
const hasConfig = Boolean(
|
|
328
|
+
resolved.appId && resolved.appSecret && resolved.backendUrl
|
|
329
|
+
);
|
|
330
|
+
return {
|
|
331
|
+
enabled: resolved.enabled,
|
|
332
|
+
configured: hasConfig,
|
|
333
|
+
tokenStatus: hasConfig ? "available" : "missing"
|
|
334
|
+
};
|
|
335
|
+
}
|
|
389
336
|
},
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
const
|
|
395
|
-
if (!
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
};
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
return {
|
|
413
|
-
ok: false,
|
|
414
|
-
error: new Error(`[cored] invalid send target: ${to}`)
|
|
415
|
-
};
|
|
337
|
+
setup: {
|
|
338
|
+
applyAccountConfig: ({ cfg, accountId, input }) => {
|
|
339
|
+
const updated = structuredClone(cfg);
|
|
340
|
+
if (!updated.channels) updated.channels = {};
|
|
341
|
+
const ch = updated.channels;
|
|
342
|
+
if (!ch["cored"]) ch["cored"] = {};
|
|
343
|
+
const section = ch["cored"];
|
|
344
|
+
const appId = input.appToken;
|
|
345
|
+
const appSecret = input.token;
|
|
346
|
+
const backendUrl = input.url;
|
|
347
|
+
if (accountId && accountId !== "default") {
|
|
348
|
+
if (!section.accounts) section.accounts = {};
|
|
349
|
+
const accounts = section.accounts;
|
|
350
|
+
if (!accounts[accountId]) accounts[accountId] = {};
|
|
351
|
+
const account = accounts[accountId];
|
|
352
|
+
if (appId) account.appId = appId;
|
|
353
|
+
if (appSecret) account.appSecret = appSecret;
|
|
354
|
+
if (backendUrl) account.backendUrl = backendUrl;
|
|
355
|
+
} else {
|
|
356
|
+
if (appId) section.appId = appId;
|
|
357
|
+
if (appSecret) section.appSecret = appSecret;
|
|
358
|
+
if (backendUrl) section.backendUrl = backendUrl;
|
|
416
359
|
}
|
|
417
|
-
return
|
|
360
|
+
return updated;
|
|
418
361
|
}
|
|
419
362
|
},
|
|
420
|
-
// Setup wizard for openclaw onboard
|
|
421
363
|
setupWizard: {
|
|
422
364
|
channel: "cored",
|
|
423
365
|
status: {
|
|
424
366
|
configuredLabel: "Connected",
|
|
425
367
|
unconfiguredLabel: "Not configured",
|
|
426
368
|
resolveConfigured: ({ cfg }) => {
|
|
427
|
-
const
|
|
428
|
-
return
|
|
369
|
+
const ids = listAccountIds(cfg);
|
|
370
|
+
return ids.some((id) => {
|
|
371
|
+
const resolved = resolveAccountConfig(cfg, id);
|
|
372
|
+
return Boolean(resolved.appId && resolved.appSecret && resolved.backendUrl);
|
|
373
|
+
});
|
|
429
374
|
}
|
|
430
375
|
},
|
|
431
376
|
credentials: [
|
|
432
377
|
{
|
|
433
|
-
inputKey: "
|
|
378
|
+
inputKey: "appToken",
|
|
434
379
|
providerHint: "cored",
|
|
435
380
|
credentialLabel: "App ID",
|
|
436
381
|
preferredEnvVar: "CORED_APP_ID",
|
|
437
382
|
envPrompt: "Use CORED_APP_ID from environment?",
|
|
438
383
|
keepPrompt: "Keep current App ID?",
|
|
439
384
|
inputPrompt: "Enter your Cored App ID:",
|
|
440
|
-
inspect: ({ cfg }) => {
|
|
441
|
-
const
|
|
385
|
+
inspect: ({ cfg, accountId }) => {
|
|
386
|
+
const resolved = resolveAccountConfig(cfg, accountId ?? void 0);
|
|
442
387
|
return {
|
|
443
|
-
accountConfigured: Boolean(
|
|
444
|
-
hasConfiguredValue: Boolean(
|
|
388
|
+
accountConfigured: Boolean(resolved.appId),
|
|
389
|
+
hasConfiguredValue: Boolean(resolved.appId)
|
|
445
390
|
};
|
|
446
391
|
}
|
|
447
392
|
},
|
|
448
393
|
{
|
|
449
|
-
inputKey: "
|
|
394
|
+
inputKey: "token",
|
|
450
395
|
providerHint: "cored",
|
|
451
396
|
credentialLabel: "App Secret",
|
|
452
397
|
preferredEnvVar: "CORED_APP_SECRET",
|
|
453
398
|
envPrompt: "Use CORED_APP_SECRET from environment?",
|
|
454
399
|
keepPrompt: "Keep current App Secret?",
|
|
455
400
|
inputPrompt: "Enter your Cored App Secret:",
|
|
456
|
-
inspect: ({ cfg }) => {
|
|
457
|
-
const
|
|
401
|
+
inspect: ({ cfg, accountId }) => {
|
|
402
|
+
const resolved = resolveAccountConfig(cfg, accountId ?? void 0);
|
|
458
403
|
return {
|
|
459
|
-
accountConfigured: Boolean(
|
|
460
|
-
hasConfiguredValue: Boolean(
|
|
404
|
+
accountConfigured: Boolean(resolved.appSecret),
|
|
405
|
+
hasConfiguredValue: Boolean(resolved.appSecret)
|
|
461
406
|
};
|
|
462
407
|
}
|
|
463
408
|
},
|
|
464
409
|
{
|
|
465
|
-
inputKey: "
|
|
410
|
+
inputKey: "url",
|
|
466
411
|
providerHint: "cored",
|
|
467
412
|
credentialLabel: "Backend URL",
|
|
468
413
|
preferredEnvVar: "CORED_BACKEND_URL",
|
|
469
414
|
envPrompt: "Use CORED_BACKEND_URL from environment?",
|
|
470
415
|
keepPrompt: "Keep current Backend URL?",
|
|
471
416
|
inputPrompt: "Enter your Cored backend server URL:",
|
|
472
|
-
inspect: ({ cfg }) => {
|
|
473
|
-
const
|
|
417
|
+
inspect: ({ cfg, accountId }) => {
|
|
418
|
+
const resolved = resolveAccountConfig(cfg, accountId ?? void 0);
|
|
474
419
|
return {
|
|
475
|
-
accountConfigured: Boolean(
|
|
476
|
-
hasConfiguredValue: Boolean(
|
|
420
|
+
accountConfigured: Boolean(resolved.backendUrl),
|
|
421
|
+
hasConfiguredValue: Boolean(resolved.backendUrl)
|
|
477
422
|
};
|
|
478
423
|
}
|
|
479
424
|
}
|
|
480
425
|
]
|
|
481
426
|
}
|
|
482
427
|
});
|
|
428
|
+
var coredPlugin = createChatChannelPlugin({
|
|
429
|
+
base,
|
|
430
|
+
// DM security: who can message the bot
|
|
431
|
+
security: {
|
|
432
|
+
dm: {
|
|
433
|
+
channelKey: "cored",
|
|
434
|
+
resolvePolicy: () => void 0,
|
|
435
|
+
resolveAllowFrom: () => [],
|
|
436
|
+
defaultPolicy: "allowlist"
|
|
437
|
+
}
|
|
438
|
+
},
|
|
439
|
+
// Threading: how replies are delivered
|
|
440
|
+
threading: { topLevelReplyToMode: "reply" },
|
|
441
|
+
// Outbound: send messages to the platform
|
|
442
|
+
outbound: {
|
|
443
|
+
attachedResults: {
|
|
444
|
+
channel: "cored",
|
|
445
|
+
sendText: async (ctx) => {
|
|
446
|
+
const target = parseTarget(ctx.to);
|
|
447
|
+
if (!target) {
|
|
448
|
+
throw new Error(`[cored] invalid send target: ${ctx.to}`);
|
|
449
|
+
}
|
|
450
|
+
const result = await sendText(
|
|
451
|
+
target.id,
|
|
452
|
+
ctx.text,
|
|
453
|
+
ctx.accountId ?? void 0,
|
|
454
|
+
ctx.replyToId ?? void 0
|
|
455
|
+
);
|
|
456
|
+
if (!result.ok) {
|
|
457
|
+
throw result.error ?? new Error("[cored] send failed");
|
|
458
|
+
}
|
|
459
|
+
return { messageId: result.messageId ?? "" };
|
|
460
|
+
}
|
|
461
|
+
},
|
|
462
|
+
base: {
|
|
463
|
+
deliveryMode: "direct",
|
|
464
|
+
resolveTarget: ({ to }) => {
|
|
465
|
+
if (!to) return { ok: false, error: new Error("[cored] --to is required") };
|
|
466
|
+
const target = parseTarget(to);
|
|
467
|
+
if (!target) {
|
|
468
|
+
return {
|
|
469
|
+
ok: false,
|
|
470
|
+
error: new Error(
|
|
471
|
+
`Cored requires --to <user:ID|chat:ID>, got: ${JSON.stringify(to)}`
|
|
472
|
+
)
|
|
473
|
+
};
|
|
474
|
+
}
|
|
475
|
+
return { ok: true, to: `${target.kind}:${target.id}` };
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
});
|
|
483
480
|
|
|
484
481
|
// src/messaging/inbound.ts
|
|
485
482
|
function parseMessageEvent(event) {
|
|
@@ -528,23 +525,8 @@ function extractTextBody(msg) {
|
|
|
528
525
|
return null;
|
|
529
526
|
}
|
|
530
527
|
function checkMessageGate(msg, account) {
|
|
531
|
-
if (account.botUserId && msg.senderId === account.botUserId) {
|
|
532
|
-
return { pass: false, reason: "self-message" };
|
|
533
|
-
}
|
|
534
|
-
if (account.inboundWhitelist.length > 0) {
|
|
535
|
-
if (!account.inboundWhitelist.includes(msg.senderId)) {
|
|
536
|
-
return { pass: false, reason: "sender-not-in-whitelist" };
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
if (msg.chatType === "group" && account.requireMention && !isBotMentioned(msg, account)) {
|
|
540
|
-
return { pass: false, reason: "group-no-mention" };
|
|
541
|
-
}
|
|
542
528
|
return { pass: true };
|
|
543
529
|
}
|
|
544
|
-
function isBotMentioned(msg, account) {
|
|
545
|
-
if (!account.botUserId) return false;
|
|
546
|
-
return msg.mentionUserIds.includes(account.botUserId);
|
|
547
|
-
}
|
|
548
530
|
var DEDUP_TTL_MS = 5 * 60 * 1e3;
|
|
549
531
|
var DEDUP_CLEANUP_INTERVAL_MS = 60 * 1e3;
|
|
550
532
|
var DEDUP_MAX_SIZE = 1e4;
|
|
@@ -579,7 +561,7 @@ function buildContext(msg, account) {
|
|
|
579
561
|
return {
|
|
580
562
|
Body: msg.body,
|
|
581
563
|
From: isGroup ? `cored:chat:${msg.chatId}` : `cored:user:${msg.senderId}`,
|
|
582
|
-
To: `cored:bot:${account.
|
|
564
|
+
To: `cored:bot:${account.appId}`,
|
|
583
565
|
SessionKey: sessionKey,
|
|
584
566
|
AccountId: account.accountId,
|
|
585
567
|
ChatType: isGroup ? "group" : "direct",
|
|
@@ -695,43 +677,42 @@ var index_default = defineChannelPluginEntry({
|
|
|
695
677
|
description: "Connect OpenClaw with Cored",
|
|
696
678
|
plugin: coredPlugin,
|
|
697
679
|
registerFull(api) {
|
|
698
|
-
|
|
699
|
-
typedApi.registerService({
|
|
680
|
+
api.registerService({
|
|
700
681
|
id: "cored-sdk",
|
|
701
682
|
start: async () => {
|
|
702
683
|
if (clientCount() > 0) return;
|
|
703
|
-
const accounts = listEnabledAccountConfigs(
|
|
684
|
+
const accounts = listEnabledAccountConfigs(api.config);
|
|
704
685
|
if (accounts.length === 0) {
|
|
705
|
-
|
|
686
|
+
api.logger?.warn?.("[cored] no enabled account config found \u2014 service idle");
|
|
706
687
|
return;
|
|
707
688
|
}
|
|
708
689
|
for (const account of accounts) {
|
|
709
690
|
const errors = validateAccountConfig(account);
|
|
710
691
|
if (errors.length > 0) {
|
|
711
|
-
|
|
692
|
+
api.logger?.warn?.(
|
|
712
693
|
`[cored] skipping account=${account.accountId}: ${errors.map((e) => e.message).join("; ")}`
|
|
713
694
|
);
|
|
714
695
|
continue;
|
|
715
696
|
}
|
|
716
697
|
try {
|
|
717
|
-
await startAccount(
|
|
718
|
-
|
|
698
|
+
await startAccount(api, account);
|
|
699
|
+
api.logger?.info?.(
|
|
719
700
|
`[cored] account=${account.accountId} connected (appId=${account.appId})`
|
|
720
701
|
);
|
|
721
702
|
} catch (err) {
|
|
722
|
-
|
|
703
|
+
api.logger?.error?.(
|
|
723
704
|
`[cored] account=${account.accountId} failed to start: ${err instanceof Error ? err.message : String(err)}`
|
|
724
705
|
);
|
|
725
706
|
}
|
|
726
707
|
}
|
|
727
|
-
|
|
708
|
+
api.logger?.info?.(`[cored] service started with ${clientCount()} account(s)`);
|
|
728
709
|
},
|
|
729
710
|
stop: async () => {
|
|
730
711
|
await destroyAllClients();
|
|
731
|
-
|
|
712
|
+
api.logger?.info?.("[cored] service stopped \u2014 all clients disconnected");
|
|
732
713
|
}
|
|
733
714
|
});
|
|
734
|
-
|
|
715
|
+
api.logger?.info?.("[cored] plugin registered");
|
|
735
716
|
}
|
|
736
717
|
});
|
|
737
718
|
async function startAccount(api, account) {
|