@dcrays/dcgchat-test 0.4.24 → 0.4.26

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 ADDED
@@ -0,0 +1,83 @@
1
+ # OpenClaw 书灵墨宝 插件
2
+
3
+ 连接 OpenClaw 与 书灵墨宝 产品的通道插件。
4
+
5
+ ## 架构
6
+
7
+ ```
8
+ ┌──────────┐ WebSocket ┌──────────────┐ WebSocket ┌─────────────────────┐
9
+ │ Web 前端 │ ←───────────────→ │ 公司后端服务 │ ←───────────────→ │ OpenClaw(工作电脑) │
10
+ └──────────┘ └──────────────┘ (OpenClaw 主动连) └─────────────────────┘
11
+ ```
12
+
13
+ - OpenClaw 插件**主动连接**后端的 WebSocket 服务(不需要公网 IP)
14
+ - 后端收到用户消息后转发给 OpenClaw,OpenClaw 回复后发回后端
15
+
16
+ ## 快速开始
17
+
18
+ ### 1. 安装插件
19
+
20
+ ```bash
21
+ pnpm openclaw plugins install -l /path/to/openclaw-dcgchat
22
+ ```
23
+
24
+ ### 2. 配置
25
+
26
+ ```bash
27
+ openclaw config set channels.dcgchat.enabled true
28
+ openclaw config set channels.dcgchat.wsUrl "ws://your-backend:8080/openclaw/ws"
29
+ ```
30
+
31
+ ### 3. 启动
32
+
33
+ ```bash
34
+ pnpm openclaw gateway
35
+ ```
36
+
37
+ ## 消息协议(MVP)
38
+
39
+ ### 下行:后端 → OpenClaw(用户消息)
40
+
41
+ ```json
42
+ { "type": "message", "userId": "user_001", "text": "你好" }
43
+ ```
44
+
45
+ ### 上行:OpenClaw → 后端(Agent 回复)
46
+
47
+ ```json
48
+ { "type": "reply", "userId": "user_001", "text": "你好!有什么可以帮你的?" }
49
+ ```
50
+
51
+ ## 配置项
52
+
53
+ | 配置键 | 类型 | 说明 |
54
+ |--------|------|------|
55
+ | `channels.dcgchat.enabled` | boolean | 是否启用 |
56
+ | `channels.dcgchat.wsUrl` | string | 后端 WebSocket 地址 |
57
+
58
+ ## 开发
59
+
60
+ ```bash
61
+ # 安装依赖
62
+ pnpm install
63
+
64
+ # 类型检查
65
+ pnpm typecheck
66
+ ```
67
+
68
+ ## 文件结构
69
+
70
+ - `index.ts` - 插件入口
71
+ - `src/channel.ts` - ChannelPlugin 定义
72
+ - `src/runtime.ts` - 插件 runtime
73
+ - `src/types.ts` - 类型定义
74
+ - `src/monitor.ts` - WebSocket 连接与断线重连
75
+ - `src/bot.ts` - 消息处理与 Agent 调用
76
+
77
+ ## 后续迭代
78
+
79
+ - [ ] Token 认证
80
+ - [ ] 流式输出
81
+ - [ ] Typing 指示
82
+ - [ ] messageId 去重
83
+ - [ ] 错误消息类型
package/index.ts CHANGED
@@ -3,11 +3,12 @@ import { emptyPluginConfigSchema } from 'openclaw/plugin-sdk'
3
3
  import { dcgchatPlugin } from './src/channel.js'
4
4
  import { setDcgchatRuntime, setWorkspaceDir } from './src/utils/global.js'
5
5
  import { monitoringToolMessage } from './src/tool.js'
6
+ import { channelInfo, ENV } from './src/utils/constant.js'
6
7
  import { setOpenClawConfig } from './src/utils/global.js'
7
8
  import { createDcgchatMessageTool } from './src/tools/messageTool.js'
8
9
 
9
10
  const plugin = {
10
- id: "dcgchat-test",
11
+ id: channelInfo[ENV],
11
12
  name: '书灵墨宝',
12
13
  description: '连接 OpenClaw 与 书灵墨宝 产品(WebSocket)',
13
14
  configSchema: emptyPluginConfigSchema(),
@@ -1,11 +1,9 @@
1
1
  {
2
2
  "id": "dcgchat-test",
3
- "channels": [
4
- "dcgchat-test"
5
- ],
3
+ "channels": ["dcgchat-test"],
6
4
  "configSchema": {
7
5
  "type": "object",
8
6
  "additionalProperties": false,
9
7
  "properties": {}
10
8
  }
11
- }
9
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dcrays/dcgchat-test",
3
- "version": "0.4.24",
3
+ "version": "0.4.26",
4
4
  "type": "module",
5
5
  "description": "OpenClaw channel plugin for 书灵墨宝 (WebSocket)",
6
6
  "main": "index.ts",
@@ -16,6 +16,12 @@
16
16
  "websocket",
17
17
  "ai"
18
18
  ],
19
+ "scripts": {
20
+ "typecheck": "tsc --noEmit",
21
+ "build:production": "npx tsx scripts/build.ts production",
22
+ "build:prod": "npx tsx scripts/build.ts production",
23
+ "build:test": "npx tsx scripts/build.ts test"
24
+ },
19
25
  "dependencies": {
20
26
  "ali-oss": "file:src/libs/ali-oss-6.23.0.tgz",
21
27
  "axios": "file:src/libs/axios-1.13.6.tgz",
@@ -31,15 +37,19 @@
31
37
  "id": "dcgchat-test",
32
38
  "label": "书灵墨宝",
33
39
  "selectionLabel": "书灵墨宝",
34
- "docsPath": "/channels/dcgchat-test",
40
+ "docsPath": "/channels/dcgchat",
35
41
  "docsLabel": "dcgchat-test",
36
42
  "blurb": "连接 OpenClaw 与 书灵墨宝 产品",
37
43
  "order": 80
38
44
  },
39
45
  "install": {
40
46
  "npmSpec": "@dcrays/dcgchat-test",
41
- "localPath": "extensions/dcgchat-test",
47
+ "localPath": "extensions/dcgchat",
42
48
  "defaultChoice": "npm"
43
49
  }
50
+ },
51
+ "devDependencies": {
52
+ "openclaw": "^2026.3.13",
53
+ "typescript": "~5.8.0"
44
54
  }
45
55
  }
package/src/bot.ts CHANGED
@@ -11,7 +11,7 @@ import {
11
11
  getWorkspaceDir,
12
12
  setMsgStatus
13
13
  } from './utils/global.js'
14
- import { resolveAccount, sendDcgchatMedia } from './channel.js'
14
+ import { normalizeOutboundMediaPaths, resolveAccount, sendDcgchatMedia } from './channel.js'
15
15
  import { generateSignUrl } from './request/api.js'
16
16
  import { sendChunk, sendFinal, sendText as sendTextMsg, sendError, wsSendRaw, sendText } from './transport.js'
17
17
  import { dcgLogger } from './utils/log.js'
@@ -143,8 +143,11 @@ function buildMediaPayload(mediaList: MediaInfo[]): MediaPayload {
143
143
  }
144
144
 
145
145
  function resolveReplyMediaList(payload: ReplyPayload): string[] {
146
- if (payload.mediaUrls?.length) return payload.mediaUrls.filter(Boolean)
147
- return payload.mediaUrl ? [payload.mediaUrl] : []
146
+ const p = payload as { mediaUrls?: unknown[]; mediaUrl?: unknown }
147
+ if (p.mediaUrls != null && Array.isArray(p.mediaUrls) && p.mediaUrls.length > 0) {
148
+ return normalizeOutboundMediaPaths(p.mediaUrls)
149
+ }
150
+ return normalizeOutboundMediaPaths(p.mediaUrl ?? null)
148
151
  }
149
152
 
150
153
  const typingCallbacks = createTypingCallbacks({
@@ -187,7 +190,7 @@ async function handleDcgchatMessageInboundTurn(msg: InboundMessage, accountId: s
187
190
 
188
191
  const route = core.channel.routing.resolveAgentRoute({
189
192
  cfg: config,
190
- channel: "dcgchat-test",
193
+ channel: channelInfo[ENV],
191
194
  accountId: account.accountId,
192
195
  peer: { kind: 'direct', id: conversationId }
193
196
  })
@@ -204,7 +207,7 @@ async function handleDcgchatMessageInboundTurn(msg: InboundMessage, accountId: s
204
207
  sessionId: conversationId,
205
208
  messageId: msg.content.message_id,
206
209
  domainId: msg.content.domain_id,
207
- appId: config.channels?.["dcgchat-test"]?.appId || 100,
210
+ appId: config.channels?.[channelInfo[ENV]]?.appId || 100,
208
211
  botId: msg.content.bot_id ?? '',
209
212
  agentId: msg.content.agent_id ?? '',
210
213
  sessionKey: dcgSessionKey,
@@ -266,13 +269,13 @@ async function handleDcgchatMessageInboundTurn(msg: InboundMessage, accountId: s
266
269
  ChatType: 'direct',
267
270
  SenderName: agentDisplayName,
268
271
  SenderId: userId,
269
- Provider: "dcgchat-test",
270
- Surface: "dcgchat-test",
272
+ Provider: channelInfo[ENV],
273
+ Surface: channelInfo[ENV],
271
274
  MessageSid: msg.content.message_id,
272
275
  Timestamp: Date.now(),
273
276
  WasMentioned: true,
274
277
  CommandAuthorized: true,
275
- OriginatingChannel: "dcgchat-test",
278
+ OriginatingChannel: channelInfo[ENV],
276
279
  OriginatingTo: dcgSessionKey,
277
280
  Target: dcgSessionKey,
278
281
  SourceTarget: dcgSessionKey,
@@ -295,7 +298,7 @@ async function handleDcgchatMessageInboundTurn(msg: InboundMessage, accountId: s
295
298
  const prefixContext = createReplyPrefixContext({
296
299
  cfg: config,
297
300
  agentId: effectiveAgentId ?? '',
298
- channel: "dcgchat-test",
301
+ channel: channelInfo[ENV],
299
302
  accountId: account.accountId
300
303
  })
301
304
 
@@ -476,7 +479,7 @@ async function handleDcgchatMessageInboundTurn(msg: InboundMessage, accountId: s
476
479
  ctx: ctxPayload,
477
480
  updateLastRoute: {
478
481
  sessionKey: dcgSessionKey,
479
- channel: "dcgchat-test",
482
+ channel: channelInfo[ENV],
480
483
  to: dcgSessionKey,
481
484
  accountId: route.accountId
482
485
  },
package/src/channel.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import fs from 'node:fs'
1
2
  import type { ChannelPlugin, OpenClawConfig, PluginRuntime } from 'openclaw/plugin-sdk'
2
3
  import { createPluginRuntimeStore, DEFAULT_ACCOUNT_ID } from 'openclaw/plugin-sdk'
3
4
  import type { ResolvedDcgchatAccount, DcgchatConfig } from './types.js'
@@ -12,6 +13,7 @@ import {
12
13
  setCronMessageId
13
14
  } from './utils/global.js'
14
15
  import { isWsOpen, mergeDefaultParams, mergeSessionParams, sendFinal, wsSendRaw } from './transport.js'
16
+ import { channelInfo, ENV } from './utils/constant.js'
15
17
  import { dcgLogger, setLogger } from './utils/log.js'
16
18
  import { getOutboundMsgParams, getParamsMessage } from './utils/params.js'
17
19
  import { isSessionActiveForTool } from './tool.js'
@@ -19,7 +21,7 @@ import { startDcgchatGatewaySocket } from './gateway/socket.js'
19
21
  import { getCronJobsPath, readCronJob } from './cron.js'
20
22
 
21
23
  function dcgchatChannelCfg(): DcgchatConfig {
22
- return (getOpenClawConfig()?.channels?.["dcgchat-test"] as DcgchatConfig | undefined) ?? {}
24
+ return (getOpenClawConfig()?.channels?.[channelInfo[ENV]] as DcgchatConfig | undefined) ?? {}
23
25
  }
24
26
 
25
27
  /** `agent:<code>:mobook:direct:<agentId>:<sessionId>`(与 getSessionKey 非 real_mobook 分支一致) */
@@ -103,6 +105,53 @@ function outboundChatId(rawTo: string | undefined, normalizedTo: string): string
103
105
  return raw.indexOf('dcg-cron:') >= 0 ? raw : normalizedTo
104
106
  }
105
107
 
108
+ /**
109
+ * 仅从 JSON / `{ file | path | url }` 等结构里取出路径字符串,不做改写(不拼 workspace、不 normalize)。
110
+ */
111
+ function collectOutboundMediaPaths(item: unknown, out: string[]): void {
112
+ if (item == null) return
113
+ if (typeof item === 'string') {
114
+ const t = item.trim()
115
+ if (!t) return
116
+ if (t.startsWith('[')) {
117
+ try {
118
+ const parsed = JSON.parse(t) as unknown
119
+ collectOutboundMediaPaths(parsed, out)
120
+ return
121
+ } catch {
122
+ /* 非 JSON,按普通路径处理 */
123
+ }
124
+ }
125
+ out.push(t)
126
+ return
127
+ }
128
+ if (Array.isArray(item)) {
129
+ for (const el of item) collectOutboundMediaPaths(el, out)
130
+ return
131
+ }
132
+ if (typeof item === 'object') {
133
+ const o = item as Record<string, unknown>
134
+ const raw = o.file ?? o.path ?? o.url
135
+ if (typeof raw === 'string' && raw.trim()) {
136
+ out.push(raw.trim())
137
+ }
138
+ }
139
+ }
140
+
141
+ /** 将出站 media 展平为路径字符串列表(去重保序;路径保持 Core 原样) */
142
+ export function normalizeOutboundMediaPaths(raw: unknown): string[] {
143
+ const acc: string[] = []
144
+ collectOutboundMediaPaths(raw, acc)
145
+ const seen = new Set<string>()
146
+ const deduped: string[] = []
147
+ for (const p of acc) {
148
+ if (!p || seen.has(p)) continue
149
+ seen.add(p)
150
+ deduped.push(p)
151
+ }
152
+ return deduped
153
+ }
154
+
106
155
  export async function sendDcgchatMedia(opts: DcgchatMediaSendOptions): Promise<void> {
107
156
  const rawOpt = (opts.sessionKey ?? '').trim()
108
157
  const strippedForCron = rawOpt.replace(/^dcg-cron:/i, '').trim()
@@ -129,7 +178,34 @@ export async function sendDcgchatMedia(opts: DcgchatMediaSendOptions): Promise<v
129
178
  return
130
179
  }
131
180
 
132
- const mediaUrl = opts.mediaUrl
181
+ const expanded = normalizeOutboundMediaPaths(opts.mediaUrl)
182
+ if (expanded.length === 0) {
183
+ dcgLogger(
184
+ `dcgchat: sendMedia skipped (no resolvable path): ${typeof opts.mediaUrl === 'string' ? opts.mediaUrl : JSON.stringify(opts.mediaUrl)} sessionKey=${sessionKey}`,
185
+ 'error'
186
+ )
187
+ return
188
+ }
189
+ if (expanded.length > 1) {
190
+ for (const single of expanded) {
191
+ await sendDcgchatMedia({ ...opts, mediaUrl: single })
192
+ }
193
+ return
194
+ }
195
+ const mediaUrl = expanded[0]
196
+ if (!mediaUrl || !msgCtx.sessionId) {
197
+ dcgLogger(`dcgchat: sendMedia skipped (duplicate in session): ${mediaUrl} sessionId=${msgCtx.sessionId} sessionKey=${sessionKey}`)
198
+ return
199
+ }
200
+ // 判断文件存在
201
+ try {
202
+ if (!fs.existsSync(mediaUrl)) {
203
+ dcgLogger(`dcgchat: sendMedia skipped (file not found): ${mediaUrl} sessionKey=${sessionKey}`, 'error')
204
+ return
205
+ }
206
+ } catch (err) {
207
+ dcgLogger(`dcgchat: sendMedia skipped (cannot stat path): ${mediaUrl} ${String(err)} sessionKey=${sessionKey}`, 'error')
208
+ }
133
209
 
134
210
  if (mediaUrl && msgCtx.sessionId) {
135
211
  if (hasSentMediaKey(msgCtx.sessionId, mediaUrl)) {
@@ -143,14 +219,10 @@ export async function sendDcgchatMedia(opts: DcgchatMediaSendOptions): Promise<v
143
219
  if (!msgCtx.sessionId) {
144
220
  msgCtx.sessionId = sessionId
145
221
  }
146
- if (!mediaUrl || !msgCtx.sessionId) {
147
- dcgLogger(`dcgchat: sendMedia skipped (duplicate in session): ${mediaUrl} sessionId=${msgCtx.sessionId} sessionKey=${sessionKey}`)
148
- return
149
- }
150
222
  const fileName = mediaUrl?.split(/[\\/]/).pop() || ''
151
223
  const notMessageId = `${msgCtx?.messageId}`?.length === 13 || !msgCtx?.messageId
152
224
  try {
153
- const botToken = msgCtx.botToken ?? getOpenClawConfig()?.channels?.["dcgchat-test"]?.botToken ?? ''
225
+ const botToken = msgCtx.botToken ?? getOpenClawConfig()?.channels?.[channelInfo[ENV]]?.botToken ?? ''
154
226
  const url = opts.mediaUrl ? await ossUpload(opts.mediaUrl, botToken, 1) : ''
155
227
  if (!msgCtx.agentId) {
156
228
  msgCtx.agentId = agentId
@@ -175,7 +247,7 @@ export async function sendDcgchatMedia(opts: DcgchatMediaSendOptions): Promise<v
175
247
 
176
248
  export function resolveAccount(cfg: OpenClawConfig, accountId?: string | null): ResolvedDcgchatAccount {
177
249
  const id = accountId ?? DEFAULT_ACCOUNT_ID
178
- const raw = (cfg.channels?.["dcgchat-test"] as DcgchatConfig | undefined) ?? {}
250
+ const raw = (cfg.channels?.[channelInfo[ENV]] as DcgchatConfig | undefined) ?? {}
179
251
  return {
180
252
  accountId: id,
181
253
  enabled: raw.enabled !== false,
@@ -189,13 +261,13 @@ export function resolveAccount(cfg: OpenClawConfig, accountId?: string | null):
189
261
  }
190
262
 
191
263
  export const dcgchatPlugin: ChannelPlugin<ResolvedDcgchatAccount> = {
192
- id: "dcgchat-test",
264
+ id: channelInfo[ENV],
193
265
  meta: {
194
- id: "dcgchat-test",
266
+ id: channelInfo[ENV],
195
267
  label: '书灵墨宝',
196
268
  selectionLabel: '书灵墨宝',
197
269
  docsPath: '/channels/dcgchat',
198
- docsLabel: "dcgchat-test",
270
+ docsLabel: channelInfo[ENV],
199
271
  blurb: '连接 OpenClaw 与 书灵墨宝 产品',
200
272
  order: 80
201
273
  },
@@ -212,7 +284,7 @@ export const dcgchatPlugin: ChannelPlugin<ResolvedDcgchatAccount> = {
212
284
  // blockStreaming: true,
213
285
  },
214
286
  /** 当前构建的 channel id + 兼容旧配置键 `channels.dcgchat` */
215
- reload: { configPrefixes: [`channels.${"dcgchat-test"}`, 'channels.dcgchat'] },
287
+ reload: { configPrefixes: [`channels.${channelInfo[ENV]}`, 'channels.dcgchat'] },
216
288
  configSchema: {
217
289
  schema: {
218
290
  type: 'object',
@@ -248,7 +320,7 @@ export const dcgchatPlugin: ChannelPlugin<ResolvedDcgchatAccount> = {
248
320
  resolveAccount: (cfg, accountId) => resolveAccount(cfg, accountId),
249
321
  defaultAccountId: () => DEFAULT_ACCOUNT_ID,
250
322
  setAccountEnabled: ({ cfg, enabled }) => {
251
- const channelKey = "dcgchat-test"
323
+ const channelKey = channelInfo[ENV]
252
324
  const prev = (cfg.channels?.[channelKey as keyof NonNullable<typeof cfg.channels>] as Record<string, unknown> | undefined) ?? {}
253
325
  return {
254
326
  ...cfg,
@@ -320,7 +392,7 @@ export const dcgchatPlugin: ChannelPlugin<ResolvedDcgchatAccount> = {
320
392
  if (!isSessionActiveForTool(to)) {
321
393
  dcgLogger(`channel sendText dropped (session not active): to=${to}`)
322
394
  return {
323
- channel: "dcgchat-test",
395
+ channel: channelInfo[ENV],
324
396
  messageId: '',
325
397
  chatId: outboundChatId(ctx.to, to)
326
398
  }
@@ -332,7 +404,7 @@ export const dcgchatPlugin: ChannelPlugin<ResolvedDcgchatAccount> = {
332
404
  }
333
405
  }
334
406
  return {
335
- channel: "dcgchat-test",
407
+ channel: channelInfo[ENV],
336
408
  messageId: `${messageId}`,
337
409
  chatId: outboundChatId(ctx.to, to)
338
410
  }
@@ -353,20 +425,26 @@ export const dcgchatPlugin: ChannelPlugin<ResolvedDcgchatAccount> = {
353
425
  if (!sessionId) {
354
426
  dcgLogger(`channel sendMedia to ${ctx.to} -> sessionId not found`, 'error')
355
427
  return {
356
- channel: "dcgchat-test",
428
+ channel: channelInfo[ENV],
357
429
  messageId,
358
430
  chatId: outboundChatId(ctx.to, to || '')
359
431
  }
360
432
  }
361
433
 
362
434
  dcgLogger(`channel sendMedia to ${ctx.to}`)
363
- await sendDcgchatMedia({
364
- sessionKey: to || '',
365
- mediaUrl: ctx.mediaUrl || '',
366
- ...(isCron ? { messageId } : {})
367
- })
435
+
436
+ const ctxExt = ctx as { mediaUrls?: unknown; mediaUrl?: string }
437
+ const rawMedia = ctxExt.mediaUrls ?? ctxExt.mediaUrl
438
+ const paths = normalizeOutboundMediaPaths(rawMedia)
439
+ for (const mediaUrl of paths) {
440
+ await sendDcgchatMedia({
441
+ sessionKey: to || '',
442
+ mediaUrl,
443
+ ...(isCron ? { messageId } : {})
444
+ })
445
+ }
368
446
  return {
369
- channel: "dcgchat-test",
447
+ channel: channelInfo[ENV],
370
448
  messageId,
371
449
  chatId: outboundChatId(ctx.to, to || '')
372
450
  }
@@ -1,5 +1,9 @@
1
1
  export const ENV: 'production' | 'test' | 'develop' = 'test'
2
2
 
3
+ export const channelInfo: Record<string, string> = {
4
+ production: 'dcgchat',
5
+ test: 'dcgchat-test'
6
+ }
3
7
 
4
8
  export const systemCommand = ['/new', '/status']
5
9
  export const stopCommand = ['/stop']
@@ -30,7 +30,7 @@ export function getOpenClawConfig(): OpenClawConfig | null {
30
30
  function getWorkspacePath(): string | null {
31
31
  const workspacePath = path.join(
32
32
  os.homedir(),
33
- config?.channels?.["dcgchat-test"]?.appId == 110 ? '.mobook' : '.openclaw',
33
+ config?.channels?.[channelInfo[ENV]]?.appId == 110 ? '.mobook' : '.openclaw',
34
34
  'workspace'
35
35
  )
36
36
  if (fs.existsSync(workspacePath)) {
@@ -55,7 +55,7 @@ export function getWorkspaceDir(): string {
55
55
  }
56
56
 
57
57
  const { setRuntime: setDcgchatRuntime, getRuntime: getDcgchatRuntime } = createPluginRuntimeStore<PluginRuntime>(
58
- `${"dcgchat-test"} runtime not initialized`
58
+ `${channelInfo[ENV]} runtime not initialized`
59
59
  )
60
60
  export { setDcgchatRuntime, getDcgchatRuntime }
61
61
 
@@ -147,7 +147,7 @@ export const getSessionKey = (content: any, accountId: string) => {
147
147
 
148
148
  const route = core.channel.routing.resolveAgentRoute({
149
149
  cfg: getOpenClawConfig() as OpenClawConfig,
150
- channel: "dcgchat-test",
150
+ channel: channelInfo[ENV],
151
151
  accountId: accountId || 'default',
152
152
  peer: { kind: 'direct', id: session_id }
153
153
  })
package/src/utils/log.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { RuntimeEnv } from 'openclaw/plugin-sdk'
2
+ import { channelInfo, ENV } from './constant.js'
2
3
 
3
4
  let logger: RuntimeEnv | null = null
4
5
 
@@ -10,6 +11,6 @@ export function dcgLogger(message: string, type: 'log' | 'error' = 'log'): void
10
11
  if (logger) {
11
12
  logger[type](`书灵墨宝🚀 ~ [${new Date().toISOString()}] ${message}`)
12
13
  } else {
13
- console[type](`书灵墨宝🚀 ~ ${new Date().toISOString()} [${"dcgchat-test"}]: ${message}`)
14
+ console[type](`书灵墨宝🚀 ~ ${new Date().toISOString()} [${channelInfo[ENV]}]: ${message}`)
14
15
  }
15
16
  }
@@ -9,7 +9,7 @@ const paramsMessageMap = new Map<string, IMsgParams>()
9
9
 
10
10
  /** 从 OpenClaw 配置读取当前 channel 的基础参数(唯一来源,供 transport / resolve 等复用) */
11
11
  export function getParamsDefaults(): IMsgParams {
12
- const ch = (getOpenClawConfig()?.channels?.["dcgchat-test"] as DcgchatConfig | undefined) ?? {}
12
+ const ch = (getOpenClawConfig()?.channels?.[channelInfo[ENV]] as DcgchatConfig | undefined) ?? {}
13
13
  return {
14
14
  userId: Number(ch.userId ?? 0),
15
15
  botToken: ch.botToken ?? '',