@openclaw-china/qqbot 2026.3.29 → 2026.4.23

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
@@ -4214,6 +4214,10 @@ var coerce = {
4214
4214
  var NEVER = INVALID;
4215
4215
 
4216
4216
  // src/config.ts
4217
+ var QQBOT_CHANNEL_ID = "qqbot";
4218
+ var QQBOT_CONFIG_CHANNEL_ID = "qqbot-china";
4219
+ var QQBOT_CONFIG_PREFIX = `channels.${QQBOT_CONFIG_CHANNEL_ID}`;
4220
+ var QQBOT_CONFIG_PREFIXES = [QQBOT_CONFIG_PREFIX];
4217
4221
  function toTrimmedString(value) {
4218
4222
  if (value === void 0 || value === null) return void 0;
4219
4223
  const next = String(value).trim();
@@ -4325,9 +4329,42 @@ function resolveQQBotStreaming(config) {
4325
4329
  function resolveInboundMediaTempDir() {
4326
4330
  return DEFAULT_INBOUND_MEDIA_TEMP_DIR;
4327
4331
  }
4332
+ function asQQBotConfig(value) {
4333
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
4334
+ return void 0;
4335
+ }
4336
+ return value;
4337
+ }
4338
+ function resolveQQBotChannelConfig(cfg) {
4339
+ return asQQBotConfig(cfg?.channels?.[QQBOT_CONFIG_CHANNEL_ID]);
4340
+ }
4341
+ function withQQBotChannelConfig(cfg, qqbotConfig) {
4342
+ const nextChannels = { ...cfg.channels ?? {} };
4343
+ if (qqbotConfig) {
4344
+ nextChannels[QQBOT_CONFIG_CHANNEL_ID] = qqbotConfig;
4345
+ } else {
4346
+ delete nextChannels[QQBOT_CONFIG_CHANNEL_ID];
4347
+ }
4348
+ if (Object.keys(nextChannels).length === 0) {
4349
+ const next = { ...cfg };
4350
+ delete next.channels;
4351
+ return next;
4352
+ }
4353
+ return {
4354
+ ...cfg,
4355
+ channels: nextChannels
4356
+ };
4357
+ }
4358
+ function stripQQBotChannelPrefix(value) {
4359
+ let next = value.trim();
4360
+ if (next.slice(0, QQBOT_CHANNEL_ID.length + 1).toLowerCase() === `${QQBOT_CHANNEL_ID}:`) {
4361
+ next = next.slice(QQBOT_CHANNEL_ID.length + 1).trim();
4362
+ }
4363
+ return next;
4364
+ }
4328
4365
  var DEFAULT_ACCOUNT_ID = "default";
4329
4366
  function listConfiguredAccountIds(cfg) {
4330
- const accounts = cfg.channels?.qqbot?.accounts;
4367
+ const accounts = resolveQQBotChannelConfig(cfg)?.accounts;
4331
4368
  if (!accounts || typeof accounts !== "object") return [];
4332
4369
  return Object.keys(accounts).filter(Boolean);
4333
4370
  }
@@ -4337,19 +4374,19 @@ function listQQBotAccountIds(cfg) {
4337
4374
  return ids.sort((a, b) => a.localeCompare(b));
4338
4375
  }
4339
4376
  function resolveDefaultQQBotAccountId(cfg) {
4340
- const qqbotConfig = cfg.channels?.qqbot;
4377
+ const qqbotConfig = resolveQQBotChannelConfig(cfg);
4341
4378
  if (qqbotConfig?.defaultAccount?.trim()) return qqbotConfig.defaultAccount.trim();
4342
4379
  const ids = listQQBotAccountIds(cfg);
4343
4380
  if (ids.includes(DEFAULT_ACCOUNT_ID)) return DEFAULT_ACCOUNT_ID;
4344
4381
  return ids[0] ?? DEFAULT_ACCOUNT_ID;
4345
4382
  }
4346
4383
  function resolveAccountConfig(cfg, accountId) {
4347
- const accounts = cfg.channels?.qqbot?.accounts;
4384
+ const accounts = resolveQQBotChannelConfig(cfg)?.accounts;
4348
4385
  if (!accounts || typeof accounts !== "object") return void 0;
4349
4386
  return accounts[accountId];
4350
4387
  }
4351
4388
  function mergeQQBotAccountConfig(cfg, accountId) {
4352
- const base = cfg.channels?.qqbot ?? {};
4389
+ const base = resolveQQBotChannelConfig(cfg) ?? {};
4353
4390
  const { accounts: _ignored, defaultAccount: _ignored2, ...baseConfig } = base;
4354
4391
  const account = resolveAccountConfig(cfg, accountId) ?? {};
4355
4392
  const mergedDisplayAliases = {
@@ -4387,41 +4424,35 @@ function isPromptCancelled(value) {
4387
4424
  return typeof value === "symbol";
4388
4425
  }
4389
4426
  function setQQBotCredentials(params) {
4390
- const existing = params.cfg.channels?.qqbot ?? {};
4427
+ const existing = resolveQQBotChannelConfig(params.cfg) ?? {};
4391
4428
  if (params.accountId === DEFAULT_ACCOUNT_ID) {
4392
- return {
4393
- ...params.cfg,
4394
- channels: {
4395
- ...params.cfg.channels,
4396
- qqbot: {
4397
- ...existing,
4398
- enabled: true,
4399
- appId: params.appId,
4400
- clientSecret: params.clientSecret
4401
- }
4429
+ return withQQBotChannelConfig(
4430
+ params.cfg,
4431
+ {
4432
+ ...existing,
4433
+ enabled: true,
4434
+ appId: params.appId,
4435
+ clientSecret: params.clientSecret
4402
4436
  }
4403
- };
4437
+ );
4404
4438
  }
4405
4439
  const accounts = existing.accounts ?? {};
4406
- return {
4407
- ...params.cfg,
4408
- channels: {
4409
- ...params.cfg.channels,
4410
- qqbot: {
4411
- ...existing,
4412
- enabled: true,
4413
- accounts: {
4414
- ...accounts,
4415
- [params.accountId]: {
4416
- ...accounts[params.accountId],
4417
- enabled: true,
4418
- appId: params.appId,
4419
- clientSecret: params.clientSecret
4420
- }
4440
+ return withQQBotChannelConfig(
4441
+ params.cfg,
4442
+ {
4443
+ ...existing,
4444
+ enabled: true,
4445
+ accounts: {
4446
+ ...accounts,
4447
+ [params.accountId]: {
4448
+ ...accounts[params.accountId],
4449
+ enabled: true,
4450
+ appId: params.appId,
4451
+ clientSecret: params.clientSecret
4421
4452
  }
4422
4453
  }
4423
4454
  }
4424
- };
4455
+ );
4425
4456
  }
4426
4457
  async function noteQQBotCredentialHelp(prompter) {
4427
4458
  await prompter.note(
@@ -4431,13 +4462,13 @@ async function noteQQBotCredentialHelp(prompter) {
4431
4462
  "3) \u5728\u5F00\u53D1\u8BBE\u7F6E\u4E2D\u914D\u7F6E\u6C99\u7BB1\u6210\u5458\u6216\u6D4B\u8BD5\u7FA4",
4432
4463
  "4) \u914D\u7F6E\u5B8C\u6210\u540E\u53EF\u4F7F\u7528 openclaw gateway \u542F\u52A8\u8FDE\u63A5",
4433
4464
  "",
4434
- '\u547D\u4EE4\u884C\u4E5F\u652F\u6301\uFF1Aopenclaw channels add --channel qqbot --token "AppID:ClientSecret"'
4465
+ `\u547D\u4EE4\u884C\u4E5F\u652F\u6301\uFF1Aopenclaw channels add --channel ${QQBOT_CHANNEL_ID} --token "AppID:ClientSecret"`
4435
4466
  ].join("\n"),
4436
4467
  "QQ Bot \u914D\u7F6E"
4437
4468
  );
4438
4469
  }
4439
4470
  function resolveOnboardingAccountId(params) {
4440
- const override = params.accountOverrides?.qqbot?.trim();
4471
+ const override = params.accountOverrides?.[QQBOT_CONFIG_CHANNEL_ID]?.trim();
4441
4472
  if (override) return override;
4442
4473
  const defaultAccountId = resolveDefaultQQBotAccountId(params.cfg);
4443
4474
  const accountIds = listQQBotAccountIds(params.cfg);
@@ -4454,7 +4485,7 @@ function resolveOnboardingAccountId(params) {
4454
4485
  }).then((selected) => isPromptCancelled(selected) ? defaultAccountId : selected);
4455
4486
  }
4456
4487
  var qqbotOnboardingAdapter = {
4457
- channel: "qqbot",
4488
+ channel: QQBOT_CHANNEL_ID,
4458
4489
  getStatus: async (params) => {
4459
4490
  const accountIds = listQQBotAccountIds(params.cfg);
4460
4491
  const configuredAccountId = accountIds.find(
@@ -4466,7 +4497,7 @@ var qqbotOnboardingAdapter = {
4466
4497
  configuredAccountId && configuredAccountId !== DEFAULT_ACCOUNT_ID ? `QQ Bot: \u5DF2\u914D\u7F6E (${configuredAccountId})` : `QQ Bot: \u5DF2\u914D\u7F6E${defaultAccountId !== DEFAULT_ACCOUNT_ID ? ` (default=${defaultAccountId})` : ""}`
4467
4498
  ] : ["QQ Bot: \u9700\u8981 AppID \u548C ClientSecret"];
4468
4499
  return {
4469
- channel: "qqbot",
4500
+ channel: QQBOT_CHANNEL_ID,
4470
4501
  configured,
4471
4502
  statusLines,
4472
4503
  selectionHint: configured ? "\u5DF2\u914D\u7F6E" : "\u9700\u8981 AppID \u548C ClientSecret",
@@ -4520,15 +4551,9 @@ var qqbotOnboardingAdapter = {
4520
4551
  }
4521
4552
  return { cfg: next, accountId };
4522
4553
  },
4523
- disable: (cfg) => ({
4524
- ...cfg,
4525
- channels: {
4526
- ...cfg.channels,
4527
- qqbot: {
4528
- ...cfg.channels?.qqbot ?? {},
4529
- enabled: false
4530
- }
4531
- }
4554
+ disable: (cfg) => withQQBotChannelConfig(cfg, {
4555
+ ...resolveQQBotChannelConfig(cfg) ?? {},
4556
+ enabled: false
4532
4557
  })
4533
4558
  };
4534
4559
 
@@ -6572,9 +6597,10 @@ var CONFIG_FILE_PATH = join(OPENCLAW_HOME, "openclaw.json");
6572
6597
  var ANSI_RESET = "\x1B[0m";
6573
6598
  var ANSI_LINK = "\x1B[1;4;96m";
6574
6599
  var ANSI_BORDER = "\x1B[92m";
6600
+ var QQBOT_CHANNEL_ID2 = "qqbot-china";
6575
6601
  var CHANNEL_ORDER = [
6576
6602
  "dingtalk",
6577
- "qqbot",
6603
+ QQBOT_CHANNEL_ID2,
6578
6604
  "wecom",
6579
6605
  "wecom-app",
6580
6606
  "wecom-kf",
@@ -6588,7 +6614,7 @@ var CHANNEL_DISPLAY_LABELS = {
6588
6614
  "wecom-app": "WeCom App\uFF08\u81EA\u5EFA\u5E94\u7528-\u53EF\u63A5\u5165\u5FAE\u4FE1\uFF09",
6589
6615
  "wecom-kf": "WeCom KF\uFF08\u5FAE\u4FE1\u5BA2\u670D\uFF09",
6590
6616
  "wechat-mp": "WeChat MP\uFF08\u5FAE\u4FE1\u516C\u4F17\u53F7\uFF09",
6591
- qqbot: "QQBot\uFF08QQ \u673A\u5668\u4EBA\uFF09"
6617
+ "qqbot-china": "QQBot\uFF08QQ \u673A\u5668\u4EBA\uFF09"
6592
6618
  };
6593
6619
  var CHANNEL_GUIDE_LINKS = {
6594
6620
  dingtalk: `${GUIDES_BASE}/dingtalk/configuration.md`,
@@ -6597,7 +6623,7 @@ var CHANNEL_GUIDE_LINKS = {
6597
6623
  "wecom-app": `${GUIDES_BASE}/wecom-app/configuration.md`,
6598
6624
  "wecom-kf": "https://github.com/BytePioneer-AI/openclaw-china/blob/main/extensions/wecom-kf/README.md",
6599
6625
  "wechat-mp": `${GUIDES_BASE}/wechat-mp/configuration.md`,
6600
- qqbot: `${GUIDES_BASE}/qqbot/configuration.md`
6626
+ "qqbot-china": `${GUIDES_BASE}/qqbot/configuration.md`
6601
6627
  };
6602
6628
  var CHINA_CLI_STATE_KEY = /* @__PURE__ */ Symbol.for("@openclaw-china/china-cli-state");
6603
6629
  var PromptCancelledError = class extends Error {
@@ -6799,7 +6825,7 @@ function isChannelConfigured(cfg, channelId) {
6799
6825
  return hasNonEmptyString(channelCfg.clientId) && hasNonEmptyString(channelCfg.clientSecret);
6800
6826
  case "feishu-china":
6801
6827
  return hasNonEmptyString(channelCfg.appId) && hasNonEmptyString(channelCfg.appSecret);
6802
- case "qqbot":
6828
+ case "qqbot-china":
6803
6829
  return hasNonEmptyString(channelCfg.appId) && hasNonEmptyString(channelCfg.clientSecret);
6804
6830
  case "wecom":
6805
6831
  return hasWecomWsCredentialPair(channelCfg);
@@ -6820,11 +6846,12 @@ function withConfiguredSuffix(cfg, channelId) {
6820
6846
  function mergeChannelConfig(cfg, channelId, patch) {
6821
6847
  const channels = isRecord(cfg.channels) ? { ...cfg.channels } : {};
6822
6848
  const existing = getChannelConfig(cfg, channelId);
6823
- channels[channelId] = {
6849
+ const nextChannelConfig = {
6824
6850
  ...existing,
6825
6851
  ...patch,
6826
6852
  enabled: true
6827
6853
  };
6854
+ channels[channelId] = nextChannelConfig;
6828
6855
  return {
6829
6856
  ...cfg,
6830
6857
  channels
@@ -7201,8 +7228,8 @@ async function configureWechatMp(prompter, cfg) {
7201
7228
  }
7202
7229
  async function configureQQBot(prompter, cfg) {
7203
7230
  section("\u914D\u7F6E QQBot\uFF08QQ \u673A\u5668\u4EBA\uFF09");
7204
- showGuideLink("qqbot");
7205
- const existing = getChannelConfig(cfg, "qqbot");
7231
+ showGuideLink(QQBOT_CHANNEL_ID2);
7232
+ const existing = getChannelConfig(cfg, QQBOT_CHANNEL_ID2);
7206
7233
  const existingAsr = isRecord(existing.asr) ? existing.asr : {};
7207
7234
  const appId = await prompter.askText({
7208
7235
  label: "QQBot appId",
@@ -7239,7 +7266,7 @@ async function configureQQBot(prompter, cfg) {
7239
7266
  required: true
7240
7267
  });
7241
7268
  }
7242
- return mergeChannelConfig(cfg, "qqbot", {
7269
+ return mergeChannelConfig(cfg, QQBOT_CHANNEL_ID2, {
7243
7270
  appId,
7244
7271
  clientSecret,
7245
7272
  asr
@@ -7259,7 +7286,7 @@ async function configureSingleChannel(channel, prompter, cfg) {
7259
7286
  return configureWecomKf(prompter, cfg);
7260
7287
  case "wechat-mp":
7261
7288
  return configureWechatMp(prompter, cfg);
7262
- case "qqbot":
7289
+ case "qqbot-china":
7263
7290
  return configureQQBot(prompter, cfg);
7264
7291
  default:
7265
7292
  return cfg;
@@ -7401,7 +7428,7 @@ var SUPPORTED_CHANNELS = [
7401
7428
  "wecom-app",
7402
7429
  "wecom-kf",
7403
7430
  "wechat-mp",
7404
- "qqbot"
7431
+ "qqbot-china"
7405
7432
  ];
7406
7433
  var CHINA_INSTALL_HINT_SHOWN_KEY = /* @__PURE__ */ Symbol.for("@openclaw-china/china-install-hint-shown");
7407
7434
  function isRecord2(value) {
@@ -8254,12 +8281,8 @@ async function readMediaWithConfig(source, options) {
8254
8281
  }
8255
8282
 
8256
8283
  // src/outbound.ts
8257
- function stripPrefix(value, prefix) {
8258
- return value.slice(0, prefix.length).toLowerCase() === prefix ? value.slice(prefix.length) : value;
8259
- }
8260
8284
  function parseTarget(to) {
8261
- let raw = to.trim();
8262
- raw = stripPrefix(raw, "qqbot:");
8285
+ let raw = stripQQBotChannelPrefix(to);
8263
8286
  const normalizedRaw = raw.toLowerCase();
8264
8287
  if (normalizedRaw.startsWith("group:")) {
8265
8288
  return { kind: "group", id: raw.slice("group:".length) };
@@ -8426,7 +8449,7 @@ var qqbotOutbound = {
8426
8449
  const qqCfg = mergeQQBotAccountConfig(cfg, accountId ?? DEFAULT_ACCOUNT_ID);
8427
8450
  const credentials = resolveQQBotCredentials(qqCfg);
8428
8451
  if (!credentials) {
8429
- return { channel: "qqbot", error: "QQBot not configured (missing appId/clientSecret)" };
8452
+ return { channel: QQBOT_CHANNEL_ID, error: "QQBot not configured (missing appId/clientSecret)" };
8430
8453
  }
8431
8454
  const target = parseTarget(to);
8432
8455
  const accessToken = await getAccessToken(credentials.appId, credentials.clientSecret);
@@ -8450,7 +8473,7 @@ var qqbotOutbound = {
8450
8473
  content: text,
8451
8474
  markdown
8452
8475
  });
8453
- return { channel: "qqbot", messageId: result3.id, timestamp: result3.timestamp };
8476
+ return { channel: QQBOT_CHANNEL_ID, messageId: result3.id, timestamp: result3.timestamp };
8454
8477
  }
8455
8478
  let result2;
8456
8479
  try {
@@ -8517,7 +8540,7 @@ var qqbotOutbound = {
8517
8540
  throw retryErr;
8518
8541
  }
8519
8542
  }
8520
- return { channel: "qqbot", messageId: result2.id, timestamp: result2.timestamp };
8543
+ return { channel: QQBOT_CHANNEL_ID, messageId: result2.id, timestamp: result2.timestamp };
8521
8544
  }
8522
8545
  if (target.kind === "channel") {
8523
8546
  logQQBotOutboundDispatch({
@@ -8535,7 +8558,7 @@ var qqbotOutbound = {
8535
8558
  content: text,
8536
8559
  messageId: replyToId
8537
8560
  });
8538
- return { channel: "qqbot", messageId: result2.id, timestamp: result2.timestamp };
8561
+ return { channel: QQBOT_CHANNEL_ID, messageId: result2.id, timestamp: result2.timestamp };
8539
8562
  }
8540
8563
  if (!replyToId && !replyEventId) {
8541
8564
  logQQBotOutboundDispatch({
@@ -8556,7 +8579,7 @@ var qqbotOutbound = {
8556
8579
  const refIdx2 = resolveResponseRefIdx(result2);
8557
8580
  recordOutboundC2CRefIndex({ refIdx: refIdx2, accountId, text });
8558
8581
  return {
8559
- channel: "qqbot",
8582
+ channel: QQBOT_CHANNEL_ID,
8560
8583
  messageId: result2.id,
8561
8584
  timestamp: result2.timestamp,
8562
8585
  ...refIdx2 ? { refIdx: refIdx2 } : {}
@@ -8630,14 +8653,14 @@ var qqbotOutbound = {
8630
8653
  const refIdx = resolveResponseRefIdx(result);
8631
8654
  recordOutboundC2CRefIndex({ refIdx, accountId, text });
8632
8655
  return {
8633
- channel: "qqbot",
8656
+ channel: QQBOT_CHANNEL_ID,
8634
8657
  messageId: result.id,
8635
8658
  timestamp: result.timestamp,
8636
8659
  ...refIdx ? { refIdx } : {}
8637
8660
  };
8638
8661
  } catch (err) {
8639
8662
  const message = summarizeError(err);
8640
- return { channel: "qqbot", error: message };
8663
+ return { channel: QQBOT_CHANNEL_ID, error: message };
8641
8664
  }
8642
8665
  },
8643
8666
  sendMedia: async (params) => {
@@ -8645,13 +8668,13 @@ var qqbotOutbound = {
8645
8668
  if (!mediaUrl) {
8646
8669
  const fallbackText = text?.trim() ?? "";
8647
8670
  if (!fallbackText) {
8648
- return { channel: "qqbot", error: "mediaUrl is required for sendMedia" };
8671
+ return { channel: QQBOT_CHANNEL_ID, error: "mediaUrl is required for sendMedia" };
8649
8672
  }
8650
8673
  return qqbotOutbound.sendText({ cfg, to, text: fallbackText, replyToId, replyEventId, accountId });
8651
8674
  }
8652
8675
  const qqCfg = mergeQQBotAccountConfig(cfg, accountId ?? DEFAULT_ACCOUNT_ID);
8653
8676
  if (!resolveQQBotCredentials(qqCfg)) {
8654
- return { channel: "qqbot", error: "QQBot not configured (missing appId/clientSecret)" };
8677
+ return { channel: QQBOT_CHANNEL_ID, error: "QQBot not configured (missing appId/clientSecret)" };
8655
8678
  }
8656
8679
  const target = parseTarget(to);
8657
8680
  const trimmedText = text?.trim() ? text.trim() : void 0;
@@ -8738,7 +8761,7 @@ ${mediaUrl}` : mediaUrl;
8738
8761
  });
8739
8762
  if (textResult.error) {
8740
8763
  return {
8741
- channel: "qqbot",
8764
+ channel: QQBOT_CHANNEL_ID,
8742
8765
  error: `QQBot follow-up text send failed after media delivery: ${textResult.error}`
8743
8766
  };
8744
8767
  }
@@ -8753,14 +8776,14 @@ ${mediaUrl}` : mediaUrl;
8753
8776
  });
8754
8777
  }
8755
8778
  return {
8756
- channel: "qqbot",
8779
+ channel: QQBOT_CHANNEL_ID,
8757
8780
  messageId: result.id,
8758
8781
  timestamp: result.timestamp,
8759
8782
  ...refIdx ? { refIdx } : {}
8760
8783
  };
8761
8784
  } catch (err) {
8762
8785
  const message = summarizeError(err);
8763
- return { channel: "qqbot", error: message };
8786
+ return { channel: QQBOT_CHANNEL_ID, error: message };
8764
8787
  }
8765
8788
  },
8766
8789
  sendTyping: async (params) => {
@@ -8768,11 +8791,11 @@ ${mediaUrl}` : mediaUrl;
8768
8791
  const qqCfg = mergeQQBotAccountConfig(cfg, accountId ?? DEFAULT_ACCOUNT_ID);
8769
8792
  const credentials = resolveQQBotCredentials(qqCfg);
8770
8793
  if (!credentials) {
8771
- return { channel: "qqbot", error: "QQBot not configured (missing appId/clientSecret)" };
8794
+ return { channel: QQBOT_CHANNEL_ID, error: "QQBot not configured (missing appId/clientSecret)" };
8772
8795
  }
8773
8796
  const target = parseTarget(to);
8774
8797
  if (target.kind !== "c2c") {
8775
- return { channel: "qqbot" };
8798
+ return { channel: QQBOT_CHANNEL_ID };
8776
8799
  }
8777
8800
  try {
8778
8801
  const accessToken = await getAccessToken(credentials.appId, credentials.clientSecret);
@@ -8830,12 +8853,12 @@ ${mediaUrl}` : mediaUrl;
8830
8853
  }
8831
8854
  }
8832
8855
  return {
8833
- channel: "qqbot",
8856
+ channel: QQBOT_CHANNEL_ID,
8834
8857
  ...typingResult?.refIdx ? { refIdx: typingResult.refIdx } : {}
8835
8858
  };
8836
8859
  } catch (err) {
8837
8860
  const message = summarizeError(err);
8838
- return { channel: "qqbot", error: message };
8861
+ return { channel: QQBOT_CHANNEL_ID, error: message };
8839
8862
  }
8840
8863
  }
8841
8864
  };
@@ -9283,7 +9306,7 @@ function clearKnownQQBotTargets(params = {}) {
9283
9306
  async function sendProactiveQQBotMessage(params) {
9284
9307
  const to = params.to.trim();
9285
9308
  if (!to) {
9286
- return { channel: "qqbot", error: "to is required for proactive send" };
9309
+ return { channel: QQBOT_CHANNEL_ID, error: "to is required for proactive send" };
9287
9310
  }
9288
9311
  if (params.mediaUrl?.trim()) {
9289
9312
  return qqbotOutbound.sendMedia({
@@ -9296,7 +9319,7 @@ async function sendProactiveQQBotMessage(params) {
9296
9319
  }
9297
9320
  const text = params.text?.trim();
9298
9321
  if (!text) {
9299
- return { channel: "qqbot", error: "text or mediaUrl is required for proactive send" };
9322
+ return { channel: QQBOT_CHANNEL_ID, error: "text or mediaUrl is required for proactive send" };
9300
9323
  }
9301
9324
  return qqbotOutbound.sendText({
9302
9325
  cfg: params.cfg,
@@ -9620,6 +9643,17 @@ var QQBOT_ABORT_TRIGGERS = /* @__PURE__ */ new Set([
9620
9643
  "stop please"
9621
9644
  ]);
9622
9645
  var QQBOT_ABORT_TRAILING_PUNCTUATION_RE = /[.!?…,,。;;::'"’”)\]}]+$/u;
9646
+ var QQBOT_ROUTE_PREFIX_RE = new RegExp(
9647
+ `^(agent:[^:]+:${QQBOT_CHANNEL_ID}:)(?:direct|dm):.+$`,
9648
+ "i"
9649
+ );
9650
+ function buildQQBotScopedConfig(qqCfg) {
9651
+ return {
9652
+ channels: {
9653
+ [QQBOT_CONFIG_CHANNEL_ID]: qqCfg
9654
+ }
9655
+ };
9656
+ }
9623
9657
  function resolveQQBotRouteSessionKey(route) {
9624
9658
  const effectiveSessionKey = route.effectiveSessionKey?.trim();
9625
9659
  if (effectiveSessionKey) {
@@ -9734,9 +9768,9 @@ function buildQQBotDirectSessionKey(params) {
9734
9768
  const normalizedSenderId = normalizeQQBotSessionKeyPart(params.senderStableId);
9735
9769
  const trimmedRouteSessionKey = params.routeSessionKey.trim();
9736
9770
  if (!trimmedRouteSessionKey) {
9737
- return `agent:main:qqbot:dm:${normalizedAccountId}:${normalizedSenderId}`;
9771
+ return `agent:main:${QQBOT_CHANNEL_ID}:dm:${normalizedAccountId}:${normalizedSenderId}`;
9738
9772
  }
9739
- const qqAgentRouteMatch = trimmedRouteSessionKey.match(/^(agent:[^:]+:qqbot:)(?:direct|dm):.+$/i);
9773
+ const qqAgentRouteMatch = trimmedRouteSessionKey.match(QQBOT_ROUTE_PREFIX_RE);
9740
9774
  if (qqAgentRouteMatch?.[1]) {
9741
9775
  return `${qqAgentRouteMatch[1]}dm:${normalizedAccountId}:${normalizedSenderId}`;
9742
9776
  }
@@ -9750,9 +9784,7 @@ function normalizeQQBotReplyTarget(value) {
9750
9784
  if (!trimmed) {
9751
9785
  return void 0;
9752
9786
  }
9753
- if (/^qqbot:/i.test(trimmed)) {
9754
- trimmed = trimmed.slice("qqbot:".length).trim();
9755
- }
9787
+ trimmed = stripQQBotChannelPrefix(trimmed);
9756
9788
  if (/^c2c:/i.test(trimmed)) {
9757
9789
  const openid = trimmed.slice("c2c:".length).trim();
9758
9790
  return openid ? `user:${openid}` : void 0;
@@ -9861,7 +9893,7 @@ function normalizeQQBotDisplayAliasesMap(raw) {
9861
9893
  return aliases;
9862
9894
  }
9863
9895
  function resolveQQBotDisplayAliasMaps(cfg, accountId) {
9864
- const qqbot = cfg?.channels?.qqbot;
9896
+ const qqbot = resolveQQBotChannelConfig(cfg);
9865
9897
  return {
9866
9898
  globalAliases: normalizeQQBotDisplayAliasesMap(qqbot?.displayAliases),
9867
9899
  accountAliases: normalizeQQBotDisplayAliasesMap(qqbot?.accounts?.[accountId]?.displayAliases)
@@ -10705,8 +10737,7 @@ function evaluateReplyFinalOnlyDelivery(params) {
10705
10737
  return { skipDelivery: true, suppressText: false };
10706
10738
  }
10707
10739
  function isQQBotC2CTarget(to) {
10708
- const trimmed = to.trim();
10709
- const raw = trimmed.slice(0, "qqbot:".length).toLowerCase() === "qqbot:" ? trimmed.slice("qqbot:".length) : trimmed;
10740
+ const raw = stripQQBotChannelPrefix(to);
10710
10741
  const normalizedRaw = raw.toLowerCase();
10711
10742
  return !normalizedRaw.startsWith("group:") && !normalizedRaw.startsWith("channel:");
10712
10743
  }
@@ -11731,7 +11762,7 @@ async function sendQQBotMediaWithFallback(params) {
11731
11762
  return;
11732
11763
  }
11733
11764
  const result = await outbound.sendMedia({
11734
- cfg: { channels: { qqbot: qqCfg } },
11765
+ cfg: buildQQBotScopedConfig(qqCfg),
11735
11766
  to,
11736
11767
  mediaUrl,
11737
11768
  replyToId,
@@ -11749,7 +11780,7 @@ async function sendQQBotMediaWithFallback(params) {
11749
11780
  return;
11750
11781
  }
11751
11782
  const fallbackResult = await outbound.sendText({
11752
- cfg: { channels: { qqbot: qqCfg } },
11783
+ cfg: buildQQBotScopedConfig(qqCfg),
11753
11784
  to,
11754
11785
  text: fallback,
11755
11786
  replyToId,
@@ -11774,7 +11805,7 @@ function buildInboundContext(params) {
11774
11805
  const commandBody = params.commandBody ?? event.content;
11775
11806
  const chatType = event.type === "group" || event.type === "channel" ? "group" : "direct";
11776
11807
  const { to } = resolveChatTarget(event);
11777
- const from = event.type === "group" ? `qqbot:group:${event.groupOpenid ?? ""}` : event.type === "channel" ? `qqbot:channel:${event.channelId ?? ""}` : `qqbot:${event.senderId}`;
11808
+ const from = event.type === "group" ? `${QQBOT_CHANNEL_ID}:group:${event.groupOpenid ?? ""}` : event.type === "channel" ? `${QQBOT_CHANNEL_ID}:channel:${event.channelId ?? ""}` : `${QQBOT_CHANNEL_ID}:${event.senderId}`;
11778
11809
  return {
11779
11810
  Body: body,
11780
11811
  RawBody: rawBody,
@@ -11787,12 +11818,12 @@ function buildInboundContext(params) {
11787
11818
  GroupSubject: event.type === "group" ? event.groupOpenid : event.channelId,
11788
11819
  SenderName: event.senderName,
11789
11820
  SenderId: event.senderId,
11790
- Provider: "qqbot",
11821
+ Provider: QQBOT_CHANNEL_ID,
11791
11822
  MessageSid: event.messageId,
11792
11823
  Timestamp: event.timestamp,
11793
11824
  WasMentioned: event.mentionedBot,
11794
11825
  CommandAuthorized: true,
11795
- OriginatingChannel: "qqbot",
11826
+ OriginatingChannel: QQBOT_CHANNEL_ID,
11796
11827
  OriginatingTo: to
11797
11828
  };
11798
11829
  }
@@ -11815,7 +11846,7 @@ async function dispatchToAgent(params) {
11815
11846
  let typingRefIdx;
11816
11847
  if (inbound.c2cOpenid && !isFastAbortCommand && !shouldSuppressVisibleReplies()) {
11817
11848
  const typing = await qqbotOutbound.sendTyping({
11818
- cfg: { channels: { qqbot: qqCfg } },
11849
+ cfg: buildQQBotScopedConfig(qqCfg),
11819
11850
  to: `user:${inbound.c2cOpenid}`,
11820
11851
  replyToId: inbound.messageId,
11821
11852
  replyEventId: inbound.eventId,
@@ -11866,7 +11897,7 @@ async function dispatchToAgent(params) {
11866
11897
  renew: async () => {
11867
11898
  try {
11868
11899
  const typing = await qqbotOutbound.sendTyping({
11869
- cfg: { channels: { qqbot: qqCfg } },
11900
+ cfg: buildQQBotScopedConfig(qqCfg),
11870
11901
  to: `user:${inbound.c2cOpenid}`,
11871
11902
  replyToId: inbound.messageId,
11872
11903
  replyEventId: inbound.eventId,
@@ -11886,7 +11917,7 @@ async function dispatchToAgent(params) {
11886
11917
  if (groupMessageInterfaceBlocked || isFastAbortCommand || shouldSuppressVisibleReplies()) return;
11887
11918
  markVisibleOutboundStarted();
11888
11919
  const result = await qqbotOutbound.sendText({
11889
- cfg: { channels: { qqbot: qqCfg } },
11920
+ cfg: buildQQBotScopedConfig(qqCfg),
11890
11921
  to: target.to,
11891
11922
  text: LONG_TASK_NOTICE_TEXT,
11892
11923
  replyToId: inbound.messageId,
@@ -11923,7 +11954,7 @@ async function dispatchToAgent(params) {
11923
11954
  }
11924
11955
  markVisibleOutboundStarted();
11925
11956
  const fallback = await qqbotOutbound.sendText({
11926
- cfg: { channels: { qqbot: qqCfg } },
11957
+ cfg: buildQQBotScopedConfig(qqCfg),
11927
11958
  to: target.to,
11928
11959
  text: buildVoiceASRFallbackReply(resolvedAttachmentResult.asrErrorMessage),
11929
11960
  replyToId: inbound.messageId,
@@ -12037,7 +12068,7 @@ async function dispatchToAgent(params) {
12037
12068
  const isGroup = inbound.type === "group" || inbound.type === "channel";
12038
12069
  const updateLastRoute = !isGroup ? {
12039
12070
  sessionKey: mainSessionKey ?? route.sessionKey,
12040
- channel: "qqbot",
12071
+ channel: QQBOT_CHANNEL_ID,
12041
12072
  to: stableTo,
12042
12073
  accountId: outboundAccountId
12043
12074
  } : void 0;
@@ -12073,13 +12104,13 @@ async function dispatchToAgent(params) {
12073
12104
  const textApi = runtime2.channel?.text;
12074
12105
  const limit = textApi?.resolveTextChunkLimit?.({
12075
12106
  cfg,
12076
- channel: "qqbot",
12107
+ channel: QQBOT_CHANNEL_ID,
12077
12108
  defaultLimit: qqCfg.textChunkLimit ?? 1500
12078
12109
  }) ?? (qqCfg.textChunkLimit ?? 1500);
12079
- const chunkMode = textApi?.resolveChunkMode?.(cfg, "qqbot");
12110
+ const chunkMode = textApi?.resolveChunkMode?.(cfg, QQBOT_CHANNEL_ID);
12080
12111
  const tableMode = textApi?.resolveMarkdownTableMode?.({
12081
12112
  cfg,
12082
- channel: "qqbot",
12113
+ channel: QQBOT_CHANNEL_ID,
12083
12114
  accountId: outboundAccountId
12084
12115
  });
12085
12116
  const resolvedTableMode = tableMode ?? "bullets";
@@ -12213,7 +12244,7 @@ async function dispatchToAgent(params) {
12213
12244
  );
12214
12245
  markVisibleOutboundStarted();
12215
12246
  const result = await qqbotOutbound.sendText({
12216
- cfg: { channels: { qqbot: qqCfg } },
12247
+ cfg: buildQQBotScopedConfig(qqCfg),
12217
12248
  to: target.to,
12218
12249
  text: chunk,
12219
12250
  replyToId: textReplyRefs.replyToId,
@@ -12334,7 +12365,7 @@ async function dispatchToAgent(params) {
12334
12365
  }
12335
12366
  markVisibleOutboundStarted();
12336
12367
  const result = await qqbotOutbound.sendText({
12337
- cfg: { channels: { qqbot: qqCfg } },
12368
+ cfg: buildQQBotScopedConfig(qqCfg),
12338
12369
  to: target.to,
12339
12370
  text: chunk,
12340
12371
  replyToId: textReplyRefs.replyToId,
@@ -12471,7 +12502,7 @@ async function dispatchToAgent(params) {
12471
12502
  logger.info("no visible reply generated for group mention; sending fallback text");
12472
12503
  markVisibleOutboundStarted();
12473
12504
  const fallbackResult = await qqbotOutbound.sendText({
12474
- cfg: { channels: { qqbot: qqCfg } },
12505
+ cfg: buildQQBotScopedConfig(qqCfg),
12475
12506
  to: target.to,
12476
12507
  text: noReplyFallback,
12477
12508
  replyToId: inbound.messageId,
@@ -12599,7 +12630,7 @@ async function handleQQBotDispatch(params) {
12599
12630
  const target = resolveChatTarget(resolvedInbound);
12600
12631
  const route = routing({
12601
12632
  cfg: params.cfg,
12602
- channel: "qqbot",
12633
+ channel: QQBOT_CHANNEL_ID,
12603
12634
  accountId,
12604
12635
  peer: { kind: target.peerKind, id: target.peerId }
12605
12636
  });
@@ -12965,7 +12996,7 @@ function stopQQBotMonitorForAccount(accountId = DEFAULT_ACCOUNT_ID) {
12965
12996
 
12966
12997
  // src/channel.ts
12967
12998
  var meta = {
12968
- id: "qqbot",
12999
+ id: QQBOT_CHANNEL_ID,
12969
13000
  label: "QQ Bot",
12970
13001
  selectionLabel: "QQ Bot",
12971
13002
  docsPath: "/channels/qqbot",
@@ -12977,7 +13008,7 @@ var meta = {
12977
13008
  function resolveQQBotAccount(params) {
12978
13009
  const { cfg, accountId = DEFAULT_ACCOUNT_ID } = params;
12979
13010
  const merged = mergeQQBotAccountConfig(cfg, accountId);
12980
- const baseEnabled = cfg.channels?.qqbot?.enabled !== false;
13011
+ const baseEnabled = resolveQQBotChannelConfig(cfg)?.enabled !== false;
12981
13012
  const enabled = baseEnabled && merged.enabled !== false;
12982
13013
  const credentials = resolveQQBotCredentials(merged);
12983
13014
  const configured = Boolean(credentials);
@@ -12993,7 +13024,7 @@ function resolveQQBotAccount(params) {
12993
13024
  };
12994
13025
  }
12995
13026
  var qqbotPlugin = {
12996
- id: "qqbot",
13027
+ id: QQBOT_CHANNEL_ID,
12997
13028
  meta: {
12998
13029
  ...meta
12999
13030
  },
@@ -13012,10 +13043,7 @@ var qqbotPlugin = {
13012
13043
  normalizeTarget: (raw) => {
13013
13044
  const trimmed = raw.trim();
13014
13045
  if (!trimmed) return void 0;
13015
- let value = trimmed;
13016
- if (/^qqbot:/i.test(value)) {
13017
- value = value.slice("qqbot:".length);
13018
- }
13046
+ let value = stripQQBotChannelPrefix(trimmed);
13019
13047
  if (/^(user|group|channel):/i.test(value)) {
13020
13048
  return value;
13021
13049
  }
@@ -13173,7 +13201,7 @@ var qqbotPlugin = {
13173
13201
  }
13174
13202
  }
13175
13203
  },
13176
- reload: { configPrefixes: ["channels.qqbot"] },
13204
+ reload: { configPrefixes: [...QQBOT_CONFIG_PREFIXES] },
13177
13205
  onboarding: qqbotOnboardingAdapter,
13178
13206
  config: {
13179
13207
  listAccountIds: (cfg) => listQQBotAccountIds(cfg),
@@ -13181,58 +13209,41 @@ var qqbotPlugin = {
13181
13209
  defaultAccountId: () => DEFAULT_ACCOUNT_ID,
13182
13210
  setAccountEnabled: (params) => {
13183
13211
  const accountId = params.accountId ?? DEFAULT_ACCOUNT_ID;
13184
- const existing = params.cfg.channels?.qqbot ?? {};
13212
+ const existing = resolveQQBotChannelConfig(params.cfg) ?? {};
13185
13213
  if (accountId === DEFAULT_ACCOUNT_ID) {
13186
- return {
13187
- ...params.cfg,
13188
- channels: {
13189
- ...params.cfg.channels,
13190
- qqbot: { ...existing, enabled: params.enabled }
13191
- }
13192
- };
13214
+ return withQQBotChannelConfig(
13215
+ params.cfg,
13216
+ { ...existing, enabled: params.enabled }
13217
+ );
13193
13218
  }
13194
13219
  const accounts = existing.accounts ?? {};
13195
13220
  const account = accounts[accountId] ?? {};
13196
- return {
13197
- ...params.cfg,
13198
- channels: {
13199
- ...params.cfg.channels,
13200
- qqbot: {
13201
- ...existing,
13202
- accounts: {
13203
- ...accounts,
13204
- [accountId]: { ...account, enabled: params.enabled }
13205
- }
13221
+ return withQQBotChannelConfig(
13222
+ params.cfg,
13223
+ {
13224
+ ...existing,
13225
+ accounts: {
13226
+ ...accounts,
13227
+ [accountId]: { ...account, enabled: params.enabled }
13206
13228
  }
13207
13229
  }
13208
- };
13230
+ );
13209
13231
  },
13210
13232
  deleteAccount: (params) => {
13211
13233
  const accountId = params.accountId ?? DEFAULT_ACCOUNT_ID;
13212
13234
  if (accountId === DEFAULT_ACCOUNT_ID) {
13213
- const next = { ...params.cfg };
13214
- const nextChannels = { ...params.cfg.channels };
13215
- delete nextChannels.qqbot;
13216
- if (Object.keys(nextChannels).length > 0) {
13217
- next.channels = nextChannels;
13218
- } else {
13219
- delete next.channels;
13220
- }
13221
- return next;
13235
+ return withQQBotChannelConfig(params.cfg);
13222
13236
  }
13223
- const existing = params.cfg.channels?.qqbot;
13237
+ const existing = resolveQQBotChannelConfig(params.cfg);
13224
13238
  if (!existing?.accounts?.[accountId]) return params.cfg;
13225
13239
  const { [accountId]: _removed, ...remainingAccounts } = existing.accounts;
13226
- return {
13227
- ...params.cfg,
13228
- channels: {
13229
- ...params.cfg.channels,
13230
- qqbot: {
13231
- ...existing,
13232
- accounts: Object.keys(remainingAccounts).length > 0 ? remainingAccounts : void 0
13233
- }
13240
+ return withQQBotChannelConfig(
13241
+ params.cfg,
13242
+ {
13243
+ ...existing,
13244
+ accounts: Object.keys(remainingAccounts).length > 0 ? remainingAccounts : void 0
13234
13245
  }
13235
- };
13246
+ );
13236
13247
  },
13237
13248
  isConfigured: (_account, cfg, accountId) => {
13238
13249
  const id = accountId ?? _account.accountId;
@@ -13253,11 +13264,11 @@ var qqbotPlugin = {
13253
13264
  },
13254
13265
  security: {
13255
13266
  collectWarnings: (params) => {
13256
- const qqCfg = params.cfg.channels?.qqbot;
13267
+ const qqCfg = resolveQQBotChannelConfig(params.cfg);
13257
13268
  const groupPolicy = qqCfg?.groupPolicy ?? "allowlist";
13258
13269
  if (groupPolicy !== "open") return [];
13259
13270
  return [
13260
- `- QQ groups: groupPolicy="open" allows any member to trigger (mention-gated). Set channels.qqbot.groupPolicy="allowlist" + channels.qqbot.groupAllowFrom to restrict senders.`
13271
+ `- QQ groups: groupPolicy="open" allows any member to trigger (mention-gated). Set channels.${QQBOT_CONFIG_CHANNEL_ID}.groupPolicy="allowlist" + channels.${QQBOT_CONFIG_CHANNEL_ID}.groupAllowFrom to restrict senders.`
13261
13272
  ];
13262
13273
  }
13263
13274
  },
@@ -13265,37 +13276,31 @@ var qqbotPlugin = {
13265
13276
  resolveAccountId: (params) => params.accountId ?? resolveDefaultQQBotAccountId(params.cfg),
13266
13277
  applyAccountConfig: (params) => {
13267
13278
  const accountId = params.accountId ?? DEFAULT_ACCOUNT_ID;
13268
- const existing = params.cfg.channels?.qqbot ?? {};
13279
+ const existing = resolveQQBotChannelConfig(params.cfg) ?? {};
13269
13280
  if (accountId === DEFAULT_ACCOUNT_ID) {
13270
- return {
13271
- ...params.cfg,
13272
- channels: {
13273
- ...params.cfg.channels,
13274
- qqbot: { ...existing, ...params.config, enabled: true }
13275
- }
13276
- };
13281
+ return withQQBotChannelConfig(
13282
+ params.cfg,
13283
+ { ...existing, ...params.config, enabled: true }
13284
+ );
13277
13285
  }
13278
13286
  const accounts = existing.accounts ?? {};
13279
- return {
13280
- ...params.cfg,
13281
- channels: {
13282
- ...params.cfg.channels,
13283
- qqbot: {
13284
- ...existing,
13285
- accounts: {
13286
- ...accounts,
13287
- [accountId]: { ...accounts[accountId], ...params.config, enabled: true }
13288
- }
13287
+ return withQQBotChannelConfig(
13288
+ params.cfg,
13289
+ {
13290
+ ...existing,
13291
+ accounts: {
13292
+ ...accounts,
13293
+ [accountId]: { ...accounts[accountId], ...params.config, enabled: true }
13289
13294
  }
13290
13295
  }
13291
- };
13296
+ );
13292
13297
  }
13293
13298
  },
13294
13299
  outbound: qqbotOutbound,
13295
13300
  gateway: {
13296
13301
  startAccount: async (ctx) => {
13297
13302
  ctx.setStatus?.({ accountId: ctx.accountId });
13298
- ctx.log?.info(`[qqbot] starting gateway for account ${ctx.accountId}`);
13303
+ ctx.log?.info(`[${QQBOT_CHANNEL_ID}] starting gateway for account ${ctx.accountId}`);
13299
13304
  if (ctx.runtime) {
13300
13305
  const candidate = ctx.runtime;
13301
13306
  const hasRouting = Boolean(candidate.channel?.routing?.resolveAgentRoute);
@@ -13324,7 +13329,7 @@ var qqbotPlugin = {
13324
13329
 
13325
13330
  // index.ts
13326
13331
  var plugin = {
13327
- id: "qqbot",
13332
+ id: QQBOT_CHANNEL_ID,
13328
13333
  name: "QQ Bot",
13329
13334
  description: "QQ \u5F00\u653E\u5E73\u53F0\u673A\u5668\u4EBA\u6D88\u606F\u6E20\u9053\u63D2\u4EF6",
13330
13335
  configSchema: {
@@ -13442,7 +13447,7 @@ var plugin = {
13442
13447
  }
13443
13448
  },
13444
13449
  register(api) {
13445
- registerChinaSetupCli(api, { channels: ["qqbot"] });
13450
+ registerChinaSetupCli(api, { channels: [QQBOT_CONFIG_CHANNEL_ID] });
13446
13451
  showChinaInstallHint(api);
13447
13452
  if (api.runtime) {
13448
13453
  setQQBotRuntime(api.runtime);
@@ -13452,6 +13457,6 @@ var plugin = {
13452
13457
  };
13453
13458
  var index_default = plugin;
13454
13459
 
13455
- export { DEFAULT_ACCOUNT_ID, clearKnownQQBotTargets, index_default as default, getKnownQQBotTarget, getQQBotRuntime, listKnownQQBotTargets, qqbotPlugin, removeKnownQQBotTarget, sendProactiveQQBotMessage, setQQBotRuntime };
13460
+ export { DEFAULT_ACCOUNT_ID, QQBOT_CHANNEL_ID, QQBOT_CONFIG_CHANNEL_ID, clearKnownQQBotTargets, index_default as default, getKnownQQBotTarget, getQQBotRuntime, listKnownQQBotTargets, qqbotPlugin, removeKnownQQBotTarget, sendProactiveQQBotMessage, setQQBotRuntime };
13456
13461
  //# sourceMappingURL=index.js.map
13457
13462
  //# sourceMappingURL=index.js.map