@cored-im/openclaw-plugin 0.1.5 → 0.1.10

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 CHANGED
@@ -315,171 +315,177 @@ function parseTarget(to) {
315
315
  }
316
316
 
317
317
  // src/channel.ts
318
- function resolveAccount(cfg, accountId) {
319
- const section = cfg.channels?.["cored"];
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
318
+ var base = createChannelPluginBase({
319
+ id: "cored",
373
320
  meta: {
374
321
  id: "cored",
375
322
  label: "Cored",
376
323
  selectionLabel: "Cored",
377
324
  docsPath: "/channels/cored",
378
325
  blurb: "Connect OpenClaw to Cored",
379
- aliases: ["cored", "co"]
326
+ aliases: ["co"]
380
327
  },
381
- // Capabilities
382
328
  capabilities: {
383
329
  chatTypes: ["direct", "group"]
384
330
  },
385
- // Config
386
331
  config: {
387
332
  listAccountIds: (cfg) => listAccountIds(cfg),
388
- resolveAccount: (cfg, accountId) => resolveAccountConfig(cfg, accountId)
333
+ resolveAccount: (cfg, accountId) => resolveAccountConfig(cfg, accountId ?? void 0),
334
+ inspectAccount(cfg, accountId) {
335
+ const resolved = resolveAccountConfig(cfg, accountId ?? void 0);
336
+ const hasConfig = Boolean(
337
+ resolved.appId && resolved.appSecret && resolved.backendUrl
338
+ );
339
+ return {
340
+ enabled: resolved.enabled,
341
+ configured: hasConfig,
342
+ tokenStatus: hasConfig ? "available" : "missing"
343
+ };
344
+ }
389
345
  },
390
- // Outbound messaging
391
- outbound: {
392
- deliveryMode: "direct",
393
- resolveTarget: ({ to }) => {
394
- const target = parseTarget(to);
395
- if (!target) {
396
- return {
397
- ok: false,
398
- error: new Error(
399
- `Cored requires --to <user:ID|chat:ID>, got: ${JSON.stringify(to)}`
400
- )
401
- };
346
+ setup: {
347
+ applyAccountConfig: ({ cfg, accountId, input }) => {
348
+ const updated = structuredClone(cfg);
349
+ if (!updated.channels) updated.channels = {};
350
+ const ch = updated.channels;
351
+ if (!ch["cored"]) ch["cored"] = {};
352
+ const section = ch["cored"];
353
+ const appId = input.appToken;
354
+ const appSecret = input.token;
355
+ const backendUrl = input.url;
356
+ if (accountId && accountId !== "default") {
357
+ if (!section.accounts) section.accounts = {};
358
+ const accounts = section.accounts;
359
+ if (!accounts[accountId]) accounts[accountId] = {};
360
+ const account = accounts[accountId];
361
+ if (appId) account.appId = appId;
362
+ if (appSecret) account.appSecret = appSecret;
363
+ if (backendUrl) account.backendUrl = backendUrl;
364
+ } else {
365
+ if (appId) section.appId = appId;
366
+ if (appSecret) section.appSecret = appSecret;
367
+ if (backendUrl) section.backendUrl = backendUrl;
402
368
  }
403
- return { ok: true, to: `${target.kind}:${target.id}` };
404
- },
405
- sendText: async ({
406
- to,
407
- text,
408
- accountId
409
- }) => {
410
- const target = parseTarget(to);
411
- if (!target) {
412
- return {
413
- ok: false,
414
- error: new Error(`[cored] invalid send target: ${to}`)
415
- };
416
- }
417
- return sendText(target.id, text, accountId);
369
+ return updated;
418
370
  }
419
371
  },
420
- // Setup wizard for openclaw onboard
421
372
  setupWizard: {
422
373
  channel: "cored",
423
374
  status: {
424
375
  configuredLabel: "Connected",
425
376
  unconfiguredLabel: "Not configured",
426
377
  resolveConfigured: ({ cfg }) => {
427
- const section = cfg.channels?.["cored"];
428
- return Boolean(section?.appId && section?.appSecret && section?.backendUrl);
378
+ const ids = listAccountIds(cfg);
379
+ return ids.some((id) => {
380
+ const resolved = resolveAccountConfig(cfg, id);
381
+ return Boolean(resolved.appId && resolved.appSecret && resolved.backendUrl);
382
+ });
429
383
  }
430
384
  },
431
385
  credentials: [
432
386
  {
433
- inputKey: "appId",
387
+ inputKey: "appToken",
434
388
  providerHint: "cored",
435
389
  credentialLabel: "App ID",
436
390
  preferredEnvVar: "CORED_APP_ID",
437
391
  envPrompt: "Use CORED_APP_ID from environment?",
438
392
  keepPrompt: "Keep current App ID?",
439
393
  inputPrompt: "Enter your Cored App ID:",
440
- inspect: ({ cfg }) => {
441
- const section = cfg.channels?.["cored"];
394
+ inspect: ({ cfg, accountId }) => {
395
+ const resolved = resolveAccountConfig(cfg, accountId ?? void 0);
442
396
  return {
443
- accountConfigured: Boolean(section?.appId),
444
- hasConfiguredValue: Boolean(section?.appId)
397
+ accountConfigured: Boolean(resolved.appId),
398
+ hasConfiguredValue: Boolean(resolved.appId)
445
399
  };
446
400
  }
447
401
  },
448
402
  {
449
- inputKey: "appSecret",
403
+ inputKey: "token",
450
404
  providerHint: "cored",
451
405
  credentialLabel: "App Secret",
452
406
  preferredEnvVar: "CORED_APP_SECRET",
453
407
  envPrompt: "Use CORED_APP_SECRET from environment?",
454
408
  keepPrompt: "Keep current App Secret?",
455
409
  inputPrompt: "Enter your Cored App Secret:",
456
- inspect: ({ cfg }) => {
457
- const section = cfg.channels?.["cored"];
410
+ inspect: ({ cfg, accountId }) => {
411
+ const resolved = resolveAccountConfig(cfg, accountId ?? void 0);
458
412
  return {
459
- accountConfigured: Boolean(section?.appSecret),
460
- hasConfiguredValue: Boolean(section?.appSecret)
413
+ accountConfigured: Boolean(resolved.appSecret),
414
+ hasConfiguredValue: Boolean(resolved.appSecret)
461
415
  };
462
416
  }
463
417
  },
464
418
  {
465
- inputKey: "backendUrl",
419
+ inputKey: "url",
466
420
  providerHint: "cored",
467
421
  credentialLabel: "Backend URL",
468
422
  preferredEnvVar: "CORED_BACKEND_URL",
469
423
  envPrompt: "Use CORED_BACKEND_URL from environment?",
470
424
  keepPrompt: "Keep current Backend URL?",
471
425
  inputPrompt: "Enter your Cored backend server URL:",
472
- inspect: ({ cfg }) => {
473
- const section = cfg.channels?.["cored"];
426
+ inspect: ({ cfg, accountId }) => {
427
+ const resolved = resolveAccountConfig(cfg, accountId ?? void 0);
474
428
  return {
475
- accountConfigured: Boolean(section?.backendUrl),
476
- hasConfiguredValue: Boolean(section?.backendUrl)
429
+ accountConfigured: Boolean(resolved.backendUrl),
430
+ hasConfiguredValue: Boolean(resolved.backendUrl)
477
431
  };
478
432
  }
479
433
  }
480
434
  ]
481
435
  }
482
436
  });
437
+ var coredPlugin = createChatChannelPlugin({
438
+ base,
439
+ // DM security: who can message the bot
440
+ security: {
441
+ dm: {
442
+ channelKey: "cored",
443
+ resolvePolicy: () => void 0,
444
+ resolveAllowFrom: () => [],
445
+ defaultPolicy: "allowlist"
446
+ }
447
+ },
448
+ // Threading: how replies are delivered
449
+ threading: { topLevelReplyToMode: "reply" },
450
+ // Outbound: send messages to the platform
451
+ outbound: {
452
+ attachedResults: {
453
+ channel: "cored",
454
+ sendText: async (ctx) => {
455
+ const target = parseTarget(ctx.to);
456
+ if (!target) {
457
+ throw new Error(`[cored] invalid send target: ${ctx.to}`);
458
+ }
459
+ const result = await sendText(
460
+ target.id,
461
+ ctx.text,
462
+ ctx.accountId ?? void 0,
463
+ ctx.replyToId ?? void 0
464
+ );
465
+ if (!result.ok) {
466
+ throw result.error ?? new Error("[cored] send failed");
467
+ }
468
+ return { messageId: result.messageId ?? "" };
469
+ }
470
+ },
471
+ base: {
472
+ deliveryMode: "direct",
473
+ resolveTarget: ({ to }) => {
474
+ if (!to) return { ok: false, error: new Error("[cored] --to is required") };
475
+ const target = parseTarget(to);
476
+ if (!target) {
477
+ return {
478
+ ok: false,
479
+ error: new Error(
480
+ `Cored requires --to <user:ID|chat:ID>, got: ${JSON.stringify(to)}`
481
+ )
482
+ };
483
+ }
484
+ return { ok: true, to: `${target.kind}:${target.id}` };
485
+ }
486
+ }
487
+ }
488
+ });
483
489
 
484
490
  // src/messaging/inbound.ts
485
491
  function parseMessageEvent(event) {
@@ -695,43 +701,42 @@ var index_default = defineChannelPluginEntry({
695
701
  description: "Connect OpenClaw with Cored",
696
702
  plugin: coredPlugin,
697
703
  registerFull(api) {
698
- const typedApi = api;
699
- typedApi.registerService({
704
+ api.registerService({
700
705
  id: "cored-sdk",
701
706
  start: async () => {
702
707
  if (clientCount() > 0) return;
703
- const accounts = listEnabledAccountConfigs(typedApi.config);
708
+ const accounts = listEnabledAccountConfigs(api.config);
704
709
  if (accounts.length === 0) {
705
- typedApi.logger?.warn?.("[cored] no enabled account config found \u2014 service idle");
710
+ api.logger?.warn?.("[cored] no enabled account config found \u2014 service idle");
706
711
  return;
707
712
  }
708
713
  for (const account of accounts) {
709
714
  const errors = validateAccountConfig(account);
710
715
  if (errors.length > 0) {
711
- typedApi.logger?.warn?.(
716
+ api.logger?.warn?.(
712
717
  `[cored] skipping account=${account.accountId}: ${errors.map((e) => e.message).join("; ")}`
713
718
  );
714
719
  continue;
715
720
  }
716
721
  try {
717
- await startAccount(typedApi, account);
718
- typedApi.logger?.info?.(
722
+ await startAccount(api, account);
723
+ api.logger?.info?.(
719
724
  `[cored] account=${account.accountId} connected (appId=${account.appId})`
720
725
  );
721
726
  } catch (err) {
722
- typedApi.logger?.error?.(
727
+ api.logger?.error?.(
723
728
  `[cored] account=${account.accountId} failed to start: ${err instanceof Error ? err.message : String(err)}`
724
729
  );
725
730
  }
726
731
  }
727
- typedApi.logger?.info?.(`[cored] service started with ${clientCount()} account(s)`);
732
+ api.logger?.info?.(`[cored] service started with ${clientCount()} account(s)`);
728
733
  },
729
734
  stop: async () => {
730
735
  await destroyAllClients();
731
- typedApi.logger?.info?.("[cored] service stopped \u2014 all clients disconnected");
736
+ api.logger?.info?.("[cored] service stopped \u2014 all clients disconnected");
732
737
  }
733
738
  });
734
- typedApi.logger?.info?.("[cored] plugin registered");
739
+ api.logger?.info?.("[cored] plugin registered");
735
740
  }
736
741
  });
737
742
  async function startAccount(api, account) {