csdn-im 0.1.4 → 0.1.5

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.
Files changed (3) hide show
  1. package/dist/index.cjs +102 -54
  2. package/dist/index.js +102 -54
  3. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -4078,10 +4078,12 @@ var NEVER = INVALID;
4078
4078
 
4079
4079
  // src/config.ts
4080
4080
  var CSDN_PLUGIN_ID = "csdn-im";
4081
+ var CSDN_LOG_TAG = "[csdn-im]";
4081
4082
  var FIXED_LONG_POLLING_TIMEOUT_SEC = 30;
4082
4083
  var FIXED_TAKE = 1;
4083
4084
  var FIXED_RETRY_INTERVAL_MS = 3e3;
4084
4085
  var FIXED_RETRY_BACKOFF_MAX_MS = 12e4;
4086
+ var MAX_POLL_INTERVAL_MS = 6e5;
4085
4087
  function getCsdnChannelObjectFromRoot(cfg) {
4086
4088
  return cfg?.channels?.[CSDN_PLUGIN_ID];
4087
4089
  }
@@ -4101,7 +4103,12 @@ var CsdnConfigSchema = external_exports.object({
4101
4103
  /**
4102
4104
  * 为 true 时打印完整消息体、HTTP 拉取/发送细节、路由与分发路径等调试日志。
4103
4105
  */
4104
- verbose: external_exports.boolean().default(false)
4106
+ verbose: external_exports.boolean().default(false),
4107
+ /**
4108
+ * 两次成功拉取(poll end → 下一次 poll begin)之间的额外间隔(毫秒)。
4109
+ * `0` 表示仅让出事件循环后立即下一轮(历史默认行为);设为 `1000` 等可减轻对服务端的请求频率。
4110
+ */
4111
+ pollIntervalMs: external_exports.number().min(0).max(MAX_POLL_INTERVAL_MS).default(0)
4105
4112
  });
4106
4113
  function clampLongPollingSeconds(n) {
4107
4114
  if (!Number.isFinite(n) || n < 1) return 30;
@@ -4114,6 +4121,10 @@ function clampTake(n) {
4114
4121
  function normalizeApiBaseUrl(url) {
4115
4122
  return url.replace(/\/+$/, "");
4116
4123
  }
4124
+ function clampPollIntervalMs(n) {
4125
+ if (!Number.isFinite(n) || n < 0) return 0;
4126
+ return Math.min(MAX_POLL_INTERVAL_MS, Math.floor(n));
4127
+ }
4117
4128
  function isConfigured(config) {
4118
4129
  if (!config) return false;
4119
4130
  const parsed = CsdnConfigSchema.safeParse(config);
@@ -4204,6 +4215,9 @@ function joinBaseAndPath(base, path) {
4204
4215
  function isAbortError(e) {
4205
4216
  return e instanceof Error && e.name === "AbortError" || typeof DOMException !== "undefined" && e instanceof DOMException && e.name === "AbortError";
4206
4217
  }
4218
+ function pullErrorLog(baseUrl, detail) {
4219
+ console.error(`${CSDN_LOG_TAG} pull GET ${PATH_UNREAD} base=${baseUrl} \u2014 ${detail}`);
4220
+ }
4207
4221
  var CsdnClient = class {
4208
4222
  constructor(config) {
4209
4223
  this.config = config;
@@ -4233,7 +4247,7 @@ var CsdnClient = class {
4233
4247
  try {
4234
4248
  if (this.config.verbose) {
4235
4249
  console.info(
4236
- `[csdn] pull GET ${PATH_UNREAD} base=${this.baseUrl} timeout=${sec}s take=${take}${cursor ? ` afterMessageId=${cursor}` : ""}`
4250
+ `${CSDN_LOG_TAG} pull GET ${PATH_UNREAD} base=${this.baseUrl} timeout=${sec}s take=${take}${cursor ? ` afterMessageId=${cursor}` : ""}`
4237
4251
  );
4238
4252
  }
4239
4253
  const response = await fetch(unreadUrl.href, {
@@ -4251,31 +4265,42 @@ var CsdnClient = class {
4251
4265
  if (fromResult !== null) {
4252
4266
  if (this.config.verbose) {
4253
4267
  console.info(
4254
- `[csdn] pull response ok code=0 messages=${fromResult.length} httpStatus=${response.status}`
4268
+ `${CSDN_LOG_TAG} pull response ok code=0 messages=${fromResult.length} httpStatus=${response.status}`
4255
4269
  );
4256
4270
  }
4257
4271
  return fromResult;
4258
4272
  }
4273
+ if (response.status === 408 || response.status === 504) {
4274
+ console.warn(
4275
+ `${CSDN_LOG_TAG} pull GET ${PATH_UNREAD} base=${this.baseUrl} httpStatus=${response.status} (timeout/\u7F51\u5173\u8D85\u65F6\uFF0C\u672C\u8F6E\u6309\u7A7A\u7ED3\u679C\u5904\u7406)`
4276
+ );
4277
+ return [];
4278
+ }
4259
4279
  const fail = getBotApiFailureInfo(body);
4260
4280
  if (fail) {
4261
- if (fail.code === "401") {
4262
- console.warn(`[csdn] getUnreadMessages: ${fail.message || "Token\u65E0\u6548\u6216\u5DF2\u8FC7\u671F"} (code=${fail.code})`);
4263
- } else {
4264
- console.warn(`[csdn] getUnreadMessages: ${fail.message} (code=${fail.code})`);
4281
+ pullErrorLog(
4282
+ this.baseUrl,
4283
+ `business failure httpStatus=${response.status} code=${fail.code} message=${fail.message || "(empty)"}`
4284
+ );
4285
+ if (response.ok) {
4286
+ return [];
4265
4287
  }
4266
4288
  }
4267
4289
  const legacy = tryLegacyUnreadMessages(body);
4268
4290
  if (legacy) {
4269
4291
  console.warn(
4270
- `[csdn] using legacy unread response format; prefer ClawBot Result with code "0" messages=${legacy.length}`
4292
+ `${CSDN_LOG_TAG} using legacy unread response format; prefer ClawBot Result with code "0" messages=${legacy.length}`
4271
4293
  );
4272
4294
  return legacy;
4273
4295
  }
4274
4296
  if (body !== void 0 && body !== null) {
4275
- console.warn("[csdn] unexpected response format:", JSON.stringify(body).substring(0, 200));
4297
+ pullErrorLog(this.baseUrl, `unexpected response format httpStatus=${response.status} body=${JSON.stringify(body).substring(0, 200)}`);
4276
4298
  }
4277
- if (response.status === 408 || response.status === 504) {
4278
- return [];
4299
+ if (!response.ok) {
4300
+ const hint = body !== void 0 && body !== null ? (typeof body === "string" ? body : JSON.stringify(body)).slice(0, 200) : "";
4301
+ const detail = `HTTP ${response.status}${hint ? ` body=${hint}` : ""}`;
4302
+ pullErrorLog(this.baseUrl, detail);
4303
+ throw new Error(`${CSDN_LOG_TAG} GET ${PATH_UNREAD} failed: ${detail}`);
4279
4304
  }
4280
4305
  return [];
4281
4306
  } catch (error) {
@@ -4286,7 +4311,9 @@ var CsdnClient = class {
4286
4311
  return [];
4287
4312
  }
4288
4313
  const msg = error instanceof Error ? error.message : String(error);
4289
- console.error(`[csdn] getUnreadMessages failed: ${msg}`);
4314
+ if (!(error instanceof Error && msg.startsWith(`${CSDN_LOG_TAG} GET`))) {
4315
+ pullErrorLog(this.baseUrl, `request error: ${msg}`);
4316
+ }
4290
4317
  throw error instanceof Error ? error : new Error(msg);
4291
4318
  }
4292
4319
  }
@@ -4299,7 +4326,7 @@ var CsdnClient = class {
4299
4326
  try {
4300
4327
  if (this.config.verbose) {
4301
4328
  console.info(
4302
- `[csdn] send POST ${PATH_SEND} to=${to} contentLength=${content.length}${opts?.type ? ` type=${opts.type}` : ""}`
4329
+ `${CSDN_LOG_TAG} send POST ${PATH_SEND} to=${to} contentLength=${content.length}${opts?.type ? ` type=${opts.type}` : ""}`
4303
4330
  );
4304
4331
  }
4305
4332
  const response = await fetch(sendUrl, {
@@ -4318,19 +4345,22 @@ var CsdnClient = class {
4318
4345
  if (ok) {
4319
4346
  if (this.config.verbose) {
4320
4347
  console.info(
4321
- `[csdn] send response ok code=0 id=${ok.id} httpStatus=${response.status}${ok.timestamp != null ? ` timestamp=${ok.timestamp}` : ""}`
4348
+ `${CSDN_LOG_TAG} send response ok code=0 id=${ok.id} httpStatus=${response.status}${ok.timestamp != null ? ` timestamp=${ok.timestamp}` : ""}`
4322
4349
  );
4323
4350
  }
4324
4351
  return ok;
4325
4352
  }
4326
4353
  const fail = getBotApiFailureInfo(body);
4327
4354
  const hint = fail ? `${fail.message} (code=${fail.code})` : `HTTP ${response.status}`;
4328
- throw new Error(`[csdn] sendMessage failed: ${hint}`);
4355
+ console.error(
4356
+ `${CSDN_LOG_TAG} send POST ${PATH_SEND} base=${this.baseUrl} httpStatus=${response.status} ${hint}`
4357
+ );
4358
+ throw new Error(`${CSDN_LOG_TAG} sendMessage failed: ${hint}`);
4329
4359
  } catch (error) {
4330
- if (error instanceof Error && error.message.startsWith("[csdn] sendMessage failed:")) {
4360
+ if (error instanceof Error && error.message.startsWith(`${CSDN_LOG_TAG} sendMessage failed:`)) {
4331
4361
  throw error;
4332
4362
  }
4333
- console.error("[csdn] sendMessage failed:", error);
4363
+ console.error(`${CSDN_LOG_TAG} send POST ${PATH_SEND} base=${this.baseUrl} request error:`, error);
4334
4364
  throw error;
4335
4365
  }
4336
4366
  }
@@ -4472,7 +4502,7 @@ function findRequireAnchorPackageJson() {
4472
4502
  dir = parent;
4473
4503
  }
4474
4504
  throw new Error(
4475
- "[csdn] loadOpenclawPluginSdk: no package.json found walking up from process.cwd(); cannot createRequire for openclaw fallback"
4505
+ `${CSDN_LOG_TAG} loadOpenclawPluginSdk: no package.json found walking up from process.cwd(); cannot createRequire for openclaw fallback`
4476
4506
  );
4477
4507
  }
4478
4508
  async function loadOpenclawPluginSdk() {
@@ -4507,12 +4537,12 @@ var csdnOutbound = {
4507
4537
  const csdnCfgRaw = getCsdnChannelObjectFromRoot(cfg);
4508
4538
  const parsed = CsdnConfigSchema.safeParse(csdnCfgRaw);
4509
4539
  if (!parsed.success) {
4510
- throw new Error("[csdn] invalid config for outbound");
4540
+ throw new Error(`${CSDN_LOG_TAG} invalid config for outbound`);
4511
4541
  }
4512
4542
  const client = new CsdnClient(parsed.data);
4513
4543
  const result = await client.sendMessage(to, text);
4514
4544
  if (parsed.data.verbose) {
4515
- console.info(`[csdn] outbound sent messageId=${result.id} to=${to} textLength=${text.length}`);
4545
+ console.info(`${CSDN_LOG_TAG} outbound sent messageId=${result.id} to=${to} textLength=${text.length}`);
4516
4546
  }
4517
4547
  return {
4518
4548
  channel: CSDN_PLUGIN_ID,
@@ -4576,14 +4606,14 @@ function logRoutingFallbackOnce(log) {
4576
4606
  if (routingFallbackLogged) return;
4577
4607
  routingFallbackLogged = true;
4578
4608
  log(
4579
- "[csdn] host runtime.channel.routing.resolveAgentRoute unavailable \u2192 embedded session key (normal for some gateways; once per process)"
4609
+ "host runtime.channel.routing.resolveAgentRoute unavailable \u2192 embedded session key (normal for some gateways; once per process)"
4580
4610
  );
4581
4611
  }
4582
4612
  function logDispatchFallbackOnce(log) {
4583
4613
  if (dispatchFallbackLogged) return;
4584
4614
  dispatchFallbackLogged = true;
4585
4615
  log(
4586
- "[csdn] host runtime.channel.reply.dispatchReplyFromConfig unavailable \u2192 openclaw/plugin-sdk (normal for some gateways; once per process)"
4616
+ "host runtime.channel.reply.dispatchReplyFromConfig unavailable \u2192 openclaw/plugin-sdk (normal for some gateways; once per process)"
4587
4617
  );
4588
4618
  }
4589
4619
 
@@ -4626,7 +4656,7 @@ async function handleCsdnMessage(params) {
4626
4656
  }
4627
4657
  if (usedEmbeddedRoute && verbose) {
4628
4658
  try {
4629
- logger.info(`[csdn] route.fallback sessionKey=${route.sessionKey} accountId=${route.accountId ?? accountId}`);
4659
+ logger.info(`route.fallback sessionKey=${route.sessionKey} accountId=${route.accountId ?? accountId}`);
4630
4660
  } catch {
4631
4661
  }
4632
4662
  }
@@ -4651,7 +4681,7 @@ async function handleCsdnMessage(params) {
4651
4681
  };
4652
4682
  if (verbose) {
4653
4683
  try {
4654
- logger.info(`[csdn] inbound.content ${inboundCtx.Body}`);
4684
+ logger.info(`inbound.content ${inboundCtx.Body}`);
4655
4685
  } catch {
4656
4686
  }
4657
4687
  }
@@ -4663,10 +4693,10 @@ async function handleCsdnMessage(params) {
4663
4693
  if (!text) return;
4664
4694
  try {
4665
4695
  if (verbose) {
4666
- logger.info(`[csdn] outbound text to=${msg.from} len=${text.length}`);
4667
- logger.info(`[csdn] outbound.content ${text}`);
4696
+ logger.info(`outbound text to=${msg.from} len=${text.length}`);
4697
+ logger.info(`outbound.content ${text}`);
4668
4698
  } else {
4669
- logger.info(`[csdn] reply to=${msg.from} len=${text.length}`);
4699
+ logger.info(`reply to=${msg.from} len=${text.length}`);
4670
4700
  }
4671
4701
  await csdnOutbound.sendText({
4672
4702
  cfg: config,
@@ -4674,21 +4704,21 @@ async function handleCsdnMessage(params) {
4674
4704
  text
4675
4705
  });
4676
4706
  if (verbose) {
4677
- logger.info(`[csdn] outbound done to=${msg.from}`);
4707
+ logger.info(`outbound done to=${msg.from}`);
4678
4708
  }
4679
4709
  } catch (err) {
4680
- logger.error(`[csdn] failed to send reply: ${String(err)}`);
4710
+ logger.error(`failed to send reply: ${String(err)}`);
4681
4711
  }
4682
4712
  },
4683
4713
  onError: (err, info) => {
4684
- logger.error(`[csdn] reply dispatch kind=${info.kind} error: ${String(err)}`);
4714
+ logger.error(`reply dispatch kind=${info.kind} error: ${String(err)}`);
4685
4715
  }
4686
4716
  });
4687
4717
  const dispatchFromRuntime = runtime?.channel?.reply?.dispatchReplyFromConfig;
4688
4718
  const runDispatch = async () => {
4689
4719
  if (typeof dispatchFromRuntime === "function") {
4690
4720
  if (verbose) {
4691
- logger.info(`[csdn] dispatching via runtime.channel.reply session=${route.sessionKey}`);
4721
+ logger.info(`dispatching via runtime.channel.reply session=${route.sessionKey}`);
4692
4722
  }
4693
4723
  await dispatchFromRuntime({
4694
4724
  ctx: inboundCtx,
@@ -4704,7 +4734,7 @@ async function handleCsdnMessage(params) {
4704
4734
  const withSettled = sdk.dispatchReplyFromConfigWithSettledDispatcher;
4705
4735
  const plain = sdk.dispatchReplyFromConfig;
4706
4736
  if (verbose) {
4707
- logger.info(`[csdn] dispatching via plugin-sdk session=${route.sessionKey}`);
4737
+ logger.info(`dispatching via plugin-sdk session=${route.sessionKey}`);
4708
4738
  }
4709
4739
  if (typeof withSettled === "function") {
4710
4740
  await withSettled({
@@ -4728,24 +4758,24 @@ async function handleCsdnMessage(params) {
4728
4758
  );
4729
4759
  }
4730
4760
  } catch (err) {
4731
- logger.error(`[csdn] plugin-sdk dispatch unavailable: ${String(err)}`);
4761
+ logger.error(`plugin-sdk dispatch unavailable: ${String(err)}`);
4732
4762
  throw err;
4733
4763
  }
4734
4764
  };
4735
4765
  try {
4736
4766
  await runDispatch();
4737
4767
  if (verbose) {
4738
- logger.info(`[csdn] dispatch complete session=${route.sessionKey}`);
4768
+ logger.info(`dispatch complete session=${route.sessionKey}`);
4739
4769
  }
4740
4770
  } catch (err) {
4741
- logger.error(`[csdn] dispatch error: ${String(err)}`);
4771
+ logger.error(`dispatch error: ${String(err)}`);
4742
4772
  try {
4743
4773
  const echo = `\u5DF2\u6536\u5230\uFF1A${inboundCtx.Body}`;
4744
4774
  if (verbose) {
4745
- logger.info(`[csdn] outbound text(to=${msg.from}) via fallback len=${echo.length}`);
4746
- logger.info(`[csdn] outbound.content ${echo}`);
4775
+ logger.info(`outbound text(to=${msg.from}) via fallback len=${echo.length}`);
4776
+ logger.info(`outbound.content ${echo}`);
4747
4777
  } else {
4748
- logger.info(`[csdn] echo fallback to=${msg.from} len=${echo.length}`);
4778
+ logger.info(`echo fallback to=${msg.from} len=${echo.length}`);
4749
4779
  }
4750
4780
  await csdnOutbound.sendText({
4751
4781
  cfg: config,
@@ -4753,10 +4783,10 @@ async function handleCsdnMessage(params) {
4753
4783
  text: echo
4754
4784
  });
4755
4785
  if (verbose) {
4756
- logger.info(`[csdn] outbound done to=${msg.from} (fallback)`);
4786
+ logger.info(`outbound done to=${msg.from} (fallback)`);
4757
4787
  }
4758
4788
  } catch (sendErr) {
4759
- logger.error(`[csdn] fallback reply failed: ${String(sendErr)}`);
4789
+ logger.error(`fallback reply failed: ${String(sendErr)}`);
4760
4790
  }
4761
4791
  }
4762
4792
  }
@@ -4769,6 +4799,26 @@ function maxMessageId(messages) {
4769
4799
  }
4770
4800
  return max;
4771
4801
  }
4802
+ function sleepBetweenPolls(ms, signal) {
4803
+ if (ms <= 0) {
4804
+ return new Promise((resolve) => setImmediate(resolve));
4805
+ }
4806
+ return new Promise((resolve) => {
4807
+ if (signal?.aborted) {
4808
+ resolve();
4809
+ return;
4810
+ }
4811
+ const t = setTimeout(resolve, ms);
4812
+ signal?.addEventListener(
4813
+ "abort",
4814
+ () => {
4815
+ clearTimeout(t);
4816
+ resolve();
4817
+ },
4818
+ { once: true }
4819
+ );
4820
+ });
4821
+ }
4772
4822
  async function monitorCsdnProvider(opts) {
4773
4823
  const { config, runtime, accountId = "default", abortSignal } = opts;
4774
4824
  const baseLogger = runtime && (runtime.logger || runtime.log) || console;
@@ -4780,18 +4830,19 @@ async function monitorCsdnProvider(opts) {
4780
4830
  const csdnCfgRaw = getCsdnChannelObjectFromRoot(config);
4781
4831
  const parsed = CsdnConfigSchema.safeParse(csdnCfgRaw);
4782
4832
  if (!parsed.success) {
4783
- logger.error(`[csdn] invalid config for account ${accountId}: ${parsed.error}`);
4833
+ logger.error(`invalid config for account ${accountId}: ${parsed.error}`);
4784
4834
  return;
4785
4835
  }
4786
4836
  const csdnCfg = parsed.data;
4787
4837
  if (!csdnCfg.token) {
4788
- logger.warn(`[csdn] token missing; skip start for account ${accountId}`);
4838
+ logger.warn(`token missing; skip start for account ${accountId}`);
4789
4839
  return;
4790
4840
  }
4791
4841
  const client = new CsdnClient(csdnCfg);
4842
+ const pollIntervalMs = clampPollIntervalMs(csdnCfg.pollIntervalMs);
4792
4843
  const v = csdnCfg.verbose;
4793
4844
  logger.info(
4794
- `[csdn] starting long-polling account=${accountId} apiUrl=${csdnCfg.apiUrl} timeout=${FIXED_LONG_POLLING_TIMEOUT_SEC}s take=${FIXED_TAKE}`
4845
+ `starting long-polling account=${accountId} apiUrl=${csdnCfg.apiUrl} timeout=${FIXED_LONG_POLLING_TIMEOUT_SEC}s take=${FIXED_TAKE} pollIntervalMs=${pollIntervalMs}`
4795
4846
  );
4796
4847
  let backoffMs = FIXED_RETRY_INTERVAL_MS;
4797
4848
  const backoffCap = Math.max(FIXED_RETRY_INTERVAL_MS, FIXED_RETRY_BACKOFF_MAX_MS);
@@ -4801,9 +4852,6 @@ async function monitorCsdnProvider(opts) {
4801
4852
  try {
4802
4853
  const t0 = Date.now();
4803
4854
  if (v) {
4804
- logger.info(
4805
- `[csdn] poll begin account=${accountId} timeout=${FIXED_LONG_POLLING_TIMEOUT_SEC}s take=${FIXED_TAKE}${afterMessageId ? ` afterMessageId=${afterMessageId}` : ""}`
4806
- );
4807
4855
  }
4808
4856
  const messages = await client.getUnreadMessages(FIXED_LONG_POLLING_TIMEOUT_SEC, {
4809
4857
  afterMessageId,
@@ -4811,12 +4859,11 @@ async function monitorCsdnProvider(opts) {
4811
4859
  });
4812
4860
  backoffMs = FIXED_RETRY_INTERVAL_MS;
4813
4861
  const dur = Date.now() - t0;
4814
- logger.info(`[csdn] poll end account=${accountId} duration=${dur}ms count=${messages.length}`);
4815
4862
  for (const msg of messages) {
4816
- logger.info(`[csdn] inbound id=${msg.id} from=${msg.from} type=${msg.type} size=${msg.content?.length ?? 0}`);
4863
+ logger.info(`inbound id=${msg.id} from=${msg.from} type=${msg.type} size=${msg.content?.length ?? 0}`);
4817
4864
  if (v) {
4818
4865
  try {
4819
- logger.info(`[csdn] inbound.full ${JSON.stringify(msg)}`);
4866
+ logger.info(`inbound.full ${JSON.stringify(msg)}`);
4820
4867
  } catch {
4821
4868
  }
4822
4869
  }
@@ -4830,17 +4877,17 @@ async function monitorCsdnProvider(opts) {
4830
4877
  if (messages.length > 0) {
4831
4878
  afterMessageId = maxMessageId(messages);
4832
4879
  }
4833
- await new Promise((resolve) => setImmediate(resolve));
4880
+ await sleepBetweenPolls(pollIntervalMs, abortSignal);
4834
4881
  } catch (err) {
4835
- logger.error(`[csdn] polling error: ${err}`);
4882
+ logger.error(`polling error: ${err}`);
4836
4883
  logger.info(
4837
- `[csdn] waiting ${backoffMs}ms before retry (exponential backoff, cap=${backoffCap}ms)...`
4884
+ `waiting ${backoffMs}ms before retry (exponential backoff, cap=${backoffCap}ms)...`
4838
4885
  );
4839
4886
  await new Promise((resolve) => setTimeout(resolve, backoffMs));
4840
4887
  backoffMs = Math.min(backoffCap, Math.max(FIXED_RETRY_INTERVAL_MS, backoffMs * 2));
4841
4888
  }
4842
4889
  }
4843
- logger.info(`[csdn] polling stopped for account ${accountId}`);
4890
+ logger.info(`polling stopped for account ${accountId}`);
4844
4891
  };
4845
4892
  return pollLoop();
4846
4893
  }
@@ -4903,7 +4950,8 @@ var csdnPlugin = {
4903
4950
  token: { type: "string" },
4904
4951
  apiUrl: { type: "string" },
4905
4952
  fallbackAgentId: { type: "string" },
4906
- verbose: { type: "boolean" }
4953
+ verbose: { type: "boolean" },
4954
+ pollIntervalMs: { type: "number", minimum: 0, maximum: 6e5 }
4907
4955
  }
4908
4956
  }
4909
4957
  },
package/dist/index.js CHANGED
@@ -4047,10 +4047,12 @@ var NEVER = INVALID;
4047
4047
 
4048
4048
  // src/config.ts
4049
4049
  var CSDN_PLUGIN_ID = "csdn-im";
4050
+ var CSDN_LOG_TAG = "[csdn-im]";
4050
4051
  var FIXED_LONG_POLLING_TIMEOUT_SEC = 30;
4051
4052
  var FIXED_TAKE = 1;
4052
4053
  var FIXED_RETRY_INTERVAL_MS = 3e3;
4053
4054
  var FIXED_RETRY_BACKOFF_MAX_MS = 12e4;
4055
+ var MAX_POLL_INTERVAL_MS = 6e5;
4054
4056
  function getCsdnChannelObjectFromRoot(cfg) {
4055
4057
  return cfg?.channels?.[CSDN_PLUGIN_ID];
4056
4058
  }
@@ -4070,7 +4072,12 @@ var CsdnConfigSchema = external_exports.object({
4070
4072
  /**
4071
4073
  * 为 true 时打印完整消息体、HTTP 拉取/发送细节、路由与分发路径等调试日志。
4072
4074
  */
4073
- verbose: external_exports.boolean().default(false)
4075
+ verbose: external_exports.boolean().default(false),
4076
+ /**
4077
+ * 两次成功拉取(poll end → 下一次 poll begin)之间的额外间隔(毫秒)。
4078
+ * `0` 表示仅让出事件循环后立即下一轮(历史默认行为);设为 `1000` 等可减轻对服务端的请求频率。
4079
+ */
4080
+ pollIntervalMs: external_exports.number().min(0).max(MAX_POLL_INTERVAL_MS).default(0)
4074
4081
  });
4075
4082
  function clampLongPollingSeconds(n) {
4076
4083
  if (!Number.isFinite(n) || n < 1) return 30;
@@ -4083,6 +4090,10 @@ function clampTake(n) {
4083
4090
  function normalizeApiBaseUrl(url) {
4084
4091
  return url.replace(/\/+$/, "");
4085
4092
  }
4093
+ function clampPollIntervalMs(n) {
4094
+ if (!Number.isFinite(n) || n < 0) return 0;
4095
+ return Math.min(MAX_POLL_INTERVAL_MS, Math.floor(n));
4096
+ }
4086
4097
  function isConfigured(config) {
4087
4098
  if (!config) return false;
4088
4099
  const parsed = CsdnConfigSchema.safeParse(config);
@@ -4173,6 +4184,9 @@ function joinBaseAndPath(base, path) {
4173
4184
  function isAbortError(e) {
4174
4185
  return e instanceof Error && e.name === "AbortError" || typeof DOMException !== "undefined" && e instanceof DOMException && e.name === "AbortError";
4175
4186
  }
4187
+ function pullErrorLog(baseUrl, detail) {
4188
+ console.error(`${CSDN_LOG_TAG} pull GET ${PATH_UNREAD} base=${baseUrl} \u2014 ${detail}`);
4189
+ }
4176
4190
  var CsdnClient = class {
4177
4191
  constructor(config) {
4178
4192
  this.config = config;
@@ -4202,7 +4216,7 @@ var CsdnClient = class {
4202
4216
  try {
4203
4217
  if (this.config.verbose) {
4204
4218
  console.info(
4205
- `[csdn] pull GET ${PATH_UNREAD} base=${this.baseUrl} timeout=${sec}s take=${take}${cursor ? ` afterMessageId=${cursor}` : ""}`
4219
+ `${CSDN_LOG_TAG} pull GET ${PATH_UNREAD} base=${this.baseUrl} timeout=${sec}s take=${take}${cursor ? ` afterMessageId=${cursor}` : ""}`
4206
4220
  );
4207
4221
  }
4208
4222
  const response = await fetch(unreadUrl.href, {
@@ -4220,31 +4234,42 @@ var CsdnClient = class {
4220
4234
  if (fromResult !== null) {
4221
4235
  if (this.config.verbose) {
4222
4236
  console.info(
4223
- `[csdn] pull response ok code=0 messages=${fromResult.length} httpStatus=${response.status}`
4237
+ `${CSDN_LOG_TAG} pull response ok code=0 messages=${fromResult.length} httpStatus=${response.status}`
4224
4238
  );
4225
4239
  }
4226
4240
  return fromResult;
4227
4241
  }
4242
+ if (response.status === 408 || response.status === 504) {
4243
+ console.warn(
4244
+ `${CSDN_LOG_TAG} pull GET ${PATH_UNREAD} base=${this.baseUrl} httpStatus=${response.status} (timeout/\u7F51\u5173\u8D85\u65F6\uFF0C\u672C\u8F6E\u6309\u7A7A\u7ED3\u679C\u5904\u7406)`
4245
+ );
4246
+ return [];
4247
+ }
4228
4248
  const fail = getBotApiFailureInfo(body);
4229
4249
  if (fail) {
4230
- if (fail.code === "401") {
4231
- console.warn(`[csdn] getUnreadMessages: ${fail.message || "Token\u65E0\u6548\u6216\u5DF2\u8FC7\u671F"} (code=${fail.code})`);
4232
- } else {
4233
- console.warn(`[csdn] getUnreadMessages: ${fail.message} (code=${fail.code})`);
4250
+ pullErrorLog(
4251
+ this.baseUrl,
4252
+ `business failure httpStatus=${response.status} code=${fail.code} message=${fail.message || "(empty)"}`
4253
+ );
4254
+ if (response.ok) {
4255
+ return [];
4234
4256
  }
4235
4257
  }
4236
4258
  const legacy = tryLegacyUnreadMessages(body);
4237
4259
  if (legacy) {
4238
4260
  console.warn(
4239
- `[csdn] using legacy unread response format; prefer ClawBot Result with code "0" messages=${legacy.length}`
4261
+ `${CSDN_LOG_TAG} using legacy unread response format; prefer ClawBot Result with code "0" messages=${legacy.length}`
4240
4262
  );
4241
4263
  return legacy;
4242
4264
  }
4243
4265
  if (body !== void 0 && body !== null) {
4244
- console.warn("[csdn] unexpected response format:", JSON.stringify(body).substring(0, 200));
4266
+ pullErrorLog(this.baseUrl, `unexpected response format httpStatus=${response.status} body=${JSON.stringify(body).substring(0, 200)}`);
4245
4267
  }
4246
- if (response.status === 408 || response.status === 504) {
4247
- return [];
4268
+ if (!response.ok) {
4269
+ const hint = body !== void 0 && body !== null ? (typeof body === "string" ? body : JSON.stringify(body)).slice(0, 200) : "";
4270
+ const detail = `HTTP ${response.status}${hint ? ` body=${hint}` : ""}`;
4271
+ pullErrorLog(this.baseUrl, detail);
4272
+ throw new Error(`${CSDN_LOG_TAG} GET ${PATH_UNREAD} failed: ${detail}`);
4248
4273
  }
4249
4274
  return [];
4250
4275
  } catch (error) {
@@ -4255,7 +4280,9 @@ var CsdnClient = class {
4255
4280
  return [];
4256
4281
  }
4257
4282
  const msg = error instanceof Error ? error.message : String(error);
4258
- console.error(`[csdn] getUnreadMessages failed: ${msg}`);
4283
+ if (!(error instanceof Error && msg.startsWith(`${CSDN_LOG_TAG} GET`))) {
4284
+ pullErrorLog(this.baseUrl, `request error: ${msg}`);
4285
+ }
4259
4286
  throw error instanceof Error ? error : new Error(msg);
4260
4287
  }
4261
4288
  }
@@ -4268,7 +4295,7 @@ var CsdnClient = class {
4268
4295
  try {
4269
4296
  if (this.config.verbose) {
4270
4297
  console.info(
4271
- `[csdn] send POST ${PATH_SEND} to=${to} contentLength=${content.length}${opts?.type ? ` type=${opts.type}` : ""}`
4298
+ `${CSDN_LOG_TAG} send POST ${PATH_SEND} to=${to} contentLength=${content.length}${opts?.type ? ` type=${opts.type}` : ""}`
4272
4299
  );
4273
4300
  }
4274
4301
  const response = await fetch(sendUrl, {
@@ -4287,19 +4314,22 @@ var CsdnClient = class {
4287
4314
  if (ok) {
4288
4315
  if (this.config.verbose) {
4289
4316
  console.info(
4290
- `[csdn] send response ok code=0 id=${ok.id} httpStatus=${response.status}${ok.timestamp != null ? ` timestamp=${ok.timestamp}` : ""}`
4317
+ `${CSDN_LOG_TAG} send response ok code=0 id=${ok.id} httpStatus=${response.status}${ok.timestamp != null ? ` timestamp=${ok.timestamp}` : ""}`
4291
4318
  );
4292
4319
  }
4293
4320
  return ok;
4294
4321
  }
4295
4322
  const fail = getBotApiFailureInfo(body);
4296
4323
  const hint = fail ? `${fail.message} (code=${fail.code})` : `HTTP ${response.status}`;
4297
- throw new Error(`[csdn] sendMessage failed: ${hint}`);
4324
+ console.error(
4325
+ `${CSDN_LOG_TAG} send POST ${PATH_SEND} base=${this.baseUrl} httpStatus=${response.status} ${hint}`
4326
+ );
4327
+ throw new Error(`${CSDN_LOG_TAG} sendMessage failed: ${hint}`);
4298
4328
  } catch (error) {
4299
- if (error instanceof Error && error.message.startsWith("[csdn] sendMessage failed:")) {
4329
+ if (error instanceof Error && error.message.startsWith(`${CSDN_LOG_TAG} sendMessage failed:`)) {
4300
4330
  throw error;
4301
4331
  }
4302
- console.error("[csdn] sendMessage failed:", error);
4332
+ console.error(`${CSDN_LOG_TAG} send POST ${PATH_SEND} base=${this.baseUrl} request error:`, error);
4303
4333
  throw error;
4304
4334
  }
4305
4335
  }
@@ -4441,7 +4471,7 @@ function findRequireAnchorPackageJson() {
4441
4471
  dir = parent;
4442
4472
  }
4443
4473
  throw new Error(
4444
- "[csdn] loadOpenclawPluginSdk: no package.json found walking up from process.cwd(); cannot createRequire for openclaw fallback"
4474
+ `${CSDN_LOG_TAG} loadOpenclawPluginSdk: no package.json found walking up from process.cwd(); cannot createRequire for openclaw fallback`
4445
4475
  );
4446
4476
  }
4447
4477
  async function loadOpenclawPluginSdk() {
@@ -4476,12 +4506,12 @@ var csdnOutbound = {
4476
4506
  const csdnCfgRaw = getCsdnChannelObjectFromRoot(cfg);
4477
4507
  const parsed = CsdnConfigSchema.safeParse(csdnCfgRaw);
4478
4508
  if (!parsed.success) {
4479
- throw new Error("[csdn] invalid config for outbound");
4509
+ throw new Error(`${CSDN_LOG_TAG} invalid config for outbound`);
4480
4510
  }
4481
4511
  const client = new CsdnClient(parsed.data);
4482
4512
  const result = await client.sendMessage(to, text);
4483
4513
  if (parsed.data.verbose) {
4484
- console.info(`[csdn] outbound sent messageId=${result.id} to=${to} textLength=${text.length}`);
4514
+ console.info(`${CSDN_LOG_TAG} outbound sent messageId=${result.id} to=${to} textLength=${text.length}`);
4485
4515
  }
4486
4516
  return {
4487
4517
  channel: CSDN_PLUGIN_ID,
@@ -4545,14 +4575,14 @@ function logRoutingFallbackOnce(log) {
4545
4575
  if (routingFallbackLogged) return;
4546
4576
  routingFallbackLogged = true;
4547
4577
  log(
4548
- "[csdn] host runtime.channel.routing.resolveAgentRoute unavailable \u2192 embedded session key (normal for some gateways; once per process)"
4578
+ "host runtime.channel.routing.resolveAgentRoute unavailable \u2192 embedded session key (normal for some gateways; once per process)"
4549
4579
  );
4550
4580
  }
4551
4581
  function logDispatchFallbackOnce(log) {
4552
4582
  if (dispatchFallbackLogged) return;
4553
4583
  dispatchFallbackLogged = true;
4554
4584
  log(
4555
- "[csdn] host runtime.channel.reply.dispatchReplyFromConfig unavailable \u2192 openclaw/plugin-sdk (normal for some gateways; once per process)"
4585
+ "host runtime.channel.reply.dispatchReplyFromConfig unavailable \u2192 openclaw/plugin-sdk (normal for some gateways; once per process)"
4556
4586
  );
4557
4587
  }
4558
4588
 
@@ -4595,7 +4625,7 @@ async function handleCsdnMessage(params) {
4595
4625
  }
4596
4626
  if (usedEmbeddedRoute && verbose) {
4597
4627
  try {
4598
- logger.info(`[csdn] route.fallback sessionKey=${route.sessionKey} accountId=${route.accountId ?? accountId}`);
4628
+ logger.info(`route.fallback sessionKey=${route.sessionKey} accountId=${route.accountId ?? accountId}`);
4599
4629
  } catch {
4600
4630
  }
4601
4631
  }
@@ -4620,7 +4650,7 @@ async function handleCsdnMessage(params) {
4620
4650
  };
4621
4651
  if (verbose) {
4622
4652
  try {
4623
- logger.info(`[csdn] inbound.content ${inboundCtx.Body}`);
4653
+ logger.info(`inbound.content ${inboundCtx.Body}`);
4624
4654
  } catch {
4625
4655
  }
4626
4656
  }
@@ -4632,10 +4662,10 @@ async function handleCsdnMessage(params) {
4632
4662
  if (!text) return;
4633
4663
  try {
4634
4664
  if (verbose) {
4635
- logger.info(`[csdn] outbound text to=${msg.from} len=${text.length}`);
4636
- logger.info(`[csdn] outbound.content ${text}`);
4665
+ logger.info(`outbound text to=${msg.from} len=${text.length}`);
4666
+ logger.info(`outbound.content ${text}`);
4637
4667
  } else {
4638
- logger.info(`[csdn] reply to=${msg.from} len=${text.length}`);
4668
+ logger.info(`reply to=${msg.from} len=${text.length}`);
4639
4669
  }
4640
4670
  await csdnOutbound.sendText({
4641
4671
  cfg: config,
@@ -4643,21 +4673,21 @@ async function handleCsdnMessage(params) {
4643
4673
  text
4644
4674
  });
4645
4675
  if (verbose) {
4646
- logger.info(`[csdn] outbound done to=${msg.from}`);
4676
+ logger.info(`outbound done to=${msg.from}`);
4647
4677
  }
4648
4678
  } catch (err) {
4649
- logger.error(`[csdn] failed to send reply: ${String(err)}`);
4679
+ logger.error(`failed to send reply: ${String(err)}`);
4650
4680
  }
4651
4681
  },
4652
4682
  onError: (err, info) => {
4653
- logger.error(`[csdn] reply dispatch kind=${info.kind} error: ${String(err)}`);
4683
+ logger.error(`reply dispatch kind=${info.kind} error: ${String(err)}`);
4654
4684
  }
4655
4685
  });
4656
4686
  const dispatchFromRuntime = runtime?.channel?.reply?.dispatchReplyFromConfig;
4657
4687
  const runDispatch = async () => {
4658
4688
  if (typeof dispatchFromRuntime === "function") {
4659
4689
  if (verbose) {
4660
- logger.info(`[csdn] dispatching via runtime.channel.reply session=${route.sessionKey}`);
4690
+ logger.info(`dispatching via runtime.channel.reply session=${route.sessionKey}`);
4661
4691
  }
4662
4692
  await dispatchFromRuntime({
4663
4693
  ctx: inboundCtx,
@@ -4673,7 +4703,7 @@ async function handleCsdnMessage(params) {
4673
4703
  const withSettled = sdk.dispatchReplyFromConfigWithSettledDispatcher;
4674
4704
  const plain = sdk.dispatchReplyFromConfig;
4675
4705
  if (verbose) {
4676
- logger.info(`[csdn] dispatching via plugin-sdk session=${route.sessionKey}`);
4706
+ logger.info(`dispatching via plugin-sdk session=${route.sessionKey}`);
4677
4707
  }
4678
4708
  if (typeof withSettled === "function") {
4679
4709
  await withSettled({
@@ -4697,24 +4727,24 @@ async function handleCsdnMessage(params) {
4697
4727
  );
4698
4728
  }
4699
4729
  } catch (err) {
4700
- logger.error(`[csdn] plugin-sdk dispatch unavailable: ${String(err)}`);
4730
+ logger.error(`plugin-sdk dispatch unavailable: ${String(err)}`);
4701
4731
  throw err;
4702
4732
  }
4703
4733
  };
4704
4734
  try {
4705
4735
  await runDispatch();
4706
4736
  if (verbose) {
4707
- logger.info(`[csdn] dispatch complete session=${route.sessionKey}`);
4737
+ logger.info(`dispatch complete session=${route.sessionKey}`);
4708
4738
  }
4709
4739
  } catch (err) {
4710
- logger.error(`[csdn] dispatch error: ${String(err)}`);
4740
+ logger.error(`dispatch error: ${String(err)}`);
4711
4741
  try {
4712
4742
  const echo = `\u5DF2\u6536\u5230\uFF1A${inboundCtx.Body}`;
4713
4743
  if (verbose) {
4714
- logger.info(`[csdn] outbound text(to=${msg.from}) via fallback len=${echo.length}`);
4715
- logger.info(`[csdn] outbound.content ${echo}`);
4744
+ logger.info(`outbound text(to=${msg.from}) via fallback len=${echo.length}`);
4745
+ logger.info(`outbound.content ${echo}`);
4716
4746
  } else {
4717
- logger.info(`[csdn] echo fallback to=${msg.from} len=${echo.length}`);
4747
+ logger.info(`echo fallback to=${msg.from} len=${echo.length}`);
4718
4748
  }
4719
4749
  await csdnOutbound.sendText({
4720
4750
  cfg: config,
@@ -4722,10 +4752,10 @@ async function handleCsdnMessage(params) {
4722
4752
  text: echo
4723
4753
  });
4724
4754
  if (verbose) {
4725
- logger.info(`[csdn] outbound done to=${msg.from} (fallback)`);
4755
+ logger.info(`outbound done to=${msg.from} (fallback)`);
4726
4756
  }
4727
4757
  } catch (sendErr) {
4728
- logger.error(`[csdn] fallback reply failed: ${String(sendErr)}`);
4758
+ logger.error(`fallback reply failed: ${String(sendErr)}`);
4729
4759
  }
4730
4760
  }
4731
4761
  }
@@ -4738,6 +4768,26 @@ function maxMessageId(messages) {
4738
4768
  }
4739
4769
  return max;
4740
4770
  }
4771
+ function sleepBetweenPolls(ms, signal) {
4772
+ if (ms <= 0) {
4773
+ return new Promise((resolve) => setImmediate(resolve));
4774
+ }
4775
+ return new Promise((resolve) => {
4776
+ if (signal?.aborted) {
4777
+ resolve();
4778
+ return;
4779
+ }
4780
+ const t = setTimeout(resolve, ms);
4781
+ signal?.addEventListener(
4782
+ "abort",
4783
+ () => {
4784
+ clearTimeout(t);
4785
+ resolve();
4786
+ },
4787
+ { once: true }
4788
+ );
4789
+ });
4790
+ }
4741
4791
  async function monitorCsdnProvider(opts) {
4742
4792
  const { config, runtime, accountId = "default", abortSignal } = opts;
4743
4793
  const baseLogger = runtime && (runtime.logger || runtime.log) || console;
@@ -4749,18 +4799,19 @@ async function monitorCsdnProvider(opts) {
4749
4799
  const csdnCfgRaw = getCsdnChannelObjectFromRoot(config);
4750
4800
  const parsed = CsdnConfigSchema.safeParse(csdnCfgRaw);
4751
4801
  if (!parsed.success) {
4752
- logger.error(`[csdn] invalid config for account ${accountId}: ${parsed.error}`);
4802
+ logger.error(`invalid config for account ${accountId}: ${parsed.error}`);
4753
4803
  return;
4754
4804
  }
4755
4805
  const csdnCfg = parsed.data;
4756
4806
  if (!csdnCfg.token) {
4757
- logger.warn(`[csdn] token missing; skip start for account ${accountId}`);
4807
+ logger.warn(`token missing; skip start for account ${accountId}`);
4758
4808
  return;
4759
4809
  }
4760
4810
  const client = new CsdnClient(csdnCfg);
4811
+ const pollIntervalMs = clampPollIntervalMs(csdnCfg.pollIntervalMs);
4761
4812
  const v = csdnCfg.verbose;
4762
4813
  logger.info(
4763
- `[csdn] starting long-polling account=${accountId} apiUrl=${csdnCfg.apiUrl} timeout=${FIXED_LONG_POLLING_TIMEOUT_SEC}s take=${FIXED_TAKE}`
4814
+ `starting long-polling account=${accountId} apiUrl=${csdnCfg.apiUrl} timeout=${FIXED_LONG_POLLING_TIMEOUT_SEC}s take=${FIXED_TAKE} pollIntervalMs=${pollIntervalMs}`
4764
4815
  );
4765
4816
  let backoffMs = FIXED_RETRY_INTERVAL_MS;
4766
4817
  const backoffCap = Math.max(FIXED_RETRY_INTERVAL_MS, FIXED_RETRY_BACKOFF_MAX_MS);
@@ -4770,9 +4821,6 @@ async function monitorCsdnProvider(opts) {
4770
4821
  try {
4771
4822
  const t0 = Date.now();
4772
4823
  if (v) {
4773
- logger.info(
4774
- `[csdn] poll begin account=${accountId} timeout=${FIXED_LONG_POLLING_TIMEOUT_SEC}s take=${FIXED_TAKE}${afterMessageId ? ` afterMessageId=${afterMessageId}` : ""}`
4775
- );
4776
4824
  }
4777
4825
  const messages = await client.getUnreadMessages(FIXED_LONG_POLLING_TIMEOUT_SEC, {
4778
4826
  afterMessageId,
@@ -4780,12 +4828,11 @@ async function monitorCsdnProvider(opts) {
4780
4828
  });
4781
4829
  backoffMs = FIXED_RETRY_INTERVAL_MS;
4782
4830
  const dur = Date.now() - t0;
4783
- logger.info(`[csdn] poll end account=${accountId} duration=${dur}ms count=${messages.length}`);
4784
4831
  for (const msg of messages) {
4785
- logger.info(`[csdn] inbound id=${msg.id} from=${msg.from} type=${msg.type} size=${msg.content?.length ?? 0}`);
4832
+ logger.info(`inbound id=${msg.id} from=${msg.from} type=${msg.type} size=${msg.content?.length ?? 0}`);
4786
4833
  if (v) {
4787
4834
  try {
4788
- logger.info(`[csdn] inbound.full ${JSON.stringify(msg)}`);
4835
+ logger.info(`inbound.full ${JSON.stringify(msg)}`);
4789
4836
  } catch {
4790
4837
  }
4791
4838
  }
@@ -4799,17 +4846,17 @@ async function monitorCsdnProvider(opts) {
4799
4846
  if (messages.length > 0) {
4800
4847
  afterMessageId = maxMessageId(messages);
4801
4848
  }
4802
- await new Promise((resolve) => setImmediate(resolve));
4849
+ await sleepBetweenPolls(pollIntervalMs, abortSignal);
4803
4850
  } catch (err) {
4804
- logger.error(`[csdn] polling error: ${err}`);
4851
+ logger.error(`polling error: ${err}`);
4805
4852
  logger.info(
4806
- `[csdn] waiting ${backoffMs}ms before retry (exponential backoff, cap=${backoffCap}ms)...`
4853
+ `waiting ${backoffMs}ms before retry (exponential backoff, cap=${backoffCap}ms)...`
4807
4854
  );
4808
4855
  await new Promise((resolve) => setTimeout(resolve, backoffMs));
4809
4856
  backoffMs = Math.min(backoffCap, Math.max(FIXED_RETRY_INTERVAL_MS, backoffMs * 2));
4810
4857
  }
4811
4858
  }
4812
- logger.info(`[csdn] polling stopped for account ${accountId}`);
4859
+ logger.info(`polling stopped for account ${accountId}`);
4813
4860
  };
4814
4861
  return pollLoop();
4815
4862
  }
@@ -4872,7 +4919,8 @@ var csdnPlugin = {
4872
4919
  token: { type: "string" },
4873
4920
  apiUrl: { type: "string" },
4874
4921
  fallbackAgentId: { type: "string" },
4875
- verbose: { type: "boolean" }
4922
+ verbose: { type: "boolean" },
4923
+ pollIntervalMs: { type: "number", minimum: 0, maximum: 6e5 }
4876
4924
  }
4877
4925
  }
4878
4926
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "csdn-im",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "type": "module",
5
5
  "description": "OpenClaw channel plugin for CSDN IM",
6
6
  "license": "MIT",